package services

import (
	"os"
	"strings"
	"testing"

	"veza-backend-api/internal/database"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/zap"
)

// setupTestEmailServiceForPasswordReset crée un EmailService de test
func setupTestEmailServiceForPasswordReset(_ *testing.T) *EmailService {
	// Créer un Database wrapper minimal pour les tests
	// Note: On ne peut pas vraiment tester l'envoi d'email sans un serveur SMTP réel
	// Donc on va tester la construction de l'email et la logique, mais pas l'envoi réel
	testDB := &database.Database{}
	logger, _ := zap.NewDevelopment()

	// Définir des variables d'environnement de test si nécessaire
	os.Setenv("FRONTEND_URL", "http://localhost:5173")
	os.Setenv("SMTP_HOST", "localhost")
	os.Setenv("SMTP_PORT", "587")
	os.Setenv("FROM_EMAIL", "test@veza.com")
	os.Setenv("FROM_NAME", "Veza Test")

	return NewEmailService(testDB, logger)
}

// TestEmailService_SendPasswordResetEmail_URLGeneration tests URL generation
func TestEmailService_SendPasswordResetEmail_URLGeneration(t *testing.T) {
	service := setupTestEmailServiceForPasswordReset(t)

	// Test avec FRONTEND_URL défini
	os.Setenv("FRONTEND_URL", "https://app.veza.com")
	resetURL := service.buildPasswordResetEmail("https://app.veza.com/reset-password?token=test-token-123")
	assert.Contains(t, resetURL, "https://app.veza.com/reset-password?token=test-token-123")
	assert.Contains(t, resetURL, "Reset Password")
	assert.Contains(t, resetURL, "This link will expire in 1 hour")
}

// TestEmailService_SendPasswordResetEmail_DefaultURL tests default URL when FRONTEND_URL is not set
func TestEmailService_SendPasswordResetEmail_DefaultURL(t *testing.T) {
	service := setupTestEmailServiceForPasswordReset(t)

	// Supprimer FRONTEND_URL pour tester la valeur par défaut
	os.Unsetenv("FRONTEND_URL")

	// Construire l'URL manuellement pour tester
	resetURL := "http://localhost:5173/reset-password?token=test-token-456"
	emailBody := service.buildPasswordResetEmail(resetURL)

	assert.Contains(t, emailBody, "http://localhost:5173/reset-password?token=test-token-456")
	assert.Contains(t, emailBody, "Reset Password")
	assert.Contains(t, emailBody, "This link will expire in 1 hour")
	assert.Contains(t, emailBody, "If you didn't request this, please ignore this email")
}

// TestEmailService_BuildPasswordResetEmail_HTMLContent tests HTML email content
func TestEmailService_BuildPasswordResetEmail_HTMLContent(t *testing.T) {
	service := setupTestEmailServiceForPasswordReset(t)

	resetURL := "https://example.com/reset-password?token=abc123"
	emailBody := service.buildPasswordResetEmail(resetURL)

	// Vérifier que le HTML contient les éléments requis
	assert.Contains(t, emailBody, "<!DOCTYPE html>")
	assert.Contains(t, emailBody, "<html>")
	assert.Contains(t, emailBody, "Reset your password")
	assert.Contains(t, emailBody, "Reset Password")
	assert.Contains(t, emailBody, resetURL)
	assert.Contains(t, emailBody, "This link will expire in 1 hour")
	assert.Contains(t, emailBody, "If you didn't request this, please ignore this email")
	assert.Contains(t, emailBody, "You requested to reset your Veza account password")
}

// TestEmailService_BuildPasswordResetEmail_ExpirationMessage tests expiration message
func TestEmailService_BuildPasswordResetEmail_ExpirationMessage(t *testing.T) {
	service := setupTestEmailServiceForPasswordReset(t)

	resetURL := "https://example.com/reset-password?token=xyz789"
	emailBody := service.buildPasswordResetEmail(resetURL)

	// Vérifier que le message d'expiration est présent
	assert.Contains(t, emailBody, "This link will expire in 1 hour")

	// Vérifier que le message de sécurité est présent
	assert.Contains(t, emailBody, "If you didn't request this, please ignore this email")

	// Vérifier que le lien est présent deux fois (bouton et texte)
	resetCount := strings.Count(emailBody, resetURL)
	assert.GreaterOrEqual(t, resetCount, 2, "Reset URL should appear at least twice (button and text)")
}

// TestEmailService_BuildPasswordResetEmail_TemplateFallback tests template fallback on error
func TestEmailService_BuildPasswordResetEmail_TemplateFallback(t *testing.T) {
	service := setupTestEmailServiceForPasswordReset(t)

	// Test avec une URL valide - le template devrait fonctionner
	resetURL := "https://example.com/reset-password?token=test-token"
	emailBody := service.buildPasswordResetEmail(resetURL)

	// Le template devrait être parsé correctement
	assert.Contains(t, emailBody, resetURL)
	assert.Contains(t, emailBody, "<html>")

	// Vérifier que le fallback n'est pas utilisé (le template devrait être parsé)
	assert.NotContains(t, emailBody, "Click here to reset your password:")
}

// TestEmailService_BuildPasswordResetEmail_ContainsToken tests that token is included in URL
func TestEmailService_BuildPasswordResetEmail_ContainsToken(t *testing.T) {
	service := setupTestEmailServiceForPasswordReset(t)

	testToken := "test-reset-token-12345"
	resetURL := "https://example.com/reset-password?token=" + testToken
	emailBody := service.buildPasswordResetEmail(resetURL)

	// Vérifier que le token est présent dans l'email
	assert.Contains(t, emailBody, testToken)
	assert.Contains(t, emailBody, "reset-password?token="+testToken)
}

// TestEmailService_SendPasswordResetEmail_Subject tests email subject
func TestEmailService_SendPasswordResetEmail_Subject(t *testing.T) {
	// Cette méthode teste indirectement que le sujet est correct
	// En regardant le code, le sujet est "Reset your Veza password"
	// On ne peut pas tester directement l'envoi sans SMTP, mais on peut vérifier la logique

	service := setupTestEmailServiceForPasswordReset(t)

	// Vérifier que la méthode existe et peut être appelée
	// Note: On ne peut pas vraiment tester l'envoi sans mock SMTP
	// Mais on peut vérifier que buildPasswordResetEmail fonctionne
	resetURL := "https://example.com/reset-password?token=test"
	emailBody := service.buildPasswordResetEmail(resetURL)

	require.NotEmpty(t, emailBody, "Email body should not be empty")
	assert.Contains(t, emailBody, "Reset your password")
}
