package handlers

import (
	"net/http"
	"strconv"
	"strings"

	"github.com/labstack/echo/v4"
	"gorm.io/gorm"

	"github.com/treytartt/honeydue-api/internal/admin/dto"
	"github.com/treytartt/honeydue-api/internal/models"
)

// maskCode masks a confirmation code, showing only the last 4 characters.
func maskCode(code string) string {
	if len(code) <= 4 {
		return strings.Repeat("*", len(code))
	}
	return strings.Repeat("*", len(code)-4) + code[len(code)-4:]
}

// AdminConfirmationCodeHandler handles admin confirmation code management endpoints
type AdminConfirmationCodeHandler struct {
	db *gorm.DB
}

// NewAdminConfirmationCodeHandler creates a new admin confirmation code handler
func NewAdminConfirmationCodeHandler(db *gorm.DB) *AdminConfirmationCodeHandler {
	return &AdminConfirmationCodeHandler{db: db}
}

// ConfirmationCodeResponse represents a confirmation code in API responses
type ConfirmationCodeResponse struct {
	ID        uint   `json:"id"`
	UserID    uint   `json:"user_id"`
	Username  string `json:"username"`
	Email     string `json:"email"`
	Code      string `json:"code"`
	ExpiresAt string `json:"expires_at"`
	IsUsed    bool   `json:"is_used"`
	CreatedAt string `json:"created_at"`
}

// List handles GET /api/admin/confirmation-codes
func (h *AdminConfirmationCodeHandler) List(c echo.Context) error {
	var filters dto.PaginationParams
	if err := c.Bind(&filters); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}

	var codes []models.ConfirmationCode
	var total int64

	query := h.db.Model(&models.ConfirmationCode{}).Preload("User")

	// Apply search (search by user info or code)
	if filters.Search != "" {
		search := "%" + filters.Search + "%"
		query = query.Joins("JOIN auth_user ON auth_user.id = user_confirmationcode.user_id").
			Where(
				"auth_user.username ILIKE ? OR auth_user.email ILIKE ? OR user_confirmationcode.code ILIKE ?",
				search, search, search,
			)
	}

	// Get total count
	query.Count(&total)

	// Apply sorting (allowlist prevents SQL injection via sort_by parameter)
	sortBy := filters.GetSafeSortBy([]string{
		"id", "user_id", "created_at", "expires_at", "is_used",
	}, "created_at")
	query = query.Order(sortBy + " " + filters.GetSortDir())

	// Apply pagination
	query = query.Offset(filters.GetOffset()).Limit(filters.GetPerPage())

	if err := query.Find(&codes).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch confirmation codes"})
	}

	// Build response
	responses := make([]ConfirmationCodeResponse, len(codes))
	for i, code := range codes {
		responses[i] = ConfirmationCodeResponse{
			ID:        code.ID,
			UserID:    code.UserID,
			Username:  code.User.Username,
			Email:     code.User.Email,
			Code:      maskCode(code.Code),
			ExpiresAt: code.ExpiresAt.Format("2006-01-02T15:04:05Z"),
			IsUsed:    code.IsUsed,
			CreatedAt: code.CreatedAt.Format("2006-01-02T15:04:05Z"),
		}
	}

	return c.JSON(http.StatusOK, dto.NewPaginatedResponse(responses, total, filters.GetPage(), filters.GetPerPage()))
}

// Get handles GET /api/admin/confirmation-codes/:id
func (h *AdminConfirmationCodeHandler) Get(c echo.Context) error {
	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid ID"})
	}

	var code models.ConfirmationCode
	if err := h.db.Preload("User").First(&code, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Confirmation code not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch confirmation code"})
	}

	response := ConfirmationCodeResponse{
		ID:        code.ID,
		UserID:    code.UserID,
		Username:  code.User.Username,
		Email:     code.User.Email,
		Code:      maskCode(code.Code),
		ExpiresAt: code.ExpiresAt.Format("2006-01-02T15:04:05Z"),
		IsUsed:    code.IsUsed,
		CreatedAt: code.CreatedAt.Format("2006-01-02T15:04:05Z"),
	}

	return c.JSON(http.StatusOK, response)
}

// Delete handles DELETE /api/admin/confirmation-codes/:id
func (h *AdminConfirmationCodeHandler) Delete(c echo.Context) error {
	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid ID"})
	}

	result := h.db.Delete(&models.ConfirmationCode{}, id)
	if result.Error != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete confirmation code"})
	}

	if result.RowsAffected == 0 {
		return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Confirmation code not found"})
	}

	return c.JSON(http.StatusOK, map[string]interface{}{"message": "Confirmation code deleted successfully"})
}

// BulkDelete handles DELETE /api/admin/confirmation-codes/bulk
func (h *AdminConfirmationCodeHandler) BulkDelete(c echo.Context) error {
	var req dto.BulkDeleteRequest
	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}

	result := h.db.Where("id IN ?", req.IDs).Delete(&models.ConfirmationCode{})
	if result.Error != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete confirmation codes"})
	}

	return c.JSON(http.StatusOK, map[string]interface{}{"message": "Confirmation codes deleted successfully", "count": result.RowsAffected})
}
