package sql_test

import (
	"context"
	"testing"
	"tercul/internal/data/sql"
	"tercul/internal/domain"
	"tercul/internal/platform/config"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

// newTestCopyrightClaimRepoWithSQLite sets up an in-memory SQLite database for copyright claim repository testing.
func newTestCopyrightClaimRepoWithSQLite(t *testing.T) (domain.CopyrightClaimRepository, *gorm.DB) {
	db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
	require.NoError(t, err)

	// Auto-migrate the necessary schemas
	err = db.AutoMigrate(
		&domain.User{},
		&domain.Work{},
		&domain.CopyrightClaim{},
	)
	require.NoError(t, err)

	cfg := &config.Config{}
	repo := sql.NewCopyrightClaimRepository(db, cfg)

	// Clean up the database after the test
	t.Cleanup(func() {
		sqlDB, err := db.DB()
		require.NoError(t, err)
		err = sqlDB.Close()
		require.NoError(t, err)
	})

	return repo, db
}

func TestCopyrightClaimRepository_ListByWorkID(t *testing.T) {
	repo, db := newTestCopyrightClaimRepoWithSQLite(t)
	ctx := context.Background()

	// Setup: Create a user and a work
	user := domain.User{Username: "claimuser", Email: "claim@test.com"}
	require.NoError(t, db.Create(&user).Error)
	work1 := domain.Work{Title: "Work 1"}
	require.NoError(t, db.Create(&work1).Error)
	work2 := domain.Work{Title: "Work 2"}
	require.NoError(t, db.Create(&work2).Error)

	// Create some claims
	claim1 := domain.CopyrightClaim{UserID: &user.ID, WorkID: &work1.ID, Details: "Claim 1", ClaimDate: time.Now()}
	claim2 := domain.CopyrightClaim{UserID: &user.ID, WorkID: &work1.ID, Details: "Claim 2", ClaimDate: time.Now()}
	claim3 := domain.CopyrightClaim{UserID: &user.ID, WorkID: &work2.ID, Details: "Claim 3", ClaimDate: time.Now()}
	require.NoError(t, db.Create(&claim1).Error)
	require.NoError(t, db.Create(&claim2).Error)
	require.NoError(t, db.Create(&claim3).Error)

	t.Run("finds_claims_for_work1", func(t *testing.T) {
		claims, err := repo.ListByWorkID(ctx, work1.ID)
		require.NoError(t, err)
		assert.Len(t, claims, 2)
	})

	t.Run("finds_claims_for_work2", func(t *testing.T) {
		claims, err := repo.ListByWorkID(ctx, work2.ID)
		require.NoError(t, err)
		assert.Len(t, claims, 1)
		assert.Equal(t, "Claim 3", claims[0].Details)
	})

	t.Run("returns_empty_slice_for_no_claims", func(t *testing.T) {
		claims, err := repo.ListByWorkID(ctx, 999) // Non-existent work
		require.NoError(t, err)
		assert.Empty(t, claims)
	})
}

func TestCopyrightClaimRepository_ListByUserID(t *testing.T) {
	repo, db := newTestCopyrightClaimRepoWithSQLite(t)
	ctx := context.Background()

	// Setup: Create users and a work
	user1 := domain.User{Username: "user1", Email: "user1@test.com"}
	require.NoError(t, db.Create(&user1).Error)
	user2 := domain.User{Username: "user2", Email: "user2@test.com"}
	require.NoError(t, db.Create(&user2).Error)
	work := domain.Work{Title: "Test Work"}
	require.NoError(t, db.Create(&work).Error)

	// Create some claims
	claim1 := domain.CopyrightClaim{UserID: &user1.ID, WorkID: &work.ID, Details: "Claim 1", ClaimDate: time.Now()}
	claim2 := domain.CopyrightClaim{UserID: &user2.ID, WorkID: &work.ID, Details: "Claim 2", ClaimDate: time.Now()}
	claim3 := domain.CopyrightClaim{UserID: &user2.ID, WorkID: &work.ID, Details: "Claim 3", ClaimDate: time.Now()}
	require.NoError(t, db.Create(&claim1).Error)
	require.NoError(t, db.Create(&claim2).Error)
	require.NoError(t, db.Create(&claim3).Error)

	t.Run("finds_claims_for_user1", func(t *testing.T) {
		claims, err := repo.ListByUserID(ctx, user1.ID)
		require.NoError(t, err)
		assert.Len(t, claims, 1)
		assert.Equal(t, "Claim 1", claims[0].Details)
	})

	t.Run("finds_claims_for_user2", func(t *testing.T) {
		claims, err := repo.ListByUserID(ctx, user2.ID)
		require.NoError(t, err)
		assert.Len(t, claims, 2)
	})

	t.Run("returns_empty_slice_for_no_claims", func(t *testing.T) {
		claims, err := repo.ListByUserID(ctx, 999) // Non-existent user
		require.NoError(t, err)
		assert.Empty(t, claims)
	})
}