package usecase

import (
	"context"
	"errors"
	"time"

	authdomain "gateway/internal/model/auth/domain"
	"gateway/internal/model/auth/domain/entity"
	domrepo "gateway/internal/model/auth/domain/repository"
	domusecase "gateway/internal/model/auth/domain/usecase"
)

type registrationMetaUseCase struct {
	repo domrepo.RegistrationMetaRepository
}

// RegistrationMetaUseCaseParam wires RegistrationMetaUseCase.
type RegistrationMetaUseCaseParam struct {
	Repo domrepo.RegistrationMetaRepository
}

// MustRegistrationMetaUseCase constructs RegistrationMetaUseCase.
func MustRegistrationMetaUseCase(param RegistrationMetaUseCaseParam) domusecase.RegistrationMetaUseCase {
	if param.Repo == nil {
		panic("auth: registration metadata repository is required")
	}
	return &registrationMetaUseCase{repo: param.Repo}
}

func (uc *registrationMetaUseCase) Record(ctx context.Context, req *domusecase.RecordRegistrationRequest) error {
	if req == nil || req.TenantID == "" || req.UID == "" {
		return errb.InputMissingRequired("tenant_id and uid are required")
	}
	if req.AcceptTermsVersion == "" {
		return errb.InputMissingRequired("accept_terms_version is required")
	}
	if !req.Channel.Valid() {
		return errb.InputInvalidFormat("invalid registration channel")
	}
	now := time.Now().UTC().UnixMilli()
	rec := &entity.RegistrationMetadata{
		TenantID:            req.TenantID,
		UID:                 req.UID,
		InviteCodeID:        req.InviteCodeID,
		AcceptTermsVersion:  req.AcceptTermsVersion,
		MarketingOptIn:      req.MarketingOptIn,
		RegistrationChannel: req.Channel,
		ClientIP:            req.ClientIP,
		UserAgent:           req.UserAgent,
		OccurredAt:          now,
		CreateAt:            now,
	}
	if err := uc.repo.Insert(ctx, rec); err != nil {
		if errors.Is(err, authdomain.ErrDuplicateRegistrationMeta) {
			return errb.ResAlreadyExist("registration metadata already exists").WithCause(err)
		}
		return wrapRepoErr(err, "insert registration metadata failed")
	}
	return nil
}

var _ domusecase.RegistrationMetaUseCase = (*registrationMetaUseCase)(nil)
