package handlers

import (
	"net/http"
	"strconv"

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

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

// AdminUserManagementHandler handles admin user management endpoints
type AdminUserManagementHandler struct {
	db *gorm.DB
}

// NewAdminUserManagementHandler creates a new admin user management handler
func NewAdminUserManagementHandler(db *gorm.DB) *AdminUserManagementHandler {
	return &AdminUserManagementHandler{db: db}
}

// Note: AdminUserResponse is defined in auth_handler.go and reused here

// AdminUserFilters for listing admin users
type AdminUserFilters struct {
	dto.PaginationParams
	Role     *string `form:"role"`
	IsActive *bool   `form:"is_active"`
}

// CreateAdminUserRequest for creating a new admin user
type CreateAdminUserRequest struct {
	Email     string `json:"email" validate:"required,email"`
	Password  string `json:"password" validate:"required,min=8"`
	FirstName string `json:"first_name" validate:"max=100"`
	LastName  string `json:"last_name" validate:"max=100"`
	Role      string `json:"role" validate:"omitempty,oneof=admin super_admin"`
	IsActive  *bool  `json:"is_active"`
}

// UpdateAdminUserRequest for updating an admin user
type UpdateAdminUserRequest struct {
	Email     *string `json:"email" validate:"omitempty,email"`
	Password  *string `json:"password" validate:"omitempty,min=8"`
	FirstName *string `json:"first_name" validate:"omitempty,max=100"`
	LastName  *string `json:"last_name" validate:"omitempty,max=100"`
	Role      *string `json:"role" validate:"omitempty,oneof=admin super_admin"`
	IsActive  *bool   `json:"is_active"`
}

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

	var adminUsers []models.AdminUser
	var total int64

	query := h.db.Model(&models.AdminUser{})

	// Apply search
	if filters.Search != "" {
		search := "%" + filters.Search + "%"
		query = query.Where("email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?", search, search, search)
	}

	// Apply filters
	if filters.Role != nil {
		query = query.Where("role = ?", *filters.Role)
	}
	if filters.IsActive != nil {
		query = query.Where("is_active = ?", *filters.IsActive)
	}

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

	// Apply sorting (allowlist prevents SQL injection via sort_by parameter)
	sortBy := filters.GetSafeSortBy([]string{
		"id", "email", "first_name", "last_name",
		"role", "is_active", "created_at", "updated_at",
	}, "created_at")
	query = query.Order(sortBy + " " + filters.GetSortDir())

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

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

	responses := make([]AdminUserResponse, len(adminUsers))
	for i, u := range adminUsers {
		responses[i] = h.toAdminUserResponse(&u)
	}

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

// Get handles GET /api/admin/admin-users/:id
func (h *AdminUserManagementHandler) 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 admin user ID"})
	}

	var adminUser models.AdminUser
	if err := h.db.First(&adminUser, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Admin user not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch admin user"})
	}

	return c.JSON(http.StatusOK, h.toAdminUserResponse(&adminUser))
}

// Create handles POST /api/admin/admin-users
func (h *AdminUserManagementHandler) Create(c echo.Context) error {
	// Only super admins can create admin users
	currentAdmin := c.Get(middleware.AdminUserKey)
	if currentAdmin == nil {
		return c.JSON(http.StatusUnauthorized, map[string]interface{}{"error": "Unauthorized"})
	}
	admin := currentAdmin.(*models.AdminUser)
	if !admin.IsSuperAdmin() {
		return c.JSON(http.StatusForbidden, map[string]interface{}{"error": "Only super admins can create admin users"})
	}

	var req CreateAdminUserRequest
	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}
	if err := c.Validate(&req); err != nil {
		return err
	}

	// Check if email already exists
	var existingCount int64
	h.db.Model(&models.AdminUser{}).Where("email = ?", req.Email).Count(&existingCount)
	if existingCount > 0 {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Email already exists"})
	}

	adminUser := models.AdminUser{
		Email:     req.Email,
		FirstName: req.FirstName,
		LastName:  req.LastName,
		Role:      models.AdminRole(req.Role),
		IsActive:  true,
	}

	if req.Role == "" {
		adminUser.Role = models.AdminRoleAdmin
	}
	if req.IsActive != nil {
		adminUser.IsActive = *req.IsActive
	}

	if err := adminUser.SetPassword(req.Password); err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to hash password"})
	}

	if err := h.db.Create(&adminUser).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to create admin user"})
	}

	return c.JSON(http.StatusCreated, h.toAdminUserResponse(&adminUser))
}

