package services

import (
	"context"
	"testing"
	"time"

	"github.com/google/uuid"

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

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/zap"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

// setupTestPlaylistServiceDB crée une base de données de test en mémoire
func setupTestPlaylistServiceDB(t *testing.T) *gorm.DB {
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	require.NoError(t, err, "Failed to open test database")

	// Enable foreign keys for SQLite to ensure data integrity constraints
	db.Exec("PRAGMA foreign_keys = ON")

	// Auto-migrate tous les modèles nécessaires
	err = db.AutoMigrate(
		&models.User{},
		&models.Playlist{},
		&models.Track{},
		&models.PlaylistCollaborator{},
	)
	require.NoError(t, err, "Failed to migrate test database")

	// Drop and recreate playlist_tracks table manually to ensure all columns exist (AutoMigrate might miss some in SQLite)
	db.Exec(`DROP TABLE IF EXISTS playlist_tracks`)
	db.Exec(`
		CREATE TABLE playlist_tracks (
			id TEXT PRIMARY KEY,
			playlist_id TEXT NOT NULL,
			track_id TEXT NOT NULL,
			position INTEGER NOT NULL,
			added_by TEXT NOT NULL,
			added_at DATETIME DEFAULT CURRENT_TIMESTAMP,
			UNIQUE(playlist_id, track_id)
		)
	`)

	return db
}

// createTestUser crée un utilisateur de test
func createTestUserForService(t *testing.T, db *gorm.DB, username string) *models.User {
	user := &models.User{
		Username:     username,
		Slug:         username,
		Email:        username + "@example.com",
		PasswordHash: "hashed_password",
		IsActive:     true,
		CreatedAt:    time.Now(),
	}
	err := db.Create(user).Error
	require.NoError(t, err)
	return user
}

// createTestPlaylist crée une playlist de test
func createTestPlaylistForService(t *testing.T, db *gorm.DB, userID uuid.UUID) *models.Playlist {
	playlist := &models.Playlist{
		UserID:      userID,
		Title:       "Test Playlist",
		Description: "Test Description",
		IsPublic:    true,
		TrackCount:  0,
		CreatedAt:   time.Now(),
		UpdatedAt:   time.Now(),
	}
	err := db.Create(playlist).Error
	require.NoError(t, err)
	return playlist
}

// createTestTrackForService crée un track de test
func createTestTrackForService(t *testing.T, db *gorm.DB, userID uuid.UUID) *models.Track {
	track := &models.Track{
		UserID:    userID,
		Title:     "Test Track",
		FilePath:  "/tmp/test.mp3",
		Format:    "mp3",
		IsPublic:  true,
		CreatedAt: time.Now(),
	}
	err := db.Create(track).Error
	require.NoError(t, err)
	return track
}

func TestPlaylistService_CreatePlaylist(t *testing.T) {
	db := setupTestPlaylistServiceDB(t)
	playlistRepo := repositories.NewPlaylistRepository(db)
	playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
	playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
	userRepo := &gormUserRepository{db: db}
	logger := zap.NewNop()
	service := NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
	ctx := context.Background()

	user := createTestUserForService(t, db, "testuser")

	// Test creation
	playlist, err := service.CreatePlaylist(ctx, user.ID, "My Playlist", "Desc", true)
	assert.NoError(t, err)
	assert.NotNil(t, playlist)
	assert.Equal(t, "My Playlist", playlist.Title)
	assert.Equal(t, user.ID, playlist.UserID)

	// Test user not found
	_, err = service.CreatePlaylist(ctx, uuid.New(), "Title", "Desc", true)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "user not found")
}

func TestPlaylistService_AddTrackToPlaylist(t *testing.T) {
	db := setupTestPlaylistServiceDB(t)
	playlistRepo := repositories.NewPlaylistRepository(db)
	playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
	playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
	userRepo := &gormUserRepository{db: db}
	logger := zap.NewNop()
	service := NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
	ctx := context.Background()

	user := createTestUserForService(t, db, "testuser")
	playlist := createTestPlaylistForService(t, db, user.ID)
	track := createTestTrackForService(t, db, user.ID)

	// Add track
	err := service.AddTrackToPlaylist(ctx, playlist.ID, track.ID, user.ID, 0)
	assert.NoError(t, err)

	// Verify track added
	p, err := service.GetPlaylist(ctx, playlist.ID, &user.ID)
	assert.NoError(t, err)
	require.Len(t, p.Tracks, 1)
	assert.Equal(t, track.ID, p.Tracks[0].TrackID)

	// Test ownership (other user cannot add track)
	otherUser := createTestUserForService(t, db, "other")
	err = service.AddTrackToPlaylist(ctx, playlist.ID, track.ID, otherUser.ID, 0)
	assert.Error(t, err)
	assert.Equal(t, "forbidden", err.Error())
}

