package verificationimp

import (
	"encoding/json"
	"net/http"

	"github.com/tech/sendico/pkg/api/http/response"
	"github.com/tech/sendico/pkg/db/verification"
	"github.com/tech/sendico/pkg/model"
	"github.com/tech/sendico/pkg/mutil/mask"
	"github.com/tech/sendico/pkg/mutil/mzap"
	emodel "github.com/tech/sendico/server/interface/model"
	mutil "github.com/tech/sendico/server/internal/mutil/verification"
	"go.uber.org/zap"
)

func (a *VerificationAPI) requestCode(r *http.Request, account *model.Account, token *emodel.AccountToken) http.HandlerFunc {
	var req verificationCodeRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		a.logger.Warn("Failed to decode confirmation resend request", zap.Error(err))
		return response.BadPayload(a.logger, a.Name(), err)
	}

	purpose, err := model.VPFromString(req.Purpose)
	if err != nil {
		return response.BadRequest(a.logger, a.Name(), "invalid_target", err.Error())
	}

	if purpose == model.PurposeLogin && (token == nil || !token.Pending) {
		return response.Forbidden(a.logger, a.Name(), "pending_token_required", "login confirmation requires pending token")
	}

	target := a.resolveTarget(req.Target, account)
	if target == "" {
		return response.BadRequest(a.logger, a.Name(), "missing_destination", "email destination is required")
	}
	vReq := verification.NewOTPRequest(account.ID, purpose, target).
		WithTTL(a.config.TTL).
		WithCooldown(a.config.Cooldown).
		WithMaxRetries(a.config.ResendLimit).
		WithIdempotencyKey(req.IdempotencyKey)

	otp, err := a.store.Create(r.Context(), vReq)
	if err != nil {
		a.logger.Warn("Failed to create confirmation code for resend", zap.Error(err), mzap.AccRef(account.ID))
		return mutil.MapTokenErrorToResponse(a.logger, a.Name(), err)
	}

	a.sendCode(account, purpose, target, otp)

	return response.Accepted(a.logger, verificationResponse{
		TTLSeconds:      int(vReq.Ttl.Seconds()),
		CooldownSeconds: int(a.config.Cooldown.Seconds()),
		Target:          mask.Email(target),
		IdempotencyKey:  req.IdempotencyKey,
	})
}
