// File Path: monorepo/cloud/maplepress-backend/internal/interface/http/handler/admin/account_status_handler.go
package admin

import (
	"net/http"
	"time"

	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/httperror"
	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/httpresponse"
	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/logger"
	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/ratelimit"
	"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/validation"
)

// AccountStatusHandler handles HTTP requests for checking account lock status
type AccountStatusHandler struct {
	loginRateLimiter ratelimit.LoginRateLimiter
	logger           *zap.Logger
}

// NewAccountStatusHandler creates a new account status handler
func NewAccountStatusHandler(
	loginRateLimiter ratelimit.LoginRateLimiter,
	logger *zap.Logger,
) *AccountStatusHandler {
	return &AccountStatusHandler{
		loginRateLimiter: loginRateLimiter,
		logger:           logger.Named("account-status-handler"),
	}
}

// ProvideAccountStatusHandler creates a new AccountStatusHandler for dependency injection
func ProvideAccountStatusHandler(
	loginRateLimiter ratelimit.LoginRateLimiter,
	logger *zap.Logger,
) *AccountStatusHandler {
	return NewAccountStatusHandler(loginRateLimiter, logger)
}

// AccountStatusResponse represents the account status response
type AccountStatusResponse struct {
	Email            string `json:"email"`
	IsLocked         bool   `json:"is_locked"`
	FailedAttempts   int    `json:"failed_attempts"`
	RemainingTime    string `json:"remaining_time,omitempty"`
	RemainingSeconds int    `json:"remaining_seconds,omitempty"`
}

// Handle processes GET /api/v1/admin/account-status?email=user@example.com requests
// This endpoint allows administrators to check if an account is locked and get details
func (h *AccountStatusHandler) Handle(w http.ResponseWriter, r *http.Request) {
	h.logger.Debug("handling account status request")

	// CWE-20: Validate email query parameter
	email, err := validation.ValidateQueryEmail(r, "email")
	if err != nil {
		h.logger.Warn("invalid email query parameter", zap.Error(err))
		httperror.ProblemBadRequest(w, err.Error())
		return
	}

	// Check if account is locked
	locked, remainingTime, err := h.loginRateLimiter.IsAccountLocked(r.Context(), email)
	if err != nil {
		h.logger.Error("failed to check account lock status",
			logger.EmailHash(email),
			zap.Error(err))
		httperror.ProblemInternalServerError(w, "Failed to check account status")
		return
	}

	// Get failed attempts count
	failedAttempts, err := h.loginRateLimiter.GetFailedAttempts(r.Context(), email)
	if err != nil {
		h.logger.Error("failed to get failed attempts",
			logger.EmailHash(email),
			zap.Error(err))
		// Continue with locked status even if we can't get attempt count
		failedAttempts = 0
	}

	response := &AccountStatusResponse{
		Email:          email,
		IsLocked:       locked,
		FailedAttempts: failedAttempts,
	}

	if locked {
		response.RemainingTime = formatDuration(remainingTime)
		response.RemainingSeconds = int(remainingTime.Seconds())
	}

	h.logger.Info("account status checked",
		logger.EmailHash(email),
		zap.Bool("is_locked", locked),
		zap.Int("failed_attempts", failedAttempts))

	httpresponse.OK(w, response)
}

// formatDuration formats a duration into a human-readable string
func formatDuration(d time.Duration) string {
	if d < 0 {
		return "0s"
	}

	hours := int(d.Hours())
	minutes := int(d.Minutes()) % 60
	seconds := int(d.Seconds()) % 60

	if hours > 0 {
		return formatWithUnit(hours, "hour") + " " + formatWithUnit(minutes, "minute")
	}
	if minutes > 0 {
		return formatWithUnit(minutes, "minute") + " " + formatWithUnit(seconds, "second")
	}
	return formatWithUnit(seconds, "second")
}

func formatWithUnit(value int, unit string) string {
	if value == 0 {
		return ""
	}
	if value == 1 {
		return "1 " + unit
	}
	return string(rune(value)) + " " + unit + "s"
}
