package services

import (
	"context"
	"encoding/json"
	"testing"
	"time"

	"veza-backend-api/internal/models"

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

func setupTestDB(t *testing.T) *gorm.DB {
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	require.NoError(t, err)

	// Migrate tables
	err = db.AutoMigrate(
		&models.User{},
		&models.UserSettings{},
		&models.Track{},
		&models.Playlist{},
		&models.TrackComment{},
		&models.TrackLike{},
		&models.PlaybackAnalytics{},
		&models.FederatedIdentity{},
		&models.UserRole{},
	)
	require.NoError(t, err)

	return db
}

func TestDataExportService_ExportUserData(t *testing.T) {
	db := setupTestDB(t)
	logger, _ := zap.NewDevelopment()
	service := NewDataExportService(db, logger)

	// Create test user
	userID := uuid.New()
	user := &models.User{
		ID:        userID,
		Username:  "testuser",
		Email:     "test@example.com",
		FirstName: "Test",
		LastName:  "User",
		IsActive:  true,
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	}
	require.NoError(t, db.Create(user).Error)

	// Create user settings
	settings := &models.UserSettings{
		ID:                 uuid.New(),
		UserID:             userID,
		EmailNotifications: true,
		CreatedAt:          time.Now(),
		UpdatedAt:          time.Now(),
	}
	require.NoError(t, db.Create(settings).Error)

	// Create test track
	track := &models.Track{
		ID:        uuid.New(),
		UserID:    userID,
		Title:     "Test Track",
		Duration:  180,
		FilePath:  "/path/to/track.mp3",
		IsPublic:  true,
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	}
	require.NoError(t, db.Create(track).Error)

	// Export user data
	ctx := context.Background()
	export, err := service.ExportUserData(ctx, userID)
	require.NoError(t, err)

	// Verify export structure
	assert.Equal(t, userID, export.UserID)
	assert.NotNil(t, export.Profile)
	assert.Equal(t, user.Username, export.Profile.Username)
	assert.Equal(t, user.Email, export.Profile.Email)
	assert.NotNil(t, export.Settings)
	assert.Equal(t, 1, len(export.Tracks))
	assert.Equal(t, track.Title, export.Tracks[0].Title)
}

func TestDataExportService_ExportUserDataAsJSON(t *testing.T) {
	db := setupTestDB(t)
	logger, _ := zap.NewDevelopment()
	service := NewDataExportService(db, logger)

	// Create test user
	userID := uuid.New()
	user := &models.User{
		ID:        userID,
		Username:  "testuser",
		Email:     "test@example.com",
		IsActive:  true,
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	}
	require.NoError(t, db.Create(user).Error)

	// Export as JSON
	ctx := context.Background()
	jsonData, err := service.ExportUserDataAsJSON(ctx, userID)
	require.NoError(t, err)

	// Verify JSON is valid
	var export UserDataExport
	err = json.Unmarshal(jsonData, &export)
	require.NoError(t, err)
	assert.Equal(t, userID, export.UserID)
	assert.NotNil(t, export.Profile)
}

func TestDataExportService_ExportUserData_NoData(t *testing.T) {
	db := setupTestDB(t)
	logger, _ := zap.NewDevelopment()
	service := NewDataExportService(db, logger)

	// Create test user without any related data
	userID := uuid.New()
	user := &models.User{
		ID:        userID,
		Username:  "testuser",
		Email:     "test@example.com",
		IsActive:  true,
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
	}
	require.NoError(t, db.Create(user).Error)

	// Export user data
	ctx := context.Background()
	export, err := service.ExportUserData(ctx, userID)
	require.NoError(t, err)

	// Verify export structure even with no related data
	assert.Equal(t, userID, export.UserID)
	assert.NotNil(t, export.Profile)
	assert.Equal(t, 0, len(export.Tracks))
	assert.Equal(t, 0, len(export.Playlists))
	assert.Equal(t, 0, len(export.Comments))
	assert.Equal(t, 0, len(export.Likes))
}

func TestDataExportService_ExportUserData_UserNotFound(t *testing.T) {
	db := setupTestDB(t)
	logger, _ := zap.NewDevelopment()
	service := NewDataExportService(db, logger)

	// Try to export non-existent user
	ctx := context.Background()
	nonExistentID := uuid.New()
	_, err := service.ExportUserData(ctx, nonExistentID)
	assert.Error(t, err)
}