func TestPlaylistService_RemoveTrackFromPlaylist(t *testing.T) {
	db := setupTestPlaylistServiceDB(t)
	playlistRepo := repositories.NewPlaylistRepository(db)
	playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
	playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
	userRepo := &gormUserRepository{db: db}
	logger := zap.NewNop()
	service := NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
	ctx := context.Background()

	user := createTestUserForService(t, db, "testuser")
	playlist := createTestPlaylistForService(t, db, user.ID)
	track := createTestTrackForService(t, db, user.ID)

	// Add track first
	err := service.AddTrackToPlaylist(ctx, playlist.ID, track.ID, user.ID, 0)
	assert.NoError(t, err)

	// Remove track
	err = service.RemoveTrackFromPlaylist(ctx, playlist.ID, track.ID, user.ID)
	assert.NoError(t, err)

	// Verify removed
	p, err := service.GetPlaylist(ctx, playlist.ID, &user.ID)
	assert.NoError(t, err)
	assert.Len(t, p.Tracks, 0)
}

func TestPlaylistService_AddCollaborator(t *testing.T) {
	db := setupTestPlaylistServiceDB(t)
	playlistRepo := repositories.NewPlaylistRepository(db)
	playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
	playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
	userRepo := &gormUserRepository{db: db}
	logger := zap.NewNop()
	service := NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
	ctx := context.Background()

	owner := createTestUserForService(t, db, "owner")
	collaborator := createTestUserForService(t, db, "collaborator")
	playlist := createTestPlaylistForService(t, db, owner.ID)

	// Test AddCollaborator avec permission read
	collab, err := service.AddCollaborator(ctx, playlist.ID, owner.ID, collaborator.ID, models.PlaylistPermissionRead)
	assert.NoError(t, err)
	assert.NotNil(t, collab)
	assert.Equal(t, playlist.ID, collab.PlaylistID)
	assert.Equal(t, collaborator.ID, collab.UserID)
	assert.Equal(t, models.PlaylistPermissionRead, collab.Permission)

	// Test AddCollaborator avec permission write (créer un autre utilisateur)
	collaborator2 := createTestUserForService(t, db, "collaborator2")
	collab2, err := service.AddCollaborator(ctx, playlist.ID, owner.ID, collaborator2.ID, models.PlaylistPermissionWrite)
	assert.NoError(t, err)
	assert.Equal(t, models.PlaylistPermissionWrite, collab2.Permission)

	// Test AddCollaborator avec non-propriétaire (devrait échouer)
	otherUser := createTestUserForService(t, db, "other_user")
	_, err = service.AddCollaborator(ctx, playlist.ID, collaborator.ID, otherUser.ID, models.PlaylistPermissionRead)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "forbidden")

	// Test AddCollaborator avec le propriétaire lui-même (devrait échouer)
	_, err = service.AddCollaborator(ctx, playlist.ID, owner.ID, owner.ID, models.PlaylistPermissionRead)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "cannot add playlist owner")

	// Test AddCollaborator avec playlist inexistante
	_, err = service.AddCollaborator(ctx, uuid.New(), owner.ID, collaborator.ID, models.PlaylistPermissionRead)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "playlist not found")

	// Test AddCollaborator avec utilisateur inexistant
	_, err = service.AddCollaborator(ctx, playlist.ID, owner.ID, uuid.New(), models.PlaylistPermissionRead)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "user not found")
}

