package auth

import (
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/core/authidentity"
	"github.com/tidbcloud/AgentTeam/internal/sms"
	"github.com/tidbcloud/AgentTeam/internal/store/identity"
)

func mobileVerificationAttemptViewFromStore(attempt identity.MobileVerificationAttempt) dto.MobileVerificationAttemptView {
	return dto.MobileVerificationAttemptView{
		ID:             attempt.ID,
		MobileHint:     authidentity.RedactMobile(attempt.Mobile),
		Provider:       mobileVerificationProviderName(attempt.Provider),
		Status:         strings.TrimSpace(attempt.Status),
		StatusDetail:   mobileVerificationAttemptStatusDetail(attempt),
		ProviderStatus: strings.TrimSpace(attempt.ProviderStatus),
		ExpiresAt:      attempt.ExpiresAt,
		RequestedAt:    attempt.RequestedAt,
		CompletedAt:    attempt.CompletedAt,
	}
}

func mobileVerificationAttemptViews(attempts []identity.MobileVerificationAttempt, activeCode identity.ActiveMobileVerificationCode, hasActiveCode bool) []dto.MobileVerificationAttemptView {
	var activeCodePtr *identity.ActiveMobileVerificationCode
	if hasActiveCode {
		activeCodePtr = &activeCode
	}
	return mobileVerificationAttemptViewsFromStore(attempts, activeCodePtr)
}

func mobileVerificationAttemptViewsFromStore(attempts []identity.MobileVerificationAttempt, activeCode *identity.ActiveMobileVerificationCode) []dto.MobileVerificationAttemptView {
	views := make([]dto.MobileVerificationAttemptView, 0, len(attempts))
	activeCodeMatched := false
	for _, attempt := range attempts {
		view := mobileVerificationAttemptViewFromStore(attempt)
		if !activeCodeMatched && mobileVerificationAttemptMatchesActiveCode(attempt, activeCode) {
			view.CodeActive = true
			activeCodeMatched = true
		}
		views = append(views, view)
	}
	return views
}

func mobileVerificationAttemptMatchesActiveCode(attempt identity.MobileVerificationAttempt, activeCode *identity.ActiveMobileVerificationCode) bool {
	if activeCode == nil {
		return false
	}
	return attempt.Mobile == activeCode.Mobile && attempt.ExpiresAt.Equal(activeCode.ExpiresAt)
}

func mobileVerificationAttemptStatusDetail(attempt identity.MobileVerificationAttempt) string {
	status := strings.TrimSpace(attempt.Status)
	if status == MobileVerificationAttemptStatusFailed {
		if detail := sanitizeMobileVerificationFailureDetail(attempt.ErrorMessage); detail != "" {
			return detail
		}
		return "delivery failed"
	}

	providerStatus := strings.TrimSpace(attempt.ProviderStatus)
	if providerStatus != "" {
		return fmt.Sprintf("provider %s", providerStatus)
	}

	return ""
}

func mobileVerificationAttemptParams(status string, completedAt time.Time, receipt sms.Receipt, sendErr error) identity.CompleteMobileVerificationAttemptParams {
	params := identity.CompleteMobileVerificationAttemptParams{
		Provider:          mobileVerificationProvider(receipt),
		Status:            status,
		SenderIdentity:    receipt.SenderIdentity,
		ProviderMessageID: receipt.ProviderMessageID,
		ProviderStatus:    receipt.ProviderStatus,
		CompletedAt:       completedAt,
	}
	if sendErr != nil {
		params.ErrorMessage = sendErr.Error()
	}
	return params
}

func (handler *MobileHandler) completeMobileVerificationAttempt(ctx context.Context, attemptID string, params identity.CompleteMobileVerificationAttemptParams) {
	if strings.TrimSpace(attemptID) == "" {
		return
	}
	if err := handler.store.CompleteMobileVerificationAttempt(ctx, attemptID, params); err != nil && handler.logger != nil {
		handler.logger.ErrorContext(ctx, "record mobile verification send attempt result", "attempt_id", attemptID, "error_class", "attempt_persistence_failed")
	}
}
