package repositories

import (
	"context"
	"fmt"
	"time"

	"veza-backend-api/internal/models"

	"github.com/google/uuid"
	"gorm.io/gorm"
)

// UserRepository définit les méthodes pour interagir avec le modèle User
// (Cette interface est celle utilisée par les autres packages qui dépendent de ce repository)
// MIGRATION UUID: Toutes les méthodes utilisent maintenant uuid.UUID au lieu de int64
type UserRepository interface {
	CreateUser(ctx context.Context, user *models.User) error
	GetUserByID(ctx context.Context, id uuid.UUID) (*models.User, error)
	GetUserByEmail(ctx context.Context, email string) (*models.User, error)
	GetUserByUsername(ctx context.Context, username string) (*models.User, error)
	UpdateUser(ctx context.Context, user *models.User) error
	DeleteUser(ctx context.Context, id uuid.UUID) error
	UpdateLastLoginAt(ctx context.Context, userID uuid.UUID) error
	IncrementTokenVersion(ctx context.Context, userID uuid.UUID) error
}

// GormUserRepository est une implémentation de UserRepository utilisant GORM
type GormUserRepository struct {
	db *gorm.DB
}

// NewGormUserRepository crée une nouvelle instance de GormUserRepository
func NewGormUserRepository(db *gorm.DB) *GormUserRepository {
	return &GormUserRepository{db: db}
}

// CreateUser crée un nouvel utilisateur dans la base de données
func (r *GormUserRepository) CreateUser(ctx context.Context, user *models.User) error {
	return r.db.WithContext(ctx).Create(user).Error
}

// GetUserByID récupère un utilisateur par son ID
// MIGRATION UUID: Accepte maintenant uuid.UUID au lieu de int64
func (r *GormUserRepository) GetUserByID(ctx context.Context, id uuid.UUID) (*models.User, error) {
	var user models.User
	if err := r.db.WithContext(ctx).First(&user, "id = ?", id).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, nil // Utilisateur non trouvé
		}
		return nil, fmt.Errorf("failed to get user by ID: %w", err)
	}
	return &user, nil
}

// GetUserByEmail récupère un utilisateur par son email
func (r *GormUserRepository) GetUserByEmail(ctx context.Context, email string) (*models.User, error) {
	var user models.User
	if err := r.db.WithContext(ctx).Where("email = ?", email).First(&user).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, nil // Utilisateur non trouvé
		}
		return nil, fmt.Errorf("failed to get user by email: %w", err)
	}
	return &user, nil
}

// GetUserByUsername récupère un utilisateur par son nom d'utilisateur
func (r *GormUserRepository) GetUserByUsername(ctx context.Context, username string) (*models.User, error) {
	var user models.User
	if err := r.db.WithContext(ctx).Where("username = ?", username).First(&user).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, nil // Utilisateur non trouvé
		}
		return nil, fmt.Errorf("failed to get user by username: %w", err)
	}
	return &user, nil
}

// UpdateUser met à jour un utilisateur existant
func (r *GormUserRepository) UpdateUser(ctx context.Context, user *models.User) error {
	return r.db.WithContext(ctx).Save(user).Error
}

// DeleteUser supprime un utilisateur (soft delete si GORM est configuré pour ça)
// BE-DB-003: Add soft delete support to all models
// MIGRATION UUID: Accepte maintenant uuid.UUID au lieu de int64
func (r *GormUserRepository) DeleteUser(ctx context.Context, id uuid.UUID) error {
	return r.db.WithContext(ctx).Delete(&models.User{}, "id = ?", id).Error
}

// RestoreUser restaure un utilisateur supprimé (soft delete)
// BE-DB-003: Add soft delete support to all models
func (r *GormUserRepository) RestoreUser(ctx context.Context, id uuid.UUID) error {
	return r.db.WithContext(ctx).Unscoped().Model(&models.User{}).Where("id = ?", id).Update("deleted_at", nil).Error
}

// HardDeleteUser supprime définitivement un utilisateur (hard delete)
// BE-DB-003: Add soft delete support to all models
func (r *GormUserRepository) HardDeleteUser(ctx context.Context, id uuid.UUID) error {
	return r.db.WithContext(ctx).Unscoped().Delete(&models.User{}, "id = ?", id).Error
}

// UpdateLastLoginAt met à jour le champ last_login_at pour un utilisateur
// MIGRATION UUID: Accepte maintenant uuid.UUID au lieu de int64
func (r *GormUserRepository) UpdateLastLoginAt(ctx context.Context, userID uuid.UUID) error {
	return r.db.WithContext(ctx).Model(&models.User{}).Where("id = ?", userID).Update("last_login_at", time.Now()).Error
}

// IncrementTokenVersion incrémente la version du token d'un utilisateur
// MIGRATION UUID: Accepte maintenant uuid.UUID au lieu de int64
func (r *GormUserRepository) IncrementTokenVersion(ctx context.Context, userID uuid.UUID) error {
	return r.db.WithContext(ctx).Model(&models.User{}).Where("id = ?", userID).Update("token_version", gorm.Expr("token_version + ?", 1)).Error
}

// --- Compatibility methods for services.UserRepository interface ---
// MIGRATION UUID: Parse UUID string directement au lieu de int64

func (r *GormUserRepository) GetByID(id string) (*models.User, error) {
	// Parse UUID string directly (no longer parsing as int64)
	userID, err := uuid.Parse(id)
	if err != nil {
		return nil, fmt.Errorf("invalid user ID format (expected UUID): %w", err)
	}
	return r.GetUserByID(context.Background(), userID)
}

func (r *GormUserRepository) GetByEmail(email string) (*models.User, error) {
	return r.GetUserByEmail(context.Background(), email)
}

func (r *GormUserRepository) GetByUsername(username string) (*models.User, error) {
	return r.GetUserByUsername(context.Background(), username)
}

func (r *GormUserRepository) Create(user *models.User) error {
	return r.CreateUser(context.Background(), user)
}

func (r *GormUserRepository) Update(user *models.User) error {
	return r.UpdateUser(context.Background(), user)
}

func (r *GormUserRepository) Delete(id string) error {
	// Parse UUID string directly (no longer parsing as int64)
	userID, err := uuid.Parse(id)
	if err != nil {
		return fmt.Errorf("invalid user ID format (expected UUID): %w", err)
	}
	return r.DeleteUser(context.Background(), userID)
}
