package handlers

import (
	"fmt"
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"

	"customer-support-system/internal/auth"
	"customer-support-system/internal/database"
	"customer-support-system/internal/models"
	"customer-support-system/pkg/logger"
)

// UserHandler handles user-related HTTP requests
type UserHandler struct {
	authService *auth.AuthService
}

// NewUserHandler creates a new user handler
func NewUserHandler() *UserHandler {
	return &UserHandler{
		authService: auth.NewAuthService(database.GetDB()),
	}
}

// Register handles user registration
func (h *UserHandler) Register(c *gin.Context) {
	var req models.CreateUserRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.WithError(err).Error("Failed to parse register request")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid request body",
		})
		return
	}

	// Validate request
	if err := validateRegisterRequest(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": err.Error(),
		})
		return
	}

	// Create user
	user, err := h.authService.Register(&req)
	if err != nil {
		logger.WithError(err).Error("Failed to register user")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to register user",
		})
		return
	}

	c.JSON(http.StatusCreated, gin.H{
		"success": true,
		"message": "User registered successfully",
		"data": gin.H{
			"user": user,
		},
	})
}

// Login handles user login
func (h *UserHandler) Login(c *gin.Context) {
	var req models.LoginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.WithError(err).Error("Failed to parse login request")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid request body",
		})
		return
	}

	// Validate request
	if err := validateLoginRequest(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": err.Error(),
		})
		return
	}

	// Get client IP
	clientIP := c.ClientIP()

	// Authenticate user
	response, err := h.authService.Login(req.Username, req.Password, clientIP)
	if err != nil {
		logger.WithError(err).Error("Failed to login user")
		c.JSON(http.StatusUnauthorized, gin.H{
			"success": false,
			"message": "Invalid username or password",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"message": "User logged in successfully",
		"data": gin.H{
			"user":  response.User,
			"token": response.Token,
		},
	})
}

// GetProfile handles getting user profile
func (h *UserHandler) GetProfile(c *gin.Context) {
	// Get user ID from context
	userID, exists := c.Get("userID")
	if !exists {
		logger.Error("Failed to get user ID from context")
		c.JSON(http.StatusUnauthorized, gin.H{
			"success": false,
			"message": "Unauthorized",
		})
		return
	}

	// Get user profile
	user, err := h.authService.GetUserByID(userID.(uint))
	if err != nil {
		logger.WithError(err).Error("Failed to get user profile")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to get user profile",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": gin.H{
			"user": user.ToSafeUser(),
		},
	})
}

// UpdateProfile handles updating user profile
func (h *UserHandler) UpdateProfile(c *gin.Context) {
	// Get user ID from context
	userID, exists := c.Get("userID")
	if !exists {
		logger.Error("Failed to get user ID from context")
		c.JSON(http.StatusUnauthorized, gin.H{
			"success": false,
			"message": "Unauthorized",
		})
		return
	}

	var req models.UpdateUserRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.WithError(err).Error("Failed to parse update profile request")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid request body",
		})
		return
	}

	// Update user profile
	user, err := h.authService.UpdateUser(userID.(uint), &req)
	if err != nil {
		logger.WithError(err).Error("Failed to update user profile")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to update user profile",
		})
		return
	}

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

// ChangePassword handles changing user password
func (h *UserHandler) ChangePassword(c *gin.Context) {
	// Get user ID from context
	userID, exists := c.Get("userID")
	if !exists {
		logger.Error("Failed to get user ID from context")
		c.JSON(http.StatusUnauthorized, gin.H{
			"success": false,
			"message": "Unauthorized",
		})
		return
	}

	var req models.ChangePasswordRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.WithError(err).Error("Failed to parse change password request")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid request body",
		})
		return
	}

	// Validate request
	if err := validateChangePasswordRequest(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": err.Error(),
		})
		return
	}

	// Change password
	err := h.authService.ChangePassword(userID.(uint), &req)
	if err != nil {
		logger.WithError(err).Error("Failed to change password")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to change password",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"message": "Password changed successfully",
	})
}