func TestPlaylistService_RemoveCollaborator(t *testing.T) {
	db := setupTestPlaylistServiceDB(t)
	playlistRepo := repositories.NewPlaylistRepository(db)
	playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
	playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
	userRepo := &gormUserRepository{db: db}
	logger := zap.NewNop()
	service := NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
	ctx := context.Background()

	owner := createTestUserForService(t, db, "owner")
	collaborator := createTestUserForService(t, db, "collaborator")
	playlist := createTestPlaylistForService(t, db, owner.ID)

	// Ajouter un collaborateur
	_, err := service.AddCollaborator(ctx, playlist.ID, owner.ID, collaborator.ID, models.PlaylistPermissionRead)
	assert.NoError(t, err)

	// Retirer le collaborateur
	err = service.RemoveCollaborator(ctx, playlist.ID, owner.ID, collaborator.ID)
	assert.NoError(t, err)

	// Vérifier qu'il n'existe plus
	exists, err := playlistCollaboratorRepo.Exists(ctx, playlist.ID, collaborator.ID)
	assert.NoError(t, err)
	assert.False(t, exists)

	// Test RemoveCollaborator avec non-propriétaire (devrait échouer)
	err = service.RemoveCollaborator(ctx, playlist.ID, collaborator.ID, owner.ID)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "forbidden")

	// Test RemoveCollaborator avec collaborateur inexistant
	err = service.RemoveCollaborator(ctx, playlist.ID, owner.ID, uuid.New())
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "collaborator not found")
}

func TestPlaylistService_UpdatePlaylist(t *testing.T) {
	db := setupTestPlaylistServiceDB(t)
	playlistRepo := repositories.NewPlaylistRepository(db)
	playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
	playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
	userRepo := &gormUserRepository{db: db}
	logger := zap.NewNop()
	service := NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
	ctx := context.Background()

	owner := createTestUserForService(t, db, "owner")
	otherUser := createTestUserForService(t, db, "other")
	playlist := createTestPlaylistForService(t, db, owner.ID)

	// Test Update
	newTitle := "Updated Title"
	newDesc := "Updated Desc"
	isPublic := false
	updated, err := service.UpdatePlaylist(ctx, playlist.ID, owner.ID, &newTitle, &newDesc, &isPublic)
	assert.NoError(t, err)
	assert.Equal(t, "Updated Title", updated.Title)
	assert.Equal(t, "Updated Desc", updated.Description)
	assert.False(t, updated.IsPublic)

	// Test Forbidden
	_, err = service.UpdatePlaylist(ctx, playlist.ID, otherUser.ID, &newTitle, nil, nil)
	assert.ErrorIs(t, err, ErrAccessDenied)

	// Test NotFound
	_, err = service.UpdatePlaylist(ctx, uuid.New(), owner.ID, &newTitle, nil, nil)
	assert.ErrorIs(t, err, ErrPlaylistNotFound)
}

func TestPlaylistService_DeletePlaylist(t *testing.T) {
	db := setupTestPlaylistServiceDB(t)
	playlistRepo := repositories.NewPlaylistRepository(db)
	playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
	playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
	userRepo := &gormUserRepository{db: db}
	logger := zap.NewNop()
	service := NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
	ctx := context.Background()

	owner := createTestUserForService(t, db, "owner")
	otherUser := createTestUserForService(t, db, "other")
	playlist := createTestPlaylistForService(t, db, owner.ID)

	// Test Forbidden
	err := service.DeletePlaylist(ctx, playlist.ID, otherUser.ID)
	assert.ErrorIs(t, err, ErrAccessDenied)

	// Test Success
	err = service.DeletePlaylist(ctx, playlist.ID, owner.ID)
	assert.NoError(t, err)

	// Verify deletion
	_, err = playlistRepo.GetByID(ctx, playlist.ID)
	assert.ErrorIs(t, err, gorm.ErrRecordNotFound)
}

func TestPlaylistService_ReorderPlaylistTracks(t *testing.T) {
	db := setupTestPlaylistServiceDB(t)
	playlistRepo := repositories.NewPlaylistRepository(db)
	playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
	playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
	userRepo := &gormUserRepository{db: db}
	logger := zap.NewNop()
	service := NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
	ctx := context.Background()

	owner := createTestUserForService(t, db, "owner")
	playlist := createTestPlaylistForService(t, db, owner.ID)
	track1 := createTestTrackForService(t, db, owner.ID)
	track2 := createTestTrackForService(t, db, owner.ID)

	// Add tracks
	service.AddTrackToPlaylist(ctx, playlist.ID, track1.ID, owner.ID, 1)
	service.AddTrackToPlaylist(ctx, playlist.ID, track2.ID, owner.ID, 2)

	// Reorder
	positions := map[uuid.UUID]int{
		track1.ID: 2,
		track2.ID: 1,
	}
	err := service.ReorderPlaylistTracks(ctx, playlist.ID, owner.ID, positions)
	assert.NoError(t, err)

	// Verify order via GetPlaylist (assuming it returns ordered tracks)
	p, err := service.GetPlaylist(ctx, playlist.ID, &owner.ID)
	assert.NoError(t, err)
	require.Len(t, p.Tracks, 2)
	assert.Equal(t, track2.ID, p.Tracks[0].TrackID) // Position 1
	assert.Equal(t, track1.ID, p.Tracks[1].TrackID) // Position 2
}

