package repositories

import (
	"context"
	"errors"

	"github.com/google/uuid"
	"veza-backend-api/internal/models"

	"gorm.io/gorm"
)

// PlaylistCollaboratorRepository définit l'interface pour les opérations sur les collaborateurs de playlists
type PlaylistCollaboratorRepository interface {
	// AddCollaborator ajoute un collaborateur à une playlist
	AddCollaborator(ctx context.Context, playlistID uuid.UUID, userID uuid.UUID, permission models.PlaylistPermission) (*models.PlaylistCollaborator, error)

	// RemoveCollaborator retire un collaborateur d'une playlist
	RemoveCollaborator(ctx context.Context, playlistID uuid.UUID, userID uuid.UUID) error

	// GetCollaborators récupère tous les collaborateurs d'une playlist
	GetCollaborators(ctx context.Context, playlistID uuid.UUID) ([]*models.PlaylistCollaborator, error)

	// GetCollaborator récupère un collaborateur spécifique
	GetCollaborator(ctx context.Context, playlistID uuid.UUID, userID uuid.UUID) (*models.PlaylistCollaborator, error)

	// UpdatePermission met à jour la permission d'un collaborateur
	UpdatePermission(ctx context.Context, playlistID uuid.UUID, userID uuid.UUID, permission models.PlaylistPermission) error

	// GetByUserID récupère toutes les playlists où un utilisateur est collaborateur
	GetByUserID(ctx context.Context, userID uuid.UUID) ([]*models.PlaylistCollaborator, error)

	// Exists vérifie si un collaborateur existe pour une playlist et un utilisateur
	Exists(ctx context.Context, playlistID uuid.UUID, userID uuid.UUID) (bool, error)
}

// playlistCollaboratorRepository implémente PlaylistCollaboratorRepository avec GORM
type playlistCollaboratorRepository struct {
	db *gorm.DB
}

// NewPlaylistCollaboratorRepository crée une nouvelle instance de PlaylistCollaboratorRepository
func NewPlaylistCollaboratorRepository(db *gorm.DB) PlaylistCollaboratorRepository {
	return &playlistCollaboratorRepository{
		db: db,
	}
}

// AddCollaborator ajoute un collaborateur à une playlist
// MIGRATION UUID: Completée. playlistID et userID sont des UUIDs.
func (r *playlistCollaboratorRepository) AddCollaborator(ctx context.Context, playlistID uuid.UUID, userID uuid.UUID, permission models.PlaylistPermission) (*models.PlaylistCollaborator, error) {
	// Valider la permission
	if !permission.IsValid() {
		return nil, errors.New("invalid permission")
	}

	// Vérifier si le collaborateur existe déjà
	exists, err := r.Exists(ctx, playlistID, userID)
	if err != nil {
		return nil, err
	}
	if exists {
		return nil, errors.New("collaborator already exists")
	}

	// Créer le collaborateur
	// FIXME: Assurer que le modèle PlaylistCollaborator utilise UUID
	collaborator := &models.PlaylistCollaborator{
		PlaylistID: playlistID,
		UserID:     userID,
		Permission: permission,
	}

	if err := r.db.WithContext(ctx).Create(collaborator).Error; err != nil {
		return nil, err
	}

	return collaborator, nil
}

// RemoveCollaborator retire un collaborateur d'une playlist
func (r *playlistCollaboratorRepository) RemoveCollaborator(ctx context.Context, playlistID uuid.UUID, userID uuid.UUID) error {
	result := r.db.WithContext(ctx).
		Where("playlist_id = ? AND user_id = ?", playlistID, userID).
		Delete(&models.PlaylistCollaborator{})

	if result.Error != nil {
		return result.Error
	}

	if result.RowsAffected == 0 {
		return gorm.ErrRecordNotFound
	}

	return nil
}

// GetCollaborators récupère tous les collaborateurs d'une playlist
func (r *playlistCollaboratorRepository) GetCollaborators(ctx context.Context, playlistID uuid.UUID) ([]*models.PlaylistCollaborator, error) {
	var collaborators []*models.PlaylistCollaborator

	if err := r.db.WithContext(ctx).
		Preload("User").
		Where("playlist_id = ?", playlistID).
		Find(&collaborators).Error; err != nil {
		return nil, err
	}

	return collaborators, nil
}

// GetCollaborator récupère un collaborateur spécifique
func (r *playlistCollaboratorRepository) GetCollaborator(ctx context.Context, playlistID uuid.UUID, userID uuid.UUID) (*models.PlaylistCollaborator, error) {
	var collaborator models.PlaylistCollaborator

	if err := r.db.WithContext(ctx).
		Preload("User").
		Where("playlist_id = ? AND user_id = ?", playlistID, userID).
		First(&collaborator).Error; err != nil {
		return nil, err
	}

	return &collaborator, nil
}

// UpdatePermission met à jour la permission d'un collaborateur
func (r *playlistCollaboratorRepository) UpdatePermission(ctx context.Context, playlistID uuid.UUID, userID uuid.UUID, permission models.PlaylistPermission) error {
	// Valider la permission
	if !permission.IsValid() {
		return errors.New("invalid permission")
	}

	result := r.db.WithContext(ctx).
		Model(&models.PlaylistCollaborator{}).
		Where("playlist_id = ? AND user_id = ?", playlistID, userID).
		Update("permission", permission)

	if result.Error != nil {
		return result.Error
	}

	if result.RowsAffected == 0 {
		return gorm.ErrRecordNotFound
	}

	return nil
}

// GetByUserID récupère toutes les playlists où un utilisateur est collaborateur
func (r *playlistCollaboratorRepository) GetByUserID(ctx context.Context, userID uuid.UUID) ([]*models.PlaylistCollaborator, error) {
	var collaborators []*models.PlaylistCollaborator

	if err := r.db.WithContext(ctx).
		Preload("Playlist").
		Where("user_id = ?", userID).
		Find(&collaborators).Error; err != nil {
		return nil, err
	}

	return collaborators, nil
}

// Exists vérifie si un collaborateur existe pour une playlist et un utilisateur
func (r *playlistCollaboratorRepository) Exists(ctx context.Context, playlistID uuid.UUID, userID uuid.UUID) (bool, error) {
	var count int64
	err := r.db.WithContext(ctx).
		Model(&models.PlaylistCollaborator{}).
		Where("playlist_id = ? AND user_id = ?", playlistID, userID).
		Count(&count).Error
	return count > 0, err
}
