package services

import (
	"context"
	"testing"

	"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 setupWebhookTestDB(t *testing.T) *gorm.DB {
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	require.NoError(t, err)

	// Migrate tables
	err = db.AutoMigrate(&models.Webhook{})
	require.NoError(t, err)

	return db
}

func TestWebhookService_GenerateAPIKey(t *testing.T) {
	db := setupWebhookTestDB(t)
	logger, _ := zap.NewDevelopment()
	service := NewWebhookService(db, logger, "test-secret")

	// Générer plusieurs clés et vérifier qu'elles sont uniques
	keys := make(map[string]bool)
	for i := 0; i < 10; i++ {
		key, err := service.GenerateAPIKey()
		require.NoError(t, err)
		assert.True(t, len(key) > 0)
		assert.True(t, len(key) <= 64) // Vérifier la longueur max
		assert.True(t, !keys[key], "Generated duplicate key")
		keys[key] = true
		assert.Contains(t, key, "whk_", "API key should have whk_ prefix")
	}
}

func TestWebhookService_RegisterWebhook_WithAPIKey(t *testing.T) {
	db := setupWebhookTestDB(t)
	logger, _ := zap.NewDevelopment()
	service := NewWebhookService(db, logger, "test-secret")

	userID := uuid.New()
	ctx := context.Background()

	webhook, err := service.RegisterWebhook(ctx, userID, "https://example.com/webhook", []string{"track.created"})
	require.NoError(t, err)
	assert.NotNil(t, webhook)
	assert.NotEmpty(t, webhook.APIKey)
	assert.Contains(t, webhook.APIKey, "whk_")
}

func TestWebhookService_ValidateAPIKey(t *testing.T) {
	db := setupWebhookTestDB(t)
	logger, _ := zap.NewDevelopment()
	service := NewWebhookService(db, logger, "test-secret")

	userID := uuid.New()
	ctx := context.Background()

	// Créer un webhook
	webhook, err := service.RegisterWebhook(ctx, userID, "https://example.com/webhook", []string{"track.created"})
	require.NoError(t, err)

	// Valider la clé API
	validatedWebhook, err := service.ValidateAPIKey(ctx, webhook.APIKey)
	require.NoError(t, err)
	assert.Equal(t, webhook.ID, validatedWebhook.ID)
	assert.Equal(t, webhook.UserID, validatedWebhook.UserID)

	// Tester avec une clé invalide
	_, err = service.ValidateAPIKey(ctx, "whk_invalid_key")
	assert.Error(t, err)

	// Tester avec un format invalide (sans préfixe)
	_, err = service.ValidateAPIKey(ctx, "invalid_key")
	assert.Error(t, err)
}

func TestWebhookService_RegenerateAPIKey(t *testing.T) {
	db := setupWebhookTestDB(t)
	logger, _ := zap.NewDevelopment()
	service := NewWebhookService(db, logger, "test-secret")

	userID := uuid.New()
	ctx := context.Background()

	// Créer un webhook
	webhook, err := service.RegisterWebhook(ctx, userID, "https://example.com/webhook", []string{"track.created"})
	require.NoError(t, err)
	oldAPIKey := webhook.APIKey

	// Régénérer la clé API
	newAPIKey, err := service.RegenerateAPIKey(ctx, webhook.ID, userID)
	require.NoError(t, err)
	assert.NotEqual(t, oldAPIKey, newAPIKey)
	assert.Contains(t, newAPIKey, "whk_")

	// Vérifier que l'ancienne clé ne fonctionne plus
	_, err = service.ValidateAPIKey(ctx, oldAPIKey)
	assert.Error(t, err)

	// Vérifier que la nouvelle clé fonctionne
	validatedWebhook, err := service.ValidateAPIKey(ctx, newAPIKey)
	require.NoError(t, err)
	assert.Equal(t, webhook.ID, validatedWebhook.ID)
}

func TestWebhookService_ValidateAPIKey_InactiveWebhook(t *testing.T) {
	db := setupWebhookTestDB(t)
	logger, _ := zap.NewDevelopment()
	service := NewWebhookService(db, logger, "test-secret")

	userID := uuid.New()
	ctx := context.Background()

	// Créer un webhook
	webhook, err := service.RegisterWebhook(ctx, userID, "https://example.com/webhook", []string{"track.created"})
	require.NoError(t, err)

	// Désactiver le webhook
	webhook.Active = false
	db.Save(webhook)

	// La clé API ne devrait plus être valide pour un webhook inactif
	_, err = service.ValidateAPIKey(ctx, webhook.APIKey)
	assert.Error(t, err)
}
