package usecase

import (
	"context"
	"errors"
	"time"

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

	"github.com/google/uuid"
)

type registrationSessionUseCase struct {
	store domrepo.RegistrationSessionStore
}

// RegistrationSessionUseCaseParam wires RegistrationSessionUseCase.
type RegistrationSessionUseCaseParam struct {
	Store domrepo.RegistrationSessionStore
}

// MustRegistrationSessionUseCase constructs RegistrationSessionUseCase.
func MustRegistrationSessionUseCase(param RegistrationSessionUseCaseParam) domusecase.RegistrationSessionUseCase {
	if param.Store == nil {
		panic("auth: registration session store is required")
	}
	return &registrationSessionUseCase{store: param.Store}
}

func (uc *registrationSessionUseCase) Create(ctx context.Context, req *domusecase.CreateRegistrationSessionRequest) (*domusecase.RegistrationSessionView, error) {
	if req == nil || req.TenantID == "" || req.TenantSlug == "" {
		return nil, errb.InputMissingRequired("tenant_id and tenant_slug are required")
	}
	if req.InviteCode == "" {
		return nil, errb.InputMissingRequired("invite_code is required")
	}
	if req.AcceptTermsVersion == "" {
		return nil, errb.InputMissingRequired("accept_terms_version is required")
	}
	if req.Provider == "" {
		return nil, errb.InputMissingRequired("provider is required")
	}
	if req.RedirectURI == "" {
		return nil, errb.InputMissingRequired("redirect_uri is required")
	}
	ttl := req.TTL
	if ttl <= 0 {
		ttl = 10 * time.Minute
	}
	sessionID := uuid.NewString()
	session := &domrepo.RegistrationSession{
		SessionID:          sessionID,
		TenantID:           req.TenantID,
		TenantSlug:         req.TenantSlug,
		InviteCode:         req.InviteCode,
		InviteNewUsersOnly: req.InviteNewUsersOnly,
		AcceptTermsVersion: req.AcceptTermsVersion,
		MarketingOptIn:     req.MarketingOptIn,
		Language:           req.Language,
		Provider:           req.Provider,
		RedirectURI:        req.RedirectURI,
		ClientIP:           req.ClientIP,
		UserAgent:          req.UserAgent,
	}
	if err := uc.store.Save(ctx, session, ttl); err != nil {
		return nil, wrapRepoErr(err, "save registration session failed")
	}
	return &domusecase.RegistrationSessionView{
		SessionID: sessionID,
		ExpiresIn: int(ttl.Seconds()),
	}, nil
}

func (uc *registrationSessionUseCase) Get(ctx context.Context, sessionID string) (*domusecase.CreateRegistrationSessionRequest, error) {
	if sessionID == "" {
		return nil, errb.InputMissingRequired("session_id is required")
	}
	session, err := uc.store.Get(ctx, sessionID)
	if err != nil {
		if errors.Is(err, authdomain.ErrRegistrationSessionNotFound) {
			return nil, errb.ResNotFound("registration session", sessionID).WithCause(err)
		}
		return nil, wrapRepoErr(err, "read registration session failed")
	}
	return &domusecase.CreateRegistrationSessionRequest{
		TenantID:           session.TenantID,
		TenantSlug:         session.TenantSlug,
		InviteCode:         session.InviteCode,
		InviteNewUsersOnly: session.InviteNewUsersOnly,
		AcceptTermsVersion: session.AcceptTermsVersion,
		MarketingOptIn:     session.MarketingOptIn,
		Language:           session.Language,
		Provider:           session.Provider,
		RedirectURI:        session.RedirectURI,
		ClientIP:           session.ClientIP,
		UserAgent:          session.UserAgent,
	}, nil
}

func (uc *registrationSessionUseCase) Delete(ctx context.Context, sessionID string) error {
	if sessionID == "" {
		return errb.InputMissingRequired("session_id is required")
	}
	if err := uc.store.Delete(ctx, sessionID); err != nil {
		return wrapRepoErr(err, "delete registration session failed")
	}
	return nil
}

var _ domusecase.RegistrationSessionUseCase = (*registrationSessionUseCase)(nil)
