package confirmationimp

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

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

func (a *ConfirmationAPI) resendCode(r *http.Request, account *model.Account, token *emodel.AccountToken) http.HandlerFunc {
	var req confirmationRequest
	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)
	}

	target, err := a.parseTarget(req.Target)
	if err != nil {
		return response.BadRequest(a.logger, a.Name(), "invalid_target", err.Error())
	}

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

	destination := a.resolveDestination(req.Destination, account)
	if destination == "" {
		return response.BadRequest(a.logger, a.Name(), "missing_destination", "email destination is required")
	}
	code, rec, err := a.store.Resend(r.Context(), account.ID, destination, target, a.config, a.generateCode)
	switch {
	case errors.Is(err, errConfirmationNotFound):
		return response.NotFound(a.logger, a.Name(), "no_active_code_for_resend")
	case errors.Is(err, errConfirmationCooldown):
		return response.Forbidden(a.logger, a.Name(), "cooldown_active", "please wait before requesting another code")
	case errors.Is(err, errConfirmationResendLimit):
		return response.Forbidden(a.logger, a.Name(), "resend_limit_reached", "too many resend attempts")
	case err != nil:
		a.logger.Warn("Failed to resend confirmation code", zap.Error(err), mzap.ObjRef("account_ref", account.ID))
		return response.Internal(a.logger, a.Name(), err)
	}

	a.sendCode(account, target, destination, code)

	return response.Accepted(a.logger, confirmationResponse{
		TTLSeconds:      int(time.Until(rec.ExpiresAt).Seconds()),
		CooldownSeconds: int(a.config.Cooldown.Seconds()),
		Destination:     maskEmail(destination),
	})
}