func TestPlaylistService_GetPlaylists(t *testing.T) {
	db := setupTestPlaylistServiceDB(t)
	playlistRepo := repositories.NewPlaylistRepository(db)
	playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
	playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
	userRepo := &gormUserRepository{db: db}
	logger := zap.NewNop()
	service := NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
	ctx := context.Background()

	owner := createTestUserForService(t, db, "owner")
	other := createTestUserForService(t, db, "other")

	// Helper to create playlist
	create := func(user *models.User, title string, public bool) *models.Playlist {
		p := &models.Playlist{
			UserID:   user.ID,
			Title:    title,
			IsPublic: public,
		}
		db.Create(p)
		return p
	}

	create(owner, "Public 1", true)
	create(owner, "Private 1", false)
	create(other, "Public 2", true)

	// Test List for Anonymous (Public only)
	list, total, err := service.GetPlaylists(ctx, nil, nil, 1, 10)
	assert.NoError(t, err)
	assert.Equal(t, int64(2), total)
	assert.Len(t, list, 2)

	// Test List for Owner (Own Private + Public)
	list, total, err = service.GetPlaylists(ctx, &owner.ID, nil, 1, 10)
	assert.NoError(t, err)
	// Theoretically 2 public + 1 private = 3?
	// Logic says: if currentUserID != nil, isPublic = nil, viewerID = currentUserID
	// Repository should return visible playlists.
	// Owner sees: Public 1, Private 1, Public 2 (if repo handles public OR owned)
	// Assuming repo works correctly.
	// If repo logic is (is_public OR user_id = viewer), then 3.
	assert.Equal(t, int64(3), total)

	// Test Filter User
	list, total, err = service.GetPlaylists(ctx, nil, &owner.ID, 1, 10)
	assert.NoError(t, err)
	assert.Equal(t, int64(1), total) // Only Public 1
}

func TestPlaylistService_SearchPlaylists(t *testing.T) {
	db := setupTestPlaylistServiceDB(t)
	playlistRepo := repositories.NewPlaylistRepository(db)
	playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
	playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
	userRepo := &gormUserRepository{db: db}
	logger := zap.NewNop()
	service := NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
	ctx := context.Background()

	owner := createTestUserForService(t, db, "search_owner")

	p1 := &models.Playlist{UserID: owner.ID, Title: "Techno Vibes", IsPublic: true}
	db.Create(p1)
	p2 := &models.Playlist{UserID: owner.ID, Title: "Jazz Classics", IsPublic: true}
	db.Create(p2)

	params := SearchPlaylistsParams{
		Query: "Techno",
		Page:  1,
		Limit: 10,
	}
	results, total, err := service.SearchPlaylists(ctx, params)
	assert.NoError(t, err)
	assert.Equal(t, int64(1), total)
	assert.Equal(t, "Techno Vibes", results[0].Title)
}

func TestPlaylistService_UpdateCollaboratorPermission(t *testing.T) {
	db := setupTestPlaylistServiceDB(t)
	playlistRepo := repositories.NewPlaylistRepository(db)
	playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
	playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
	userRepo := &gormUserRepository{db: db}
	logger := zap.NewNop()
	service := NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
	ctx := context.Background()

	owner := createTestUserForService(t, db, "owner")
	collaborator := createTestUserForService(t, db, "collaborator")
	playlist := createTestPlaylistForService(t, db, owner.ID)

	// Ajouter un collaborateur avec permission read
	_, err := service.AddCollaborator(ctx, playlist.ID, owner.ID, collaborator.ID, models.PlaylistPermissionRead)
	assert.NoError(t, err)

	// Mettre à jour la permission à write
	err = service.UpdateCollaboratorPermission(ctx, playlist.ID, owner.ID, collaborator.ID, models.PlaylistPermissionWrite)
	assert.NoError(t, err)

	// Vérifier la mise à jour
	collab, err := playlistCollaboratorRepo.GetCollaborator(ctx, playlist.ID, collaborator.ID)
	assert.NoError(t, err)
	assert.Equal(t, models.PlaylistPermissionWrite, collab.Permission)

	// Mettre à jour la permission à admin
	err = service.UpdateCollaboratorPermission(ctx, playlist.ID, owner.ID, collaborator.ID, models.PlaylistPermissionAdmin)
	assert.NoError(t, err)

	// Vérifier la mise à jour
	collab, err = playlistCollaboratorRepo.GetCollaborator(ctx, playlist.ID, collaborator.ID)
	assert.NoError(t, err)
	assert.Equal(t, models.PlaylistPermissionAdmin, collab.Permission)

	// Test UpdateCollaboratorPermission avec non-propriétaire (devrait échouer)
	err = service.UpdateCollaboratorPermission(ctx, playlist.ID, collaborator.ID, owner.ID, models.PlaylistPermissionRead)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "forbidden")

	// Test UpdateCollaboratorPermission avec permission invalide
	err = service.UpdateCollaboratorPermission(ctx, playlist.ID, owner.ID, collaborator.ID, models.PlaylistPermission("invalid"))
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "invalid permission")

	// Test UpdateCollaboratorPermission avec collaborateur inexistant
	err = service.UpdateCollaboratorPermission(ctx, playlist.ID, owner.ID, uuid.New(), models.PlaylistPermissionRead)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "collaborator not found")
}