// Update handles PUT /api/admin/admin-users/:id
func (h *AdminUserManagementHandler) Update(c echo.Context) error {
	// Only super admins can update admin users
	currentAdmin := c.Get(middleware.AdminUserKey)
	if currentAdmin == nil {
		return c.JSON(http.StatusUnauthorized, map[string]interface{}{"error": "Unauthorized"})
	}
	admin := currentAdmin.(*models.AdminUser)

	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid admin user ID"})
	}

	// Allow users to update themselves, but only super admins can update others
	if uint(id) != admin.ID && !admin.IsSuperAdmin() {
		return c.JSON(http.StatusForbidden, map[string]interface{}{"error": "Only super admins can update other admin users"})
	}

	var adminUser models.AdminUser
	if err := h.db.First(&adminUser, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Admin user not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch admin user"})
	}

	var req UpdateAdminUserRequest
	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid request body"})
	}
	if err := c.Validate(&req); err != nil {
		return err
	}

	if req.Email != nil {
		// Check if email already exists for another user
		var existingCount int64
		h.db.Model(&models.AdminUser{}).Where("email = ? AND id != ?", *req.Email, id).Count(&existingCount)
		if existingCount > 0 {
			return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Email already exists"})
		}
		adminUser.Email = *req.Email
	}
	if req.FirstName != nil {
		adminUser.FirstName = *req.FirstName
	}
	if req.LastName != nil {
		adminUser.LastName = *req.LastName
	}
	// Only super admins can change roles
	if req.Role != nil && admin.IsSuperAdmin() {
		adminUser.Role = models.AdminRole(*req.Role)
	}
	if req.IsActive != nil && admin.IsSuperAdmin() {
		// Prevent disabling yourself
		if uint(id) == admin.ID && !*req.IsActive {
			return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Cannot deactivate your own account"})
		}
		adminUser.IsActive = *req.IsActive
	}
	if req.Password != nil {
		if err := adminUser.SetPassword(*req.Password); err != nil {
			return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to hash password"})
		}
	}

	if err := h.db.Save(&adminUser).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to update admin user"})
	}

	return c.JSON(http.StatusOK, h.toAdminUserResponse(&adminUser))
}

// Delete handles DELETE /api/admin/admin-users/:id
func (h *AdminUserManagementHandler) Delete(c echo.Context) error {
	// Only super admins can delete admin users
	currentAdmin := c.Get(middleware.AdminUserKey)
	if currentAdmin == nil {
		return c.JSON(http.StatusUnauthorized, map[string]interface{}{"error": "Unauthorized"})
	}
	admin := currentAdmin.(*models.AdminUser)
	if !admin.IsSuperAdmin() {
		return c.JSON(http.StatusForbidden, map[string]interface{}{"error": "Only super admins can delete admin users"})
	}

	id, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid admin user ID"})
	}

	// Prevent self-deletion
	if uint(id) == admin.ID {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Cannot delete your own account"})
	}

	var adminUser models.AdminUser
	if err := h.db.First(&adminUser, id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "Admin user not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch admin user"})
	}

	if err := h.db.Delete(&adminUser).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete admin user"})
	}

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

func (h *AdminUserManagementHandler) toAdminUserResponse(u *models.AdminUser) AdminUserResponse {
	return NewAdminUserResponse(u)
}
