package testutils

import (
	"fmt"
	"testing"

	"veza-backend-api/internal/models"

	"github.com/google/uuid"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestUserFactory(t *testing.T) {
	factory := NewUserFactory().
		WithUsername("admin").
		WithEmail("admin@example.com").
		WithRole("admin")

	user := factory.Build()

	assert.Equal(t, "admin", user.Username)
	assert.Equal(t, "admin@example.com", user.Email)
	assert.Equal(t, "admin", user.Role)
	assert.True(t, user.IsAdmin)
}

func TestUserFactory_WithCustomFields(t *testing.T) {
	factory := NewUserFactory().
		WithUsername("testuser").
		WithEmail("test@example.com").
		WithFirstName("John").
		WithLastName("Doe").
		WithIsActive(false).
		WithIsVerified(true)

	user := factory.Build()

	assert.Equal(t, "testuser", user.Username)
	assert.Equal(t, "test@example.com", user.Email)
	assert.Equal(t, "John", user.FirstName)
	assert.Equal(t, "Doe", user.LastName)
	assert.False(t, user.IsActive)
	assert.True(t, user.IsVerified)
}

func TestUserFactory_MustBuild(t *testing.T) {
	db := SetupTestDB()

	factory := NewUserFactory().
		WithUsername("mustbuild").
		WithEmail("mustbuild@example.com")

	user := factory.MustBuild(db)

	assert.NotEqual(t, uuid.Nil, user.ID)
	assert.Equal(t, "mustbuild", user.Username)
	assert.Equal(t, "mustbuild@example.com", user.Email)

	// Vérifier que l'utilisateur existe en DB
	var found models.User
	err := db.First(&found, "id = ?", user.ID).Error
	require.NoError(t, err)
	assert.Equal(t, user.Username, found.Username)
}

func TestTrackFactory(t *testing.T) {
	userID := uuid.New()
	factory := NewTrackFactory(userID).
		WithTitle("My Track").
		WithArtist("My Artist").
		WithDescription("A great track").
		WithDuration(240)

	track := factory.Build()

	assert.Equal(t, userID, track.UserID)
	assert.Equal(t, "My Track", track.Title)
	assert.Equal(t, "My Artist", track.Artist)
	assert.Equal(t, "A great track", track.Description)
	assert.Equal(t, 240, track.Duration)
}

func TestTrackFactory_MustBuild(t *testing.T) {
	db := SetupTestDB()

	// Créer un utilisateur créateur d'abord
	userFactory := NewUserFactory().WithUsername("creator")
	creator := userFactory.MustBuild(db)

	trackFactory := NewTrackFactory(creator.ID).
		WithTitle("Test Track").
		WithArtist("Test Artist")

	track := trackFactory.MustBuild(db)

	assert.NotZero(t, track.ID)
	assert.Equal(t, creator.ID, track.UserID)
	assert.Equal(t, "Test Track", track.Title)
}

func TestPlaylistFactory(t *testing.T) {
	userID := uuid.New()
	factory := NewPlaylistFactory(userID).
		WithName("My Playlist").
		WithDescription("A great playlist")

	playlist := factory.Build()

	assert.Equal(t, userID, playlist.UserID)
	assert.Equal(t, "My Playlist", playlist.Title)
	assert.Equal(t, "A great playlist", playlist.Description)
}

func TestPlaylistFactory_MustBuild(t *testing.T) {
	db := SetupTestDB()

	// Créer un utilisateur d'abord
	userFactory := NewUserFactory().WithUsername("playlist_owner")
	owner := userFactory.MustBuild(db)

	playlistFactory := NewPlaylistFactory(owner.ID).
		WithName("Test Playlist").
		WithDescription("Test Description")

	playlist := playlistFactory.MustBuild(db)

	assert.NotZero(t, playlist.ID)
	assert.Equal(t, owner.ID, playlist.UserID)
	assert.Equal(t, "Test Playlist", playlist.Title)
}

func TestCreateUsers(t *testing.T) {
	db := SetupTestDB()

	users := CreateUsers(db, 5)

	require.Len(t, users, 5)
	for i, user := range users {
		assert.NotEqual(t, uuid.Nil, user.ID)
		assert.Equal(t, fmt.Sprintf("user%d", i), user.Username)
		assert.Equal(t, fmt.Sprintf("user%d@example.com", i), user.Email)
	}
}

func TestCreateTracks(t *testing.T) {
	db := SetupTestDB()

	// Créer un utilisateur créateur d'abord
	userFactory := NewUserFactory().WithUsername("track_creator")
	creator := userFactory.MustBuild(db)

	tracks := CreateTracks(db, creator.ID, 3)

	require.Len(t, tracks, 3)
	for i, track := range tracks {
		assert.NotZero(t, track.ID)
		assert.Equal(t, creator.ID, track.UserID)
		assert.Equal(t, fmt.Sprintf("Test Track %d", i+1), track.Title)
		assert.Equal(t, fmt.Sprintf("Test Artist %d", i+1), track.Artist)
	}
}

func TestUserFactory_Defaults(t *testing.T) {
	factory := NewUserFactory()
	user := factory.Build()

	assert.Equal(t, "testuser", user.Username)
	assert.Equal(t, "test@example.com", user.Email)
	assert.Equal(t, "user", user.Role)
	assert.True(t, user.IsActive)
	assert.True(t, user.IsVerified)
	assert.False(t, user.IsAdmin)
}

func TestTrackFactory_Defaults(t *testing.T) {
	userID := uuid.New()
	factory := NewTrackFactory(userID)
	track := factory.Build()

	assert.Equal(t, userID, track.UserID)
	assert.Equal(t, "Test Track", track.Title)
	assert.Equal(t, "Test Artist", track.Artist)
	assert.Equal(t, "A test track", track.Description)
	assert.Equal(t, 180, track.Duration)
}

func TestPlaylistFactory_Defaults(t *testing.T) {
	userID := uuid.New()
	factory := NewPlaylistFactory(userID)
	playlist := factory.Build()

	assert.Equal(t, userID, playlist.UserID)
	assert.Equal(t, "Test Playlist", playlist.Title)
	assert.Equal(t, "A test playlist", playlist.Description)
}