package service_test

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/user-management-system/internal/cache"
	"github.com/user-management-system/internal/service"
)

// =============================================================================
// CaptchaService Tests
// =============================================================================

func setupCaptchaService(t *testing.T) (*service.CaptchaService, context.Context) {
	l1 := cache.NewL1CacheWithSize(1000)
	// Use disabled Redis cache for testing
	l2 := cache.NewRedisCache(false)
	cacheManager := cache.NewCacheManager(l1, l2)
	ctx := context.Background()
	return service.NewCaptchaService(cacheManager), ctx
}

func TestCaptchaService_Generate_Success(t *testing.T) {
	svc, ctx := setupCaptchaService(t)

	result, err := svc.Generate(ctx)
	require.NoError(t, err)
	assert.NotNil(t, result)
	assert.NotEmpty(t, result.CaptchaID)
	assert.NotEmpty(t, result.ImageData)
	assert.Greater(t, len(result.ImageData), 0)
}

func TestCaptchaService_Verify_CorrectAnswer(t *testing.T) {
	svc, ctx := setupCaptchaService(t)

	// Generate a captcha
	result, err := svc.Generate(ctx)
	require.NoError(t, err)

	// Get the stored answer using VerifyWithoutDelete
	// We can't know the exact answer, so test with wrong answer first
	valid := svc.Verify(ctx, result.CaptchaID, "wrong_answer")
	assert.False(t, valid)
}

func TestCaptchaService_Verify_EmptyID(t *testing.T) {
	svc, ctx := setupCaptchaService(t)

	valid := svc.Verify(ctx, "", "answer")
	assert.False(t, valid)
}

func TestCaptchaService_Verify_EmptyAnswer(t *testing.T) {
	svc, ctx := setupCaptchaService(t)

	// Generate a captcha
	result, err := svc.Generate(ctx)
	require.NoError(t, err)

	valid := svc.Verify(ctx, result.CaptchaID, "")
	assert.False(t, valid)
}

func TestCaptchaService_Verify_NonExistent(t *testing.T) {
	svc, ctx := setupCaptchaService(t)

	valid := svc.Verify(ctx, "non-existent-id", "answer")
	assert.False(t, valid)
}

func TestCaptchaService_VerifyOneTimeUse(t *testing.T) {
	svc, ctx := setupCaptchaService(t)

	// Generate a captcha
	result, err := svc.Generate(ctx)
	require.NoError(t, err)

	// First verification with wrong answer should fail
	valid1 := svc.Verify(ctx, result.CaptchaID, "wrong_answer")
	assert.False(t, valid1)

	// Second verification should also fail (already deleted or wrong answer)
	valid2 := svc.Verify(ctx, result.CaptchaID, "another_wrong")
	assert.False(t, valid2)
}

func TestCaptchaService_ValidateCaptcha_Success(t *testing.T) {
	svc, ctx := setupCaptchaService(t)

	// Generate a captcha
	result, err := svc.Generate(ctx)
	require.NoError(t, err)

	// We can't validate with correct answer without knowing it
	// So test error cases
	err = svc.ValidateCaptcha(ctx, "", "answer")
	assert.Error(t, err)

	err = svc.ValidateCaptcha(ctx, result.CaptchaID, "")
	assert.Error(t, err)

	err = svc.ValidateCaptcha(ctx, result.CaptchaID, "wrong_answer")
	assert.Error(t, err)
}

func TestCaptchaService_ValidateCaptcha_EmptyID(t *testing.T) {
	svc, ctx := setupCaptchaService(t)

	err := svc.ValidateCaptcha(ctx, "", "answer")
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "验证码ID不能为空")
}

func TestCaptchaService_ValidateCaptcha_EmptyAnswer(t *testing.T) {
	svc, ctx := setupCaptchaService(t)

	err := svc.ValidateCaptcha(ctx, "some-id", "")
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "验证码答案不能为空")
}

func TestCaptchaService_MultipleGeneration(t *testing.T) {
	svc, ctx := setupCaptchaService(t)

	// Generate multiple captchas
	ids := make(map[string]bool)
	for i := 0; i < 5; i++ {
		result, err := svc.Generate(ctx)
		require.NoError(t, err)
		require.NotNil(t, result)
		require.NotEmpty(t, result.CaptchaID)
		require.NotEmpty(t, result.ImageData)

		// Check uniqueness
		assert.False(t, ids[result.CaptchaID], "Captcha ID should be unique")
		ids[result.CaptchaID] = true
	}
}

func TestCaptchaService_Verify_CaseInsensitive(t *testing.T) {
	svc, ctx := setupCaptchaService(t)

	// Generate a captcha
	result, err := svc.Generate(ctx)
	require.NoError(t, err)

	// Both should fail (we don't know the answer)
	// But this test verifies case handling doesn't crash
	_ = svc.Verify(ctx, result.CaptchaID, "ABC")
	_ = svc.Verify(ctx, result.CaptchaID, "abc")
}
