package auth

import (
	"context"
	"strings"
	"time"

	memberdom "gateway/internal/model/member/domain"
	dommember "gateway/internal/model/member/domain/usecase"
	notifenum "gateway/internal/model/notification/domain/enum"
	notifuc "gateway/internal/model/notification/domain/usecase"
	"gateway/internal/svc"
	"gateway/internal/types"
)

func sendPasswordResetOTP(
	ctx context.Context,
	sc *svc.ServiceContext,
	tenantID, uid, email string,
) (*types.PasswordForgotData, error) {
	cfg := sc.Config.Member.Defaults()
	rateKey := memberdom.GetVerifyRateRedisKey(tenantID, uid, string(passwordResetPurpose()))
	if err := sc.MemberVerifyRate.AssertResendAllowed(ctx, rateKey, time.Duration(cfg.OTP.ResendCooldownSeconds)*time.Second); err != nil {
		return nil, err
	}

	dto, plainCode, err := sc.MemberOTP.Generate(ctx, &dommember.GenerateOTPRequest{
		TenantID: tenantID,
		UID:      uid,
		Purpose:  passwordResetPurpose(),
		Target:   email,
	})
	if err != nil {
		return nil, err
	}
	locale := sc.Config.Notification.DefaultLocale
	if strings.TrimSpace(locale) == "" {
		locale = "en-us"
	}
	if _, sendErr := sc.Notifier.Send(ctx, &notifuc.SendRequest{
		TenantID:         tenantID,
		UID:              uid,
		Channel:          notifenum.ChannelEmail,
		Kind:             notifenum.NotifyVerifyEmail,
		Target:           email,
		Locale:           locale,
		Data:             map[string]any{"code": plainCode, "expires_in": dto.ExpiresIn},
		IdempotencyKey:   dto.ChallengeID,
		DoNotPersistBody: true,
		Severity:         notifenum.SeverityInfo,
	}); sendErr != nil {
		if invErr := sc.MemberOTP.Invalidate(ctx, dto.ChallengeID); invErr != nil {
			return nil, invErr
		}
		return nil, sendErr
	}
	return &types.PasswordForgotData{
		ChallengeID: dto.ChallengeID,
		ExpiresIn:   dto.ExpiresIn,
	}, nil
}
