package services

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"go.uber.org/zap"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"veza-backend-api/internal/models"
)

func setupTestTrackServiceForQuota(t *testing.T) (*TrackService, *gorm.DB, func()) {
	// Setup in-memory SQLite database
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	assert.NoError(t, err)

	// Auto-migrate
	err = db.AutoMigrate(&models.Track{}, &models.User{})
	assert.NoError(t, err)

	// Create test user
	user := &models.User{
		ID:       123,
		Username: "testuser",
		Email:    "test@example.com",
		IsActive: true,
	}
	err = db.Create(user).Error
	assert.NoError(t, err)

	// Setup logger
	logger := zap.NewNop()

	// Setup test service
	service := NewTrackService(db, logger, "test_uploads/tracks")

	// Cleanup function
	cleanup := func() {
		// Database will be closed automatically
	}

	return service, db, cleanup
}

func TestTrackService_GetUserQuota_Success(t *testing.T) {
	service, db, cleanup := setupTestTrackServiceForQuota(t)
	defer cleanup()

	ctx := context.Background()

	// Créer quelques tracks pour l'utilisateur
	track1 := &models.Track{
		UserID:   123,
		Title:    "Track 1",
		FilePath: "/test/track1.mp3",
		FileSize: 5 * 1024 * 1024, // 5MB
		Format:   "MP3",
		Duration: 180,
		IsPublic: true,
	}
	err := db.Create(track1).Error
	assert.NoError(t, err)

	track2 := &models.Track{
		UserID:   123,
		Title:    "Track 2",
		FilePath: "/test/track2.mp3",
		FileSize: 10 * 1024 * 1024, // 10MB
		Format:   "MP3",
		Duration: 200,
		IsPublic: true,
	}
	err = db.Create(track2).Error
	assert.NoError(t, err)

	// Récupérer le quota
	quota, err := service.GetUserQuota(ctx, 123)
	assert.NoError(t, err)
	assert.NotNil(t, quota)
	assert.Equal(t, int64(2), quota.TracksCount)
	assert.Equal(t, MaxTracksPerUser, quota.TracksLimit)
	assert.Equal(t, int64(15*1024*1024), quota.StorageUsed) // 15MB
	assert.Equal(t, MaxStoragePerUser, quota.StorageLimit)
}

func TestTrackService_GetUserQuota_Empty(t *testing.T) {
	service, _, cleanup := setupTestTrackServiceForQuota(t)
	defer cleanup()

	ctx := context.Background()

	// Récupérer le quota pour un utilisateur sans tracks
	quota, err := service.GetUserQuota(ctx, 123)
	assert.NoError(t, err)
	assert.NotNil(t, quota)
	assert.Equal(t, int64(0), quota.TracksCount)
	assert.Equal(t, MaxTracksPerUser, quota.TracksLimit)
	assert.Equal(t, int64(0), quota.StorageUsed)
	assert.Equal(t, MaxStoragePerUser, quota.StorageLimit)
}

func TestTrackService_GetUserQuota_UserNotFound(t *testing.T) {
	service, _, cleanup := setupTestTrackServiceForQuota(t)
	defer cleanup()

	ctx := context.Background()

	// Récupérer le quota pour un utilisateur qui n'existe pas
	quota, err := service.GetUserQuota(ctx, 999)
	assert.NoError(t, err) // Devrait retourner 0 tracks et 0 storage
	assert.NotNil(t, quota)
	assert.Equal(t, int64(0), quota.TracksCount)
	assert.Equal(t, int64(0), quota.StorageUsed)
}

func TestTrackService_GetUserQuota_MultipleUsers(t *testing.T) {
	service, db, cleanup := setupTestTrackServiceForQuota(t)
	defer cleanup()

	ctx := context.Background()

	// Créer un deuxième utilisateur
	user2 := &models.User{
		ID:       456,
		Username: "testuser2",
		Email:    "test2@example.com",
		IsActive: true,
	}
	err := db.Create(user2).Error
	assert.NoError(t, err)

	// Créer des tracks pour les deux utilisateurs
	track1 := &models.Track{
		UserID:   123,
		Title:    "User1 Track",
		FilePath: "/test/track1.mp3",
		FileSize: 5 * 1024 * 1024,
		Format:   "MP3",
		IsPublic: true,
	}
	err = db.Create(track1).Error
	assert.NoError(t, err)

	track2 := &models.Track{
		UserID:   456,
		Title:    "User2 Track",
		FilePath: "/test/track2.mp3",
		FileSize: 10 * 1024 * 1024,
		Format:   "MP3",
		IsPublic: true,
	}
	err = db.Create(track2).Error
	assert.NoError(t, err)

	// Vérifier que les quotas sont isolés
	quota1, err := service.GetUserQuota(ctx, 123)
	assert.NoError(t, err)
	assert.Equal(t, int64(1), quota1.TracksCount)
	assert.Equal(t, int64(5*1024*1024), quota1.StorageUsed)

	quota2, err := service.GetUserQuota(ctx, 456)
	assert.NoError(t, err)
	assert.Equal(t, int64(1), quota2.TracksCount)
	assert.Equal(t, int64(10*1024*1024), quota2.StorageUsed)
}

