package services

import (
	"fmt"
	"html"
	"os"
	"strings"
	"testing"
	"time"

	"goyco/internal/config"
	"goyco/internal/testutils"
)

func TestEmailService_IntegrationWithRealSMTP(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping integration test in short mode")
	}

	sender := testutils.GetSMTPSenderFromEnv(t)

	recipient := os.Getenv("SMTP_TEST_RECIPIENT")
	if strings.TrimSpace(recipient) == "" {
		recipient = sender.From
	}

	config := testutils.NewEmailTestConfig("https://example.com")
	service, err := NewEmailService(config, sender)
	if err != nil {
		t.Skipf("Skipping SMTP integration test: failed to create email service: %v", err)
	}

	user := testutils.NewEmailTestUser("integrationuser", recipient)
	token := "integration-test-token"

	t.Run("VerificationEmail_RealSMTP", func(t *testing.T) {
		err := service.SendVerificationEmail(user, token)
		if err != nil {
			t.Errorf("SendVerificationEmail failed: %v", err)
		}

		body := service.GenerateVerificationEmailBody(user.Username, fmt.Sprintf("%s/confirm?token=%s", config.App.BaseURL, token))
		if !strings.Contains(body, "https://example.com/confirm?token=integration-test-token") {
			t.Errorf("Expected body to contain verification URL")
		}
		if !strings.Contains(body, "<!DOCTYPE html>") {
			t.Errorf("Expected HTML content in email body")
		}
	})

	t.Run("PasswordResetEmail_RealSMTP", func(t *testing.T) {
		err := service.SendPasswordResetEmail(user, token)
		if err != nil {
			t.Errorf("SendPasswordResetEmail failed: %v", err)
		}

		body := service.GeneratePasswordResetEmailBody(user.Username, fmt.Sprintf("%s/reset-password?token=%s", config.App.BaseURL, token))
		if !strings.Contains(body, "https://example.com/reset-password?token=integration-test-token") {
			t.Errorf("Expected body to contain reset URL")
		}
	})

	t.Run("AccountDeletionEmail_RealSMTP", func(t *testing.T) {
		err := service.SendAccountDeletionEmail(user, token)
		if err != nil {
			t.Errorf("SendAccountDeletionEmail failed: %v", err)
		}

		body := service.GenerateAccountDeletionEmailBody(user.Username, fmt.Sprintf("%s/settings/delete/confirm?token=%s", config.App.BaseURL, token))
		if !strings.Contains(body, "https://example.com/settings/delete/confirm?token=integration-test-token") {
			t.Errorf("Expected body to contain deletion confirmation URL")
		}
	})
}

func TestEmailService_Performance(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping performance test in short mode")
	}

	config := testutils.NewEmailTestConfig("https://example.com")
	service, err := NewEmailService(config, &testutils.MockEmailSender{})
	if err != nil {
		t.Fatalf("Failed to create email service: %v", err)
	}

	user := testutils.NewEmailTestUser("perfuser", "perf@example.com")

	service.GenerateVerificationEmailBody(user.Username, "https://example.com/confirm?token=test")

	start := time.Now()
	iterations := 1000
	for range iterations {
		service.GenerateVerificationEmailBody(user.Username, "https://example.com/confirm?token=test")
	}
	duration := time.Since(start)

	maxDuration := 500 * time.Millisecond
	if duration > maxDuration {
		t.Errorf("HTML generation took too long: %v (expected < %v for %d iterations, %.2fms per template)",
			duration, maxDuration, iterations, float64(duration.Nanoseconds())/float64(iterations)/1e6)
	}

	t.Logf("Generated %d HTML emails in %v (%.2fms per template)",
		iterations, duration, float64(duration.Nanoseconds())/float64(iterations)/1e6)
}