// validateRegisterRequest validates the register request
func validateRegisterRequest(req *models.CreateUserRequest) error {
	if req.Username == "" {
		return fmt.Errorf("username is required")
	}
	if req.Password == "" {
		return fmt.Errorf("password is required")
	}
	if req.Email == "" {
		return fmt.Errorf("email is required")
	}
	return nil
}

// validateLoginRequest validates the login request
func validateLoginRequest(req *models.LoginRequest) error {
	if req.Username == "" {
		return fmt.Errorf("username is required")
	}
	if req.Password == "" {
		return fmt.Errorf("password is required")
	}
	return nil
}

// validateChangePasswordRequest validates the change password request
func validateChangePasswordRequest(req *models.ChangePasswordRequest) error {
	if req.CurrentPassword == "" {
		return fmt.Errorf("current password is required")
	}
	if req.NewPassword == "" {
		return fmt.Errorf("new password is required")
	}
	return nil
}

// AdminGetUsers handles getting all users (admin only)
func (h *UserHandler) AdminGetUsers(c *gin.Context) {
	// Parse query parameters
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
	if page < 1 {
		page = 1
	}
	if pageSize < 1 || pageSize > 100 {
		pageSize = 10
	}

	// Get users
	var users []models.User
	var total int64

	db := database.GetDB()

	// Get total count
	if err := db.Model(&models.User{}).Count(&total).Error; err != nil {
		logger.WithError(err).Error("Failed to count users")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to count users",
		})
		return
	}

	// Get paginated results
	offset := (page - 1) * pageSize
	if err := db.Offset(offset).Limit(pageSize).Find(&users).Error; err != nil {
		logger.WithError(err).Error("Failed to get users")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to get users",
		})
		return
	}

	// Convert to safe users
	safeUsers := make([]models.SafeUser, len(users))
	for i, user := range users {
		safeUsers[i] = user.ToSafeUser()
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": gin.H{
			"users":    safeUsers,
			"total":    total,
			"page":     page,
			"pageSize": pageSize,
		},
	})
}

// AdminGetUser handles getting a user by ID (admin only)
func (h *UserHandler) AdminGetUser(c *gin.Context) {
	// Get target user ID from URL params
	targetUserID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse user ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid user ID",
		})
		return
	}

	// Get user
	user, err := h.authService.GetUserByID(uint(targetUserID))
	if err != nil {
		logger.WithError(err).Error("Failed to get user")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to get user",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"data": gin.H{
			"user": user.ToSafeUser(),
		},
	})
}

// AdminUpdateUser handles updating a user (admin only)
func (h *UserHandler) AdminUpdateUser(c *gin.Context) {
	// Get target user ID from URL params
	targetUserID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse user ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid user ID",
		})
		return
	}

	var req models.UpdateUserRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		logger.WithError(err).Error("Failed to parse update user request")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid request body",
		})
		return
	}

	// Update user
	updatedUser, err := h.authService.UpdateUser(uint(targetUserID), &req)
	if err != nil {
		logger.WithError(err).Error("Failed to update user")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to update user",
		})
		return
	}

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

// AdminDeleteUser handles deleting a user (admin only)
func (h *UserHandler) AdminDeleteUser(c *gin.Context) {
	// Get target user ID from URL params
	targetUserID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		logger.WithError(err).Error("Failed to parse user ID")
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Invalid user ID",
		})
		return
	}

	// Get current user ID from context
	currentUserID, exists := c.Get("userID")
	if !exists {
		logger.Error("Failed to get current user ID from context")
		c.JSON(http.StatusUnauthorized, gin.H{
			"success": false,
			"message": "Unauthorized",
		})
		return
	}

	// Prevent self-deletion
	if currentUserID.(uint) == uint(targetUserID) {
		c.JSON(http.StatusBadRequest, gin.H{
			"success": false,
			"message": "Cannot delete your own account",
		})
		return
	}

	// Delete user
	db := database.GetDB()
	if err := db.Delete(&models.User{}, uint(targetUserID)).Error; err != nil {
		logger.WithError(err).Error("Failed to delete user")
		c.JSON(http.StatusInternalServerError, gin.H{
			"success": false,
			"message": "Failed to delete user",
		})
		return
	}

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