package repositories

import (
	"testing"

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

// setupWebhookTestDB creates an in-memory SQLite database with the
// WebhookEvent table auto-migrated. This is separate from testutil.SetupTestDB
// because WebhookEvent lives in the repositories package (not models/) and
// only needs its own table for testing.
func setupWebhookTestDB(t *testing.T) *gorm.DB {
	t.Helper()
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Silent),
	})
	require.NoError(t, err)

	err = db.AutoMigrate(&WebhookEvent{})
	require.NoError(t, err)

	return db
}

func TestWebhookEventRepo_RecordAndCheck(t *testing.T) {
	db := setupWebhookTestDB(t)
	repo := NewWebhookEventRepository(db)

	// Record an event
	err := repo.RecordEvent("apple", "evt_001", "INITIAL_BUY", "abc123hash")
	require.NoError(t, err)

	// HasProcessed should return true for the same provider + event ID
	processed, err := repo.HasProcessed("apple", "evt_001")
	require.NoError(t, err)
	assert.True(t, processed, "expected HasProcessed to return true for a recorded event")

	// HasProcessed should return false for a different event ID
	processed, err = repo.HasProcessed("apple", "evt_999")
	require.NoError(t, err)
	assert.False(t, processed, "expected HasProcessed to return false for an unrecorded event ID")

	// HasProcessed should return false for a different provider
	processed, err = repo.HasProcessed("google", "evt_001")
	require.NoError(t, err)
	assert.False(t, processed, "expected HasProcessed to return false for a different provider")
}

func TestWebhookEventRepo_DuplicateInsert(t *testing.T) {
	db := setupWebhookTestDB(t)
	repo := NewWebhookEventRepository(db)

	// First insert should succeed
	err := repo.RecordEvent("apple", "evt_dup", "RENEWAL", "hash1")
	require.NoError(t, err)

	// Second insert with the same provider + event ID should fail (unique constraint)
	err = repo.RecordEvent("apple", "evt_dup", "RENEWAL", "hash1")
	require.Error(t, err, "expected an error when inserting a duplicate provider + event_id")

	// Verify only one row exists
	var count int64
	db.Model(&WebhookEvent{}).Where("provider = ? AND event_id = ?", "apple", "evt_dup").Count(&count)
	assert.Equal(t, int64(1), count, "expected exactly one row for the duplicated event")
}

func TestWebhookEventRepo_DifferentProviders(t *testing.T) {
	db := setupWebhookTestDB(t)
	repo := NewWebhookEventRepository(db)

	sharedEventID := "evt_shared_123"

	// Record event for "apple" provider
	err := repo.RecordEvent("apple", sharedEventID, "INITIAL_BUY", "applehash")
	require.NoError(t, err)

	// HasProcessed should return true for "apple"
	processed, err := repo.HasProcessed("apple", sharedEventID)
	require.NoError(t, err)
	assert.True(t, processed, "expected HasProcessed to return true for apple provider")

	// HasProcessed should return false for "google" with the same event ID
	processed, err = repo.HasProcessed("google", sharedEventID)
	require.NoError(t, err)
	assert.False(t, processed, "expected HasProcessed to return false for google provider with the same event ID")

	// Recording the same event ID under "google" should succeed (different provider)
	err = repo.RecordEvent("google", sharedEventID, "INITIAL_BUY", "googlehash")
	require.NoError(t, err)

	// Now both providers should show as processed
	processed, err = repo.HasProcessed("apple", sharedEventID)
	require.NoError(t, err)
	assert.True(t, processed, "expected apple to still be processed")

	processed, err = repo.HasProcessed("google", sharedEventID)
	require.NoError(t, err)
	assert.True(t, processed, "expected google to now be processed")
}
