package handlers

import (
	"errors"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"gauth-central/internal/database"
	"gauth-central/internal/models"
	"gauth-central/internal/services"
	"gauth-central/pkg/utils"

	"github.com/gin-gonic/gin"
)

type UserManagementHandler struct {
	userService *services.UserManagementService
}

func NewUserManagementHandler(userService *services.UserManagementService) *UserManagementHandler {
	return &UserManagementHandler{
		userService: userService,
	}
}

// GetAllUsers godoc
// @Summary Get all users (Admin only)
// @Tags Admin - User Management
// @Security ApiKeyAuth
// @Produce json
// @Param page query int false "Page number" default(1)
// @Param limit query int false "Items per page" default(10)
// @Success 200 {object} map[string]interface{}
// @Router /admin/users [get]
func (h *UserManagementHandler) GetAllUsers(c *gin.Context) {
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))

	if page < 1 {
		page = 1
	}
	if limit < 1 || limit > 100 {
		limit = 10
	}

	users, total, err := h.userService.GetAllUsers(page, limit)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch users"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"users": users,
		"pagination": gin.H{
			"page":       page,
			"limit":      limit,
			"total":      total,
			"totalPages": (total + int64(limit) - 1) / int64(limit),
		},
	})
}

// GetUserByID godoc
// @Summary Get user by ID (Admin only)
// @Tags Admin - User Management
// @Security ApiKeyAuth
// @Produce json
// @Param id path string true "User ID"
// @Success 200 {object} models.User
// @Router /admin/users/{id} [get]
func (h *UserManagementHandler) GetUserByID(c *gin.Context) {
	userID := c.Param("id")

	user, err := h.userService.GetUserByID(userID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
		return
	}

	c.JSON(http.StatusOK, user)
}

// CreateUser godoc
// @Summary Create new user (Admin only)
// @Tags Admin - User Management
// @Security ApiKeyAuth
// @Accept multipart/form-data
// @Produce json
// @Param email formData string true "Email"
// @Param password formData string true "Password"
// @Param user_name formData string true "Username"
// @Param email_verified formData boolean false "Email verified"
// @Param roles formData string false "Roles (comma separated: admin,user)"
// @Param avatar formData file false "Avatar image"
// @Success 201 {object} models.User
// @Router /admin/users [post]
func (h *UserManagementHandler) CreateUser(c *gin.Context) {
	// Parse multipart form
	if err := c.Request.ParseMultipartForm(32 << 20); err != nil { // 32MB max
		c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse form data"})
		return
	}

	email := c.PostForm("email")
	password := c.PostForm("password")
	userName := c.PostForm("user_name")
	emailVerified := c.PostForm("email_verified") == "true"
	rolesStr := c.PostForm("roles")

	// Validate required fields
	if email == "" || password == "" || userName == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "email, password, and user_name are required"})
		return
	}

	// Parse roles
	var roles []string
	if rolesStr != "" {
		roles = strings.Split(rolesStr, ",")
		// Trim spaces
		for i, role := range roles {
			roles[i] = strings.TrimSpace(role)
		}
	}

	user, err := h.userService.CreateUser(
		email,
		password,
		userName,
		emailVerified,
		roles,
	)

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user: " + err.Error()})
		return
	}

	// Handle avatar upload if provided
	avatarFile, err := c.FormFile("avatar")
	if err == nil && avatarFile != nil {
		// Validate file size (max 5MB)
		if avatarFile.Size > 5*1024*1024 {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Avatar file size exceeds 5MB limit"})
			return
		}

		// Use utils.SaveOptimizedImage
		// Default options (WebP, 800px width)
		avatarURL, err := utils.SaveOptimizedImage(avatarFile, "./uploads/avatars", user.ID.String(), nil)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save avatar: " + err.Error()})
			return
		}

		// Update user avatar
		database.DB.Model(&user).Update("avatar", avatarURL)
		user.Avatar = avatarURL
	}

	c.JSON(http.StatusCreated, user)
}