func TestPlaylistService_CheckPermission(t *testing.T) {
	db := setupTestPlaylistServiceDB(t)
	playlistRepo := repositories.NewPlaylistRepository(db)
	playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
	playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
	userRepo := &gormUserRepository{db: db}
	logger := zap.NewNop()
	service := NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
	ctx := context.Background()

	owner := createTestUserForService(t, db, "owner")
	collaboratorRead := createTestUserForService(t, db, "collaborator_read")
	collaboratorWrite := createTestUserForService(t, db, "collaborator_write")
	collaboratorAdmin := createTestUserForService(t, db, "collaborator_admin")
	otherUser := createTestUserForService(t, db, "other_user")
	playlist := createTestPlaylistForService(t, db, owner.ID)

	// Le propriétaire a toujours toutes les permissions
	hasPermission, err := service.CheckPermission(ctx, playlist.ID, owner.ID, models.PlaylistPermissionRead)
	assert.NoError(t, err)
	assert.True(t, hasPermission)

	hasPermission, err = service.CheckPermission(ctx, playlist.ID, owner.ID, models.PlaylistPermissionWrite)
	assert.NoError(t, err)
	assert.True(t, hasPermission)

	hasPermission, err = service.CheckPermission(ctx, playlist.ID, owner.ID, models.PlaylistPermissionAdmin)
	assert.NoError(t, err)
	assert.True(t, hasPermission)

	// Pour une playlist publique, tout le monde peut lire
	hasPermission, err = service.CheckPermission(ctx, playlist.ID, otherUser.ID, models.PlaylistPermissionRead)
	assert.NoError(t, err)
	assert.True(t, hasPermission)

	// Mais pas écrire
	hasPermission, err = service.CheckPermission(ctx, playlist.ID, otherUser.ID, models.PlaylistPermissionWrite)
	assert.NoError(t, err)
	assert.False(t, hasPermission)

	// Ajouter des collaborateurs avec différentes permissions
	_, err = service.AddCollaborator(ctx, playlist.ID, owner.ID, collaboratorRead.ID, models.PlaylistPermissionRead)
	assert.NoError(t, err)

	_, err = service.AddCollaborator(ctx, playlist.ID, owner.ID, collaboratorWrite.ID, models.PlaylistPermissionWrite)
	assert.NoError(t, err)

	_, err = service.AddCollaborator(ctx, playlist.ID, owner.ID, collaboratorAdmin.ID, models.PlaylistPermissionAdmin)
	assert.NoError(t, err)

	// Vérifier les permissions du collaborateur read
	hasPermission, err = service.CheckPermission(ctx, playlist.ID, collaboratorRead.ID, models.PlaylistPermissionRead)
	assert.NoError(t, err)
	assert.True(t, hasPermission)

	hasPermission, err = service.CheckPermission(ctx, playlist.ID, collaboratorRead.ID, models.PlaylistPermissionWrite)
	assert.NoError(t, err)
	assert.False(t, hasPermission)

	hasPermission, err = service.CheckPermission(ctx, playlist.ID, collaboratorRead.ID, models.PlaylistPermissionAdmin)
	assert.NoError(t, err)
	assert.False(t, hasPermission)

	// Vérifier les permissions du collaborateur write
	hasPermission, err = service.CheckPermission(ctx, playlist.ID, collaboratorWrite.ID, models.PlaylistPermissionRead)
	assert.NoError(t, err)
	assert.True(t, hasPermission)

	hasPermission, err = service.CheckPermission(ctx, playlist.ID, collaboratorWrite.ID, models.PlaylistPermissionWrite)
	assert.NoError(t, err)
	assert.True(t, hasPermission)

	hasPermission, err = service.CheckPermission(ctx, playlist.ID, collaboratorWrite.ID, models.PlaylistPermissionAdmin)
	assert.NoError(t, err)
	assert.False(t, hasPermission)

	// Vérifier les permissions du collaborateur admin
	hasPermission, err = service.CheckPermission(ctx, playlist.ID, collaboratorAdmin.ID, models.PlaylistPermissionRead)
	assert.NoError(t, err)
	assert.True(t, hasPermission)

	hasPermission, err = service.CheckPermission(ctx, playlist.ID, collaboratorAdmin.ID, models.PlaylistPermissionWrite)
	assert.NoError(t, err)
	assert.True(t, hasPermission)

	hasPermission, err = service.CheckPermission(ctx, playlist.ID, collaboratorAdmin.ID, models.PlaylistPermissionAdmin)
	assert.NoError(t, err)
	assert.True(t, hasPermission)

	// Test avec playlist privée
	privatePlaylist := createTestPlaylistForService(t, db, owner.ID)
	privatePlaylist.IsPublic = false
	err = db.Save(privatePlaylist).Error
	assert.NoError(t, err)

	// Un utilisateur non collaborateur ne peut pas lire une playlist privée
	hasPermission, err = service.CheckPermission(ctx, privatePlaylist.ID, otherUser.ID, models.PlaylistPermissionRead)
	assert.NoError(t, err)
	assert.False(t, hasPermission)

	// Test avec playlist inexistante
	_, err = service.CheckPermission(ctx, uuid.New(), owner.ID, models.PlaylistPermissionRead)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "playlist not found")
}