func TestEmailService_EdgeCases(t *testing.T) {
	config := testutils.NewEmailTestConfig("https://example.com")
	service, err := NewEmailService(config, &testutils.MockEmailSender{})
	if err != nil {
		t.Fatalf("Failed to create email service: %v", err)
	}

	t.Run("EmptyUsername", func(t *testing.T) {
		body := service.GenerateVerificationEmailBody("", "https://example.com/confirm?token=test")
		if !strings.Contains(body, "Hello ,") {
			t.Error("Expected empty username to be handled gracefully")
		}
	})

	t.Run("VeryLongUsername", func(t *testing.T) {
		longUsername := strings.Repeat("a", 1000)
		body := service.GenerateVerificationEmailBody(longUsername, "https://example.com/confirm?token=test")
		if !strings.Contains(body, longUsername) {
			t.Error("Expected long username to be included in email")
		}
	})

	t.Run("SpecialCharactersInUsername", func(t *testing.T) {
		specialUsername := "user@domain.com & <script>alert('xss')</script>"
		body := service.GenerateVerificationEmailBody(specialUsername, "https://example.com/confirm?token=test")
		escapedUsername := html.EscapeString(specialUsername)
		if !strings.Contains(body, escapedUsername) {
			t.Errorf("Expected escaped username %q to be included", escapedUsername)
		}
	})

	t.Run("EmptyToken", func(t *testing.T) {
		body := service.GenerateVerificationEmailBody("testuser", "https://example.com/confirm?token=")
		if !strings.Contains(body, "https://example.com/confirm?token=") {
			t.Error("Expected empty token to be handled")
		}
	})

	t.Run("VeryLongToken", func(t *testing.T) {
		longToken := strings.Repeat("a", 1000)
		url := fmt.Sprintf("https://example.com/confirm?token=%s", longToken)
		body := service.GenerateVerificationEmailBody("testuser", url)
		if !strings.Contains(body, url) {
			t.Error("Expected long token to be included in email")
		}
	})
}

func TestNewEmailService(t *testing.T) {
	tests := []struct {
		name        string
		config      *config.Config
		sender      EmailSender
		expectError bool
		errorMsg    string
	}{
		{
			name:        "Valid configuration",
			config:      testutils.NewEmailTestConfig("https://example.com"),
			sender:      &testutils.MockEmailSender{},
			expectError: false,
		},
		{
			name:        "Empty base URL",
			config:      testutils.NewEmailTestConfig(""),
			sender:      &testutils.MockEmailSender{},
			expectError: true,
			errorMsg:    "APP_BASE_URL is required",
		},
		{
			name:        "Whitespace base URL",
			config:      testutils.NewEmailTestConfig("   "),
			sender:      &testutils.MockEmailSender{},
			expectError: true,
			errorMsg:    "APP_BASE_URL is required",
		},
		{
			name:        "Base URL with trailing slash",
			config:      testutils.NewEmailTestConfig("https://example.com/"),
			sender:      &testutils.MockEmailSender{},
			expectError: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			service, err := NewEmailService(tt.config, tt.sender)

			if tt.expectError {
				if err == nil {
					t.Errorf("Expected error, got nil")
					return
				}
				if !strings.Contains(err.Error(), tt.errorMsg) {
					t.Errorf("Expected error to contain '%s', got '%s'", tt.errorMsg, err.Error())
				}
				return
			}

			if err != nil {
				t.Errorf("Unexpected error: %v", err)
				return
			}

			if service == nil {
				t.Error("Expected service, got nil")
				return
			}

			expectedBaseURL := strings.TrimRight(strings.TrimSpace(tt.config.App.BaseURL), "/")
			if service.baseURL != expectedBaseURL {
				t.Errorf("Expected baseURL '%s', got '%s'", expectedBaseURL, service.baseURL)
			}
		})
	}
}

func TestEmailService_DynamicTitle(t *testing.T) {
	const (
		placeholderTitle = "My Custom Site"
		customTitle      = "Custom Community"
	)

	cfg := &config.Config{
		App: config.AppConfig{
			Title:   customTitle,
			BaseURL: "https://example.com",
		},
	}

	sender := &testutils.MockEmailSender{}
	service, err := NewEmailService(cfg, sender)
	if err != nil {
		t.Fatalf("Failed to create email service: %v", err)
	}

	body := service.GenerateVerificationEmailBody("testuser", "https://example.com/confirm?token=abc123")

	if !strings.Contains(body, customTitle) {
		t.Error("Expected email body to contain custom site title")
	}

	if strings.Contains(body, placeholderTitle) {
		t.Errorf("Expected email body to not contain placeholder title %q", placeholderTitle)
	}

	if strings.Contains(body, "The Goyco Team") {
		t.Error("Expected email body to not contain default team name when custom title is set")
	}

	cfgDefault := &config.Config{
		App: config.AppConfig{
			Title:   "Goyco",
			BaseURL: "https://example.com",
		},
	}

	serviceDefault, err := NewEmailService(cfgDefault, sender)
	if err != nil {
		t.Fatalf("Failed to create email service: %v", err)
	}

	bodyDefault := serviceDefault.GenerateVerificationEmailBody("testuser", "https://example.com/confirm?token=abc123")

	if !strings.Contains(bodyDefault, "Goyco") {
		t.Error("Expected email body to contain default site title")
	}
}