// UpdateUser godoc
// @Summary Update user (Admin only)
// @Tags Admin - User Management
// @Security ApiKeyAuth
// @Accept multipart/form-data
// @Produce json
// @Param id path string true "User ID"
// @Param email formData string false "Email"
// @Param password formData string false "Password"
// @Param user_name formData string false "Username"
// @Param email_verified formData boolean false "Email verified"
// @Param roles formData string false "Roles (comma separated: admin,user)"
// @Param avatar formData file false "Avatar image"
// @Success 200 {object} map[string]interface{}
// @Router /admin/users/{id} [put]
func (h *UserManagementHandler) UpdateUser(c *gin.Context) {
	userID := c.Param("id")

	// Try to parse as multipart form first
	contentType := c.GetHeader("Content-Type")
	isMultipart := strings.Contains(contentType, "multipart/form-data")

	updates := make(map[string]interface{})
	var roles []string

	if isMultipart {
		// Parse multipart form
		if err := c.Request.ParseMultipartForm(32 << 20); err != nil { // 32MB max
			c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse form data"})
			return
		}

		// Get form values
		if email := c.PostForm("email"); email != "" {
			updates["email"] = email
		}
		if password := c.PostForm("password"); password != "" {
			updates["password"] = password
		}
		if userName := c.PostForm("user_name"); userName != "" {
			updates["user_name"] = userName
		}
		if emailVerified := c.PostForm("email_verified"); emailVerified != "" {
			updates["email_verified"] = emailVerified == "true"
		}
		if rolesStr := c.PostForm("roles"); rolesStr != "" {
			roles = strings.Split(rolesStr, ",")
			for i, role := range roles {
				roles[i] = strings.TrimSpace(role)
			}
		}
	} else {
		// Parse as JSON
		var input struct {
			Email         *string  `json:"email"`
			Password      *string  `json:"password"`
			UserName      *string  `json:"user_name"`
			Avatar        *string  `json:"avatar"`
			EmailVerified *bool    `json:"email_verified"`
			Roles         []string `json:"roles"`
		}

		if err := c.ShouldBindJSON(&input); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		if input.Email != nil {
			updates["email"] = *input.Email
		}
		if input.Password != nil {
			updates["password"] = *input.Password
		}
		if input.UserName != nil {
			updates["user_name"] = *input.UserName
		}
		if input.Avatar != nil {
			updates["avatar"] = *input.Avatar
		}
		if input.EmailVerified != nil {
			updates["email_verified"] = *input.EmailVerified
		}
		if input.Roles != nil {
			roles = input.Roles
		}
	}

	// Update basic user fields
	if len(updates) > 0 {
		if err := h.userService.UpdateUser(userID, updates); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user"})
			return
		}
	}

	// Update roles if provided
	if len(roles) > 0 {
		if err := h.userService.AssignRoles(userID, roles); err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update roles: " + err.Error()})
			return
		}
	}

	// Handle avatar upload if multipart and file provided
	if isMultipart {
		avatarFile, err := c.FormFile("avatar")
		if err == nil && avatarFile != nil {
			// Validate file size (max 5MB)
			if avatarFile.Size > 5*1024*1024 {
				c.JSON(http.StatusBadRequest, gin.H{"error": "Avatar file size exceeds 5MB limit"})
				return
			}

			// Get user to check for old avatar
			var user models.User
			if err := database.DB.Where("id = ?", userID).First(&user).Error; err != nil {
				c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
				return
			}

			// Delete old avatar if exists and is local
			if user.Avatar != "" && strings.HasPrefix(user.Avatar, "/uploads/") {
				oldPath := "." + user.Avatar
				os.Remove(oldPath)
			}

			// Use utils.SaveOptimizedImage
			avatarURL, err := utils.SaveOptimizedImage(avatarFile, "./uploads/avatars", userID, nil)
			if err != nil {
				c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save avatar: " + err.Error()})
				return
			}

			// Update user avatar
			if err := database.DB.Model(&user).Update("avatar", avatarURL).Error; err != nil {
				c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update avatar in database"})
				return
			}
		}
	}

	// Get updated user to return
	user, err := h.userService.GetUserByID(userID)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"message": "User updated successfully"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"message": "User updated successfully",
		"user":    user,
	})
}

// DeleteUser godoc
// @Summary Delete user (Admin only)
// @Tags Admin - User Management
// @Security ApiKeyAuth
// @Param id path string true "User ID"
// @Param hard query boolean false "Hard delete (permanent)" default(false)
// @Success 200 {object} map[string]interface{}
// @Router /admin/users/{id} [delete]
func (h *UserManagementHandler) DeleteUser(c *gin.Context) {
	userID := c.Param("id")
	hardDelete := c.Query("hard") == "true"

	// Prevent deleting self
	currentUserID := c.GetString("user_id")
	if userID == currentUserID {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Cannot delete your own account"})
		return
	}

	if err := h.userService.DeleteUser(userID, hardDelete); err != nil {
		if errors.Is(err, services.ErrUserNotFound) {
			c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete user"})
		return
	}

	deleteType := "soft"
	if hardDelete {
		deleteType = "permanently"
	}
	c.JSON(http.StatusOK, gin.H{"message": "User deleted " + deleteType + " successfully"})
}

// AssignRoles godoc
// @Summary Assign roles to user (Admin only)
// @Tags Admin - User Management
// @Security ApiKeyAuth
// @Accept json
// @Produce json
// @Param id path string true "User ID"
// @Param roles body object true "Roles"
// @Success 200 {object} map[string]interface{}
// @Router /admin/users/{id}/roles [post]
func (h *UserManagementHandler) AssignRoles(c *gin.Context) {
	userID := c.Param("id")

	var input struct {
		Roles []string `json:"roles" binding:"required"` // ["admin", "user"]
	}

	if err := c.ShouldBindJSON(&input); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	if err := h.userService.AssignRoles(userID, input.Roles); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to assign roles: " + err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Roles assigned successfully"})
}