func TestPlaylistService_GetCollaborators(t *testing.T) {
	db := setupTestPlaylistServiceDB(t)
	playlistRepo := repositories.NewPlaylistRepository(db)
	playlistTrackRepo := repositories.NewPlaylistTrackRepository(db)
	playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(db)
	userRepo := &gormUserRepository{db: db}
	logger := zap.NewNop()
	service := NewPlaylistService(playlistRepo, playlistTrackRepo, playlistCollaboratorRepo, userRepo, logger)
	ctx := context.Background()

	owner := createTestUserForService(t, db, "owner")
	collaborator1 := createTestUserForService(t, db, "collaborator1")
	collaborator2 := createTestUserForService(t, db, "collaborator2")
	otherUser := createTestUserForService(t, db, "other_user")
	playlist := createTestPlaylistForService(t, db, owner.ID)

	// Ajouter des collaborateurs
	_, err := service.AddCollaborator(ctx, playlist.ID, owner.ID, collaborator1.ID, models.PlaylistPermissionRead)
	assert.NoError(t, err)

	_, err = service.AddCollaborator(ctx, playlist.ID, owner.ID, collaborator2.ID, models.PlaylistPermissionWrite)
	assert.NoError(t, err)

	// Le propriétaire peut récupérer les collaborateurs
	collaborators, err := service.GetCollaborators(ctx, playlist.ID, owner.ID)
	assert.NoError(t, err)
	assert.Len(t, collaborators, 2)

	// Un collaborateur peut récupérer les collaborateurs
	collaborators, err = service.GetCollaborators(ctx, playlist.ID, collaborator1.ID)
	assert.NoError(t, err)
	assert.Len(t, collaborators, 2)

	// Un utilisateur non collaborateur peut récupérer les collaborateurs d'une playlist publique
	collaborators, err = service.GetCollaborators(ctx, playlist.ID, otherUser.ID)
	assert.NoError(t, err)
	assert.Len(t, collaborators, 2)

	// Test avec playlist privée
	privatePlaylist := createTestPlaylistForService(t, db, owner.ID)
	privatePlaylist.IsPublic = false
	err = db.Save(privatePlaylist).Error
	assert.NoError(t, err)

	// Un utilisateur non collaborateur ne peut pas récupérer les collaborateurs d'une playlist privée
	_, err = service.GetCollaborators(ctx, privatePlaylist.ID, otherUser.ID)
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "forbidden")
}
