package services

import (
	"context"
	"errors"
	"fmt"
	"strings"

	"veza-backend-api/internal/models"
)

// SearchUsersParams représente les paramètres de recherche d'utilisateurs
// BE-API-008: Implement user search endpoint
type SearchUsersParams struct {
	Query string // Recherche par username, email, first_name, last_name
	Page  int    // Numéro de page (défaut: 1)
	Limit int    // Nombre de résultats par page (défaut: 20, max: 100)
}

// SearchUsers recherche des utilisateurs selon les critères fournis
// BE-API-008: Implement user search endpoint
func (s *UserService) SearchUsers(ctx context.Context, params SearchUsersParams) ([]*models.User, int64, error) {
	if s.db == nil {
		return nil, 0, errors.New("database connection not available")
	}

	// Appliquer la pagination
	if params.Limit <= 0 {
		params.Limit = 20
	}
	if params.Limit > 100 {
		params.Limit = 100
	}
	if params.Page < 1 {
		params.Page = 1
	}
	offset := (params.Page - 1) * params.Limit

	// Construire la requête de recherche
	query := s.db.WithContext(ctx).Model(&models.User{})

	// Recherche par query (username, email, first_name, last_name)
	if params.Query != "" {
		searchPattern := "%" + params.Query + "%"
		query = query.Where(
			"username ILIKE ? OR email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?",
			searchPattern, searchPattern, searchPattern, searchPattern,
		)
	}

	// Compter le total avant pagination
	var total int64
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, fmt.Errorf("failed to count users: %w", err)
	}

	// Appliquer pagination et récupérer les résultats
	var users []*models.User
	if err := query.Offset(offset).Limit(params.Limit).Find(&users).Error; err != nil {
		return nil, 0, fmt.Errorf("failed to search users: %w", err)
	}

	// Exclure les mots de passe des résultats
	for _, user := range users {
		user.PasswordHash = ""
	}

	return users, total, nil
}

// ListUsersParams représente les paramètres de liste d'utilisateurs
// BE-API-040: Implement user list endpoint
type ListUsersParams struct {
	Page       int    // Numéro de page (défaut: 1)
	Limit      int    // Nombre de résultats par page (défaut: 20, max: 100)
	Role       string // Filtrer par rôle (optionnel)
	IsActive   *bool  // Filtrer par statut actif (optionnel)
	IsVerified *bool  // Filtrer par statut vérifié (optionnel)
	Search     string // Recherche par username, email, first_name, last_name (optionnel)
	SortBy     string // Trier par champ (created_at, username, email) - défaut: created_at
	SortOrder  string // Ordre de tri (asc, desc) - défaut: desc
}

// ListUsers liste les utilisateurs avec pagination et filtrage
// BE-API-040: Implement user list endpoint
func (s *UserService) ListUsers(ctx context.Context, params ListUsersParams) ([]*models.User, int64, error) {
	if s.db == nil {
		return nil, 0, errors.New("database connection not available")
	}

	// Appliquer la pagination
	if params.Limit <= 0 {
		params.Limit = 20
	}
	if params.Limit > 100 {
		params.Limit = 100
	}
	if params.Page < 1 {
		params.Page = 1
	}
	offset := (params.Page - 1) * params.Limit

	// Construire la requête
	query := s.db.WithContext(ctx).Model(&models.User{})

	// Appliquer les filtres
	if params.Role != "" {
		query = query.Where("role = ?", params.Role)
	}
	if params.IsActive != nil {
		query = query.Where("is_active = ?", *params.IsActive)
	}
	if params.IsVerified != nil {
		query = query.Where("is_verified = ?", *params.IsVerified)
	}

	// Recherche par query (username, email, first_name, last_name)
	if params.Search != "" {
		searchPattern := "%" + params.Search + "%"
		query = query.Where(
			"username ILIKE ? OR email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?",
			searchPattern, searchPattern, searchPattern, searchPattern,
		)
	}

	// Compter le total avant pagination
	var total int64
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, fmt.Errorf("failed to count users: %w", err)
	}

	// Appliquer le tri
	sortBy := params.SortBy
	if sortBy == "" {
		sortBy = "created_at"
	}
	// Valider que sortBy est un champ valide
	validSortFields := map[string]bool{
		"created_at":    true,
		"username":      true,
		"email":         true,
		"last_login_at": true,
	}
	if !validSortFields[sortBy] {
		sortBy = "created_at"
	}

	sortOrder := params.SortOrder
	if sortOrder == "" {
		sortOrder = "desc"
	}
	if sortOrder != "asc" && sortOrder != "desc" {
		sortOrder = "desc"
	}

	query = query.Order(fmt.Sprintf("%s %s", sortBy, strings.ToUpper(sortOrder)))

	// Appliquer pagination et récupérer les résultats
	var users []*models.User
	if err := query.Offset(offset).Limit(params.Limit).Find(&users).Error; err != nil {
		return nil, 0, fmt.Errorf("failed to list users: %w", err)
	}

	// Exclure les mots de passe des résultats
	for _, user := range users {
		user.PasswordHash = ""
	}

	return users, total, nil
}
