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 loginMFAChallengeUseCase struct {
	store domrepo.LoginMFAChallengeStore
}

// LoginMFAChallengeUseCaseParam wires LoginMFAChallengeUseCase.
type LoginMFAChallengeUseCaseParam struct {
	Store domrepo.LoginMFAChallengeStore
}

// MustLoginMFAChallengeUseCase constructs LoginMFAChallengeUseCase.
func MustLoginMFAChallengeUseCase(param LoginMFAChallengeUseCaseParam) domusecase.LoginMFAChallengeUseCase {
	if param.Store == nil {
		panic("auth: login mfa challenge store is required")
	}
	return &loginMFAChallengeUseCase{store: param.Store}
}

func (uc *loginMFAChallengeUseCase) Create(ctx context.Context, req *domusecase.CreateLoginMFAChallengeRequest) (*domusecase.LoginMFAChallengeView, error) {
	if req == nil || req.TenantID == "" || req.TenantSlug == "" || req.UID == "" {
		return nil, errb.InputMissingRequired("tenant_id, tenant_slug and uid are required")
	}
	ttl := req.TTL
	if ttl <= 0 {
		ttl = 5 * time.Minute
	}
	challengeID := uuid.NewString()
	challenge := &domrepo.LoginMFAChallenge{
		ChallengeID: challengeID,
		TenantID:    req.TenantID,
		TenantSlug:  req.TenantSlug,
		UID:         req.UID,
	}
	if err := uc.store.Save(ctx, challenge, ttl); err != nil {
		return nil, wrapRepoErr(err, "save login mfa challenge failed")
	}
	return &domusecase.LoginMFAChallengeView{
		ChallengeID: challengeID,
		ExpiresIn:   int(ttl.Seconds()),
	}, nil
}

func (uc *loginMFAChallengeUseCase) Get(ctx context.Context, challengeID string) (*domusecase.CreateLoginMFAChallengeRequest, error) {
	if challengeID == "" {
		return nil, errb.InputMissingRequired("challenge_id is required")
	}
	challenge, err := uc.store.Get(ctx, challengeID)
	if err != nil {
		if errors.Is(err, authdomain.ErrLoginMFAChallengeNotFound) {
			return nil, errb.ResNotFound("login mfa challenge", challengeID).WithCause(err)
		}
		return nil, wrapRepoErr(err, "read login mfa challenge failed")
	}
	return &domusecase.CreateLoginMFAChallengeRequest{
		TenantID:   challenge.TenantID,
		TenantSlug: challenge.TenantSlug,
		UID:        challenge.UID,
	}, nil
}

func (uc *loginMFAChallengeUseCase) Delete(ctx context.Context, challengeID string) error {
	if challengeID == "" {
		return errb.InputMissingRequired("challenge_id is required")
	}
	if err := uc.store.Delete(ctx, challengeID); err != nil {
		return wrapRepoErr(err, "delete login mfa challenge failed")
	}
	return nil
}

var _ domusecase.LoginMFAChallengeUseCase = (*loginMFAChallengeUseCase)(nil)
