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

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

	"go.uber.org/zap"

	securityeventservice "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/service/securityevent"
	"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"
)

// UnlockAccountHandler handles HTTP requests for unlocking locked accounts
type UnlockAccountHandler struct {
	loginRateLimiter    ratelimit.LoginRateLimiter
	securityEventLogger securityeventservice.Logger
	logger              *zap.Logger
}

// NewUnlockAccountHandler creates a new unlock account handler
func NewUnlockAccountHandler(
	loginRateLimiter ratelimit.LoginRateLimiter,
	securityEventLogger securityeventservice.Logger,
	logger *zap.Logger,
) *UnlockAccountHandler {
	return &UnlockAccountHandler{
		loginRateLimiter:    loginRateLimiter,
		securityEventLogger: securityEventLogger,
		logger:              logger.Named("unlock-account-handler"),
	}
}

// ProvideUnlockAccountHandler creates a new UnlockAccountHandler for dependency injection
func ProvideUnlockAccountHandler(
	loginRateLimiter ratelimit.LoginRateLimiter,
	securityEventLogger securityeventservice.Logger,
	logger *zap.Logger,
) *UnlockAccountHandler {
	return NewUnlockAccountHandler(loginRateLimiter, securityEventLogger, logger)
}

// UnlockAccountRequest represents the unlock account request payload
type UnlockAccountRequest struct {
	Email string `json:"email"`
}

// UnlockAccountResponse represents the unlock account response
type UnlockAccountResponse struct {
	Success bool   `json:"success"`
	Message string `json:"message"`
	Email   string `json:"email"`
}

// Handle processes POST /api/v1/admin/unlock-account requests
// This endpoint allows administrators to manually unlock accounts that have been
// locked due to excessive failed login attempts
func (h *UnlockAccountHandler) Handle(w http.ResponseWriter, r *http.Request) {
	h.logger.Debug("handling unlock account request")

	// Parse request body
	body, err := io.ReadAll(r.Body)
	if err != nil {
		h.logger.Warn("failed to read request body", zap.Error(err))
		httperror.ProblemBadRequest(w, "Invalid request body")
		return
	}
	defer r.Body.Close()

	var req UnlockAccountRequest
	if err := json.Unmarshal(body, &req); err != nil {
		h.logger.Warn("failed to parse request body", zap.Error(err))
		httperror.ProblemBadRequest(w, "Invalid JSON")
		return
	}

	// CWE-20: Comprehensive email validation
	emailValidator := validation.NewEmailValidator()
	normalizedEmail, err := emailValidator.ValidateAndNormalize(req.Email, "email")
	if err != nil {
		h.logger.Warn("invalid email", zap.Error(err))
		httperror.ProblemBadRequest(w, err.Error())
		return
	}
	req.Email = normalizedEmail

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

	if !locked {
		h.logger.Info("account not locked - nothing to do",
			logger.EmailHash(req.Email))
		httpresponse.OK(w, &UnlockAccountResponse{
			Success: true,
			Message: "Account is not locked",
			Email:   req.Email,
		})
		return
	}

	// Unlock the account
	if err := h.loginRateLimiter.UnlockAccount(r.Context(), req.Email); err != nil {
		h.logger.Error("failed to unlock account",
			logger.EmailHash(req.Email),
			zap.Error(err))
		httperror.ProblemInternalServerError(w, "Failed to unlock account")
		return
	}

	// Get admin user ID from context (set by JWT middleware)
	// TODO: Extract admin user ID from JWT claims when authentication is added
	adminUserID := "admin" // Placeholder until JWT middleware is integrated

	// Log security event
	redactor := logger.NewSensitiveFieldRedactor()
	if err := h.securityEventLogger.LogAccountUnlocked(
		r.Context(),
		redactor.HashForLogging(req.Email),
		adminUserID,
	); err != nil {
		h.logger.Error("failed to log security event",
			logger.EmailHash(req.Email),
			zap.Error(err))
		// Don't fail the request if logging fails
	}

	h.logger.Info("account unlocked successfully",
		logger.EmailHash(req.Email),
		logger.SafeEmail("email_redacted", req.Email),
		zap.Duration("was_locked_for", remainingTime))

	httpresponse.OK(w, &UnlockAccountResponse{
		Success: true,
		Message: "Account unlocked successfully",
		Email:   req.Email,
	})
}
