package handlers

import (
	"net/http"
	"strconv"
	"time"

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

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

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

// NewAdminUserProfileHandler creates a new admin user profile handler
func NewAdminUserProfileHandler(db *gorm.DB) *AdminUserProfileHandler {
	return &AdminUserProfileHandler{db: db}
}

// UserProfileResponse represents the response for a user profile
type UserProfileResponse struct {
	ID             uint    `json:"id"`
	UserID         uint    `json:"user_id"`
	Username       string  `json:"username"`
	Email          string  `json:"email"`
	Verified       bool    `json:"verified"`
	Bio            string  `json:"bio"`
	PhoneNumber    string  `json:"phone_number"`
	DateOfBirth    *string `json:"date_of_birth"`
	ProfilePicture string  `json:"profile_picture"`
	CreatedAt      string  `json:"created_at"`
	UpdatedAt      string  `json:"updated_at"`
}

// UpdateUserProfileRequest represents the request to update a user profile
type UpdateUserProfileRequest struct {
	Verified       *bool   `json:"verified"`
	Bio            *string `json:"bio"`
	PhoneNumber    *string `json:"phone_number"`
	DateOfBirth    *string `json:"date_of_birth"`
	ProfilePicture *string `json:"profile_picture"`
}

// List handles GET /api/admin/user-profiles
func (h *AdminUserProfileHandler) 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 profiles []models.UserProfile
	var total int64

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

	// Apply search
	if filters.Search != "" {
		search := "%" + filters.Search + "%"
		query = query.Joins("JOIN auth_user ON auth_user.id = user_userprofile.user_id").
			Where("auth_user.username ILIKE ? OR auth_user.email ILIKE ? OR user_userprofile.phone_number 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", "verified", "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(&profiles).Error; err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch user profiles"})
	}

	// Build response
	responses := make([]UserProfileResponse, len(profiles))
	for i, profile := range profiles {
		responses[i] = h.toProfileResponse(&profile)
	}

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

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

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

	return c.JSON(http.StatusOK, h.toProfileResponse(&profile))
}

// GetByUser handles GET /api/admin/user-profiles/user/:user_id
func (h *AdminUserProfileHandler) GetByUser(c echo.Context) error {
	userID, err := strconv.ParseUint(c.Param("user_id"), 10, 32)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid user ID"})
	}

	var profile models.UserProfile
	if err := h.db.Preload("User").Where("user_id = ?", userID).First(&profile).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return c.JSON(http.StatusNotFound, map[string]interface{}{"error": "User profile not found"})
		}
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to fetch user profile"})
	}

	return c.JSON(http.StatusOK, h.toProfileResponse(&profile))
}

// Update handles PUT /api/admin/user-profiles/:id
func (h *AdminUserProfileHandler) Update(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 profile ID"})
	}

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

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

	if req.Verified != nil {
		profile.Verified = *req.Verified
	}
	if req.Bio != nil {
		profile.Bio = *req.Bio
	}
	if req.PhoneNumber != nil {
		profile.PhoneNumber = *req.PhoneNumber
	}
	if req.ProfilePicture != nil {
		profile.ProfilePicture = *req.ProfilePicture
	}
	if req.DateOfBirth != nil {
		if *req.DateOfBirth == "" {
			profile.DateOfBirth = nil
		} else {
			dob, err := time.Parse("2006-01-02", *req.DateOfBirth)
			if err != nil {
				return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": "Invalid date format for date_of_birth, use YYYY-MM-DD"})
			}
			profile.DateOfBirth = &dob
		}
	}

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

	h.db.Preload("User").First(&profile, id)
	return c.JSON(http.StatusOK, h.toProfileResponse(&profile))
}

// Delete handles DELETE /api/admin/user-profiles/:id
func (h *AdminUserProfileHandler) 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 profile ID"})
	}

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

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

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

// BulkDelete handles DELETE /api/admin/user-profiles/bulk
func (h *AdminUserProfileHandler) 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.UserProfile{})
	if result.Error != nil {
		return c.JSON(http.StatusInternalServerError, map[string]interface{}{"error": "Failed to delete user profiles"})
	}

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

// toProfileResponse converts a UserProfile model to UserProfileResponse
func (h *AdminUserProfileHandler) toProfileResponse(profile *models.UserProfile) UserProfileResponse {
	response := UserProfileResponse{
		ID:             profile.ID,
		UserID:         profile.UserID,
		Verified:       profile.Verified,
		Bio:            profile.Bio,
		PhoneNumber:    profile.PhoneNumber,
		ProfilePicture: profile.ProfilePicture,
		CreatedAt:      profile.CreatedAt.Format("2006-01-02T15:04:05Z"),
		UpdatedAt:      profile.UpdatedAt.Format("2006-01-02T15:04:05Z"),
	}

	if profile.DateOfBirth != nil {
		dob := profile.DateOfBirth.Format("2006-01-02")
		response.DateOfBirth = &dob
	}

	if profile.User.ID != 0 {
		response.Username = profile.User.Username
		response.Email = profile.User.Email
	}

	return response
}
