package handlers

import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"go.uber.org/zap"
	"veza-backend-api/internal/services"
	"veza-backend-api/internal/types"
)

// ProfileHandler handles profile-related operations
type ProfileHandler struct {
	userService   *services.UserService
	commonHandler *CommonHandler
}

// NewProfileHandler creates a new ProfileHandler instance
func NewProfileHandler(userService *services.UserService, logger *zap.Logger) *ProfileHandler {
	return &ProfileHandler{
		userService:   userService,
		commonHandler: NewCommonHandler(logger),
	}
}

// GetProfile retrieves a public user profile by ID
func (h *ProfileHandler) GetProfile(c *gin.Context) {
	userIDStr := c.Param("id")
	userID, err := uuid.Parse(userIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user id"})
		return
	}

	// Get the requesting user ID if authenticated (optional)
	var requesterID *uuid.UUID
	if reqID, exists := c.Get("user_id"); exists {
		if reqUUID, ok := reqID.(uuid.UUID); ok {
			requesterID = &reqUUID
		}
	}

	// Get user profile with privacy check
	profile, err := h.userService.GetProfile(userID, requesterID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"profile": profile})
}

// GetProfileByUsername retrieves a public profile by username
func (h *ProfileHandler) GetProfileByUsername(c *gin.Context) {
	username := c.Param("username")
	if username == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "username required"})
		return
	}

	// Get the requesting user ID if authenticated (optional)
	var requesterID *uuid.UUID
	if reqID, exists := c.Get("user_id"); exists {
		if reqUUID, ok := reqID.(uuid.UUID); ok {
			requesterID = &reqUUID
		}
	}

	// Get profile with privacy check
	profile, err := h.userService.GetProfileByUsername(username, requesterID)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"profile": profile})
}

// GetProfileCompletion retrieves the profile completion status
// T0220: Returns percentage and missing fields
func (h *ProfileHandler) GetProfileCompletion(c *gin.Context) {
	userIDStr := c.Param("id")
	userID, err := uuid.Parse(userIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user id"})
		return
	}

	// Get authenticated user ID
	var authenticatedUserID uuid.UUID
	if reqID, exists := c.Get("user_id"); exists {
		if reqUUID, ok := reqID.(uuid.UUID); ok {
			authenticatedUserID = reqUUID
		} else {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
			return
		}
	} else {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
		return
	}

	// Verify that user_id corresponds to authenticated user
	if userID != authenticatedUserID {
		c.JSON(http.StatusForbidden, gin.H{"error": "cannot access other user's profile completion"})
		return
	}

	// Calculate profile completion
	completion, err := h.userService.CalculateProfileCompletion(userID)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to calculate profile completion"})
		return
	}

	c.JSON(http.StatusOK, completion)
}

// UpdateProfileRequest represents the request body for updating a user profile
type UpdateProfileRequest struct {
	FirstName string `json:"first_name" binding:"omitempty,max=100"`
	LastName  string `json:"last_name" binding:"omitempty,max=100"`
	Username  string `json:"username" binding:"omitempty,min=3,max=30"`
	Bio       string `json:"bio" binding:"omitempty,max=500"`
	Location  string `json:"location" binding:"omitempty,max=100"`
	Birthdate string `json:"birthdate" binding:"omitempty,datetime=2006-01-02"`
	Gender    string `json:"gender" binding:"omitempty,oneof=Male Female Other 'Prefer not to say'"`
}

// UpdateProfile updates a user profile
func (h *ProfileHandler) UpdateProfile(c *gin.Context) {
	userIDStr := c.Param("id")
	userID, err := uuid.Parse(userIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user id"})
		return
	}

	// Get authenticated user ID
	var authenticatedUserID uuid.UUID
	if reqID, exists := c.Get("user_id"); exists {
		if reqUUID, ok := reqID.(uuid.UUID); ok {
			authenticatedUserID = reqUUID
		} else {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
			return
		}
	} else {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "user not authenticated"})
		return
	}

	// Verify that user_id corresponds to authenticated user
	if userID != authenticatedUserID {
		c.JSON(http.StatusForbidden, gin.H{"error": "cannot update other user's profile"})
		return
	}

	var req UpdateProfileRequest
	if appErr := h.commonHandler.BindAndValidateJSON(c, &req); appErr != nil {
		RespondWithAppError(c, appErr)
		return
	}

	// Validate username if provided
	if req.Username != "" {
		// Validate username format (alphanumeric + underscore, 3-30 chars)
		if !isValidUsername(req.Username) {
			c.JSON(http.StatusBadRequest, gin.H{"error": "username must be 3-30 characters, alphanumeric and underscore only"})
			return
		}

		// Validate username uniqueness if modified
		if err := h.userService.ValidateUsername(userID, req.Username); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		// Check if username can be modified (once per month)
		canChange, err := h.userService.CanChangeUsername(userID)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to check username change eligibility"})
			return
		}
		if !canChange {
			c.JSON(http.StatusBadRequest, gin.H{"error": "username can only be changed once per month"})
			return
		}
	}

	// Validate birthdate if provided
	if req.Birthdate != "" {
		birthdate, err := time.Parse("2006-01-02", req.Birthdate)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid birthdate format, expected YYYY-MM-DD"})
			return
		}

		// Check if user is at least 13 years old
		age := time.Since(birthdate)
		minAge := 13 * 365 * 24 * time.Hour // 13 years
		if age < minAge {
			c.JSON(http.StatusBadRequest, gin.H{"error": "user must be at least 13 years old"})
			return
		}
	}

	// Convert UpdateProfileRequest to types.UpdateProfileRequest
	serviceReq := types.UpdateProfileRequest{
		FirstName: &req.FirstName,
		LastName:  &req.LastName,
		Username:  &req.Username,
		Bio:       &req.Bio,
		Location:  &req.Location,
		Gender:    &req.Gender,
	}

	if req.Birthdate != "" {
		birthdate, _ := time.Parse("2006-01-02", req.Birthdate)
		birthdateStr := birthdate.Format("2006-01-02")
		serviceReq.BirthDate = &birthdateStr
	}

	// Update profile using the new UpdateProfile method
	profile, err := h.userService.UpdateProfile(userID, serviceReq)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update profile"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"profile": profile})
}

// isValidUsername validates username format (alphanumeric + underscore, 3-30 chars)
func isValidUsername(username string) bool {
	if len(username) < 3 || len(username) > 30 {
		return false
	}

	for _, char := range username {
		if !((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9') || char == '_') {
			return false
		}
	}

	return true
}