// RemoveRole godoc
// @Summary Remove role from user (Admin only)
// @Tags Admin - User Management
// @Security ApiKeyAuth
// @Param id path string true "User ID"
// @Param role path string true "Role name"
// @Success 200 {object} map[string]interface{}
// @Router /admin/users/{id}/roles/{role} [delete]
func (h *UserManagementHandler) RemoveRole(c *gin.Context) {
	userID := c.Param("id")
	roleName := c.Param("role")

	if err := h.userService.RemoveRole(userID, roleName); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to remove role"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "Role removed successfully"})
}

// SearchUsers godoc
// @Summary Search users (Admin only)
// @Tags Admin - User Management
// @Security ApiKeyAuth
// @Produce json
// @Param q query string true "Search query"
// @Param page query int false "Page number" default(1)
// @Param limit query int false "Items per page" default(10)
// @Success 200 {object} map[string]interface{}
// @Router /admin/users/search [get]
func (h *UserManagementHandler) SearchUsers(c *gin.Context) {
	query := c.Query("q")
	if query == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Search query required"})
		return
	}

	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))

	if page < 1 {
		page = 1
	}
	if limit < 1 || limit > 100 {
		limit = 10
	}

	users, total, err := h.userService.SearchUsers(query, page, limit)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to search users"})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"users": users,
		"pagination": gin.H{
			"page":       page,
			"limit":      limit,
			"total":      total,
			"totalPages": (total + int64(limit) - 1) / int64(limit),
		},
	})
}

// GetDeletedUsers godoc
// @Summary Get all soft deleted users (Admin only)
// @Tags Admin - User Management
// @Security ApiKeyAuth
// @Produce json
// @Param page query int false "Page number" default(1)
// @Param limit query int false "Items per page" default(10)
// @Success 200 {object} map[string]interface{}
// @Router /admin/users/deleted [get]
func (h *UserManagementHandler) GetDeletedUsers(c *gin.Context) {
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))

	if page < 1 {
		page = 1
	}
	if limit < 1 || limit > 100 {
		limit = 10
	}

	users, total, err := h.userService.GetDeletedUsers(page, limit)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch deleted users"})
		return
	}

	// Transform users to include deleted_at field
	type DeletedUserResponse struct {
		ID             string                 `json:"id"`
		UserName       string                 `json:"username"`
		Email          string                 `json:"email"`
		Avatar         string                 `json:"avatar,omitempty"`
		EmailVerified  bool                   `json:"email_verified"`
		CreatedAt      time.Time              `json:"created_at"`
		UpdatedAt      time.Time              `json:"updated_at"`
		DeletedAt      *time.Time             `json:"deleted_at"`
		Roles          []models.Role          `json:"roles,omitempty"`
		SocialAccounts []models.SocialAccount `json:"social_accounts,omitempty"`
	}

	deletedUsers := make([]DeletedUserResponse, len(users))
	for i, user := range users {
		var deletedAt *time.Time
		if user.DeletedAt.Valid {
			deletedAt = &user.DeletedAt.Time
		}

		emailVerified := false
		if user.EmailVerified != nil {
			emailVerified = *user.EmailVerified
		}

		deletedUsers[i] = DeletedUserResponse{
			ID:             user.ID.String(),
			UserName:       user.UserName,
			Email:          user.Email,
			Avatar:         user.Avatar,
			EmailVerified:  emailVerified,
			CreatedAt:      user.CreatedAt,
			UpdatedAt:      user.UpdatedAt,
			DeletedAt:      deletedAt,
			Roles:          user.Roles,
			SocialAccounts: user.SocialAccounts,
		}
	}

	c.JSON(http.StatusOK, gin.H{
		"users": deletedUsers,
		"pagination": gin.H{
			"page":       page,
			"limit":      limit,
			"total":      total,
			"totalPages": (total + int64(limit) - 1) / int64(limit),
		},
	})
}

// RestoreUser godoc
// @Summary Restore a soft deleted user (Admin only)
// @Tags Admin - User Management
// @Security ApiKeyAuth
// @Param id path string true "User ID"
// @Success 200 {object} map[string]interface{}
// @Router /admin/users/{id}/restore [post]
func (h *UserManagementHandler) RestoreUser(c *gin.Context) {
	userID := c.Param("id")

	if err := h.userService.RestoreUser(userID); err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "User restored successfully"})
}
