package services

import (
	"os"
	"strings"
	"testing"

	"veza-backend-api/internal/database"

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

func setupTestEmailService(t *testing.T) *EmailService {
	testDB := &database.Database{}
	logger := zap.NewNop()

	// Set environment variables for testing
	os.Setenv("FRONTEND_URL", "http://localhost:5173")
	os.Setenv("SMTP_HOST", "")
	os.Setenv("SMTP_PORT", "587")
	os.Setenv("FROM_EMAIL", "test@veza.com")
	os.Setenv("FROM_NAME", "Veza Test")

	return NewEmailService(testDB, logger)
}

func TestEmailService_NewEmailService(t *testing.T) {
	service := setupTestEmailService(t)

	assert.NotNil(t, service)
	assert.NotNil(t, service.logger)
	assert.NotNil(t, service.db)
}

func TestEmailService_SendVerificationEmail_NoSMTP(t *testing.T) {
	service := setupTestEmailService(t)

	// Without SMTP configured, should not error (just logs)
	err := service.SendVerificationEmail("test@example.com", "test-token-123")
	assert.NoError(t, err)
}

func TestEmailService_SendVerificationEmail_WithFRONTEND_URL(t *testing.T) {
	service := setupTestEmailService(t)

	os.Setenv("FRONTEND_URL", "https://app.veza.com")
	err := service.SendVerificationEmail("test@example.com", "test-token-123")
	assert.NoError(t, err)
}

func TestEmailService_SendVerificationEmail_DefaultURL(t *testing.T) {
	service := setupTestEmailService(t)

	os.Unsetenv("FRONTEND_URL")
	err := service.SendVerificationEmail("test@example.com", "test-token-123")
	assert.NoError(t, err)
}

func TestEmailService_buildVerificationEmailHTML_Success(t *testing.T) {
	service := setupTestEmailService(t)

	verifyURL := "https://app.veza.com/verify-email?token=test-token-123"
	html := service.buildVerificationEmailHTML(verifyURL)

	assert.Contains(t, html, "<!DOCTYPE html>")
	assert.Contains(t, html, "<html>")
	assert.Contains(t, html, "Verify your Veza account")
	assert.Contains(t, html, "Verify Email Address")
	assert.Contains(t, html, verifyURL)
	assert.Contains(t, html, "This link will expire in 24 hours")
}

func TestEmailService_buildVerificationEmailHTML_TemplateFallback(t *testing.T) {
	service := setupTestEmailService(t)

	verifyURL := "https://app.veza.com/verify-email?token=test-token-123"
	html := service.buildVerificationEmailHTML(verifyURL)

	// Should contain the URL even if template parsing fails
	assert.Contains(t, html, verifyURL)
}

func TestEmailService_SendWelcomeEmail_NoSMTP(t *testing.T) {
	service := setupTestEmailService(t)

	err := service.SendWelcomeEmail("test@example.com", "testuser")
	assert.NoError(t, err)
}

func TestEmailService_buildWelcomeEmailHTML_Success(t *testing.T) {
	service := setupTestEmailService(t)

	username := "testuser"
	html := service.buildWelcomeEmailHTML(username)

	assert.Contains(t, html, "<!DOCTYPE html>")
	assert.Contains(t, html, "<html>")
	assert.Contains(t, html, "Welcome to Veza")
	assert.Contains(t, html, username)
	assert.Contains(t, html, "Get Started")
	assert.Contains(t, html, "Uploading your first track")
	assert.Contains(t, html, "Creating playlists")
	assert.Contains(t, html, "Discovering new music")
}

func TestEmailService_buildWelcomeEmailHTML_WithFRONTEND_URL(t *testing.T) {
	service := setupTestEmailService(t)

	os.Setenv("FRONTEND_URL", "https://app.veza.com")
	username := "testuser"
	html := service.buildWelcomeEmailHTML(username)

	assert.Contains(t, html, "https://app.veza.com")
}

func TestEmailService_buildWelcomeEmailHTML_DefaultURL(t *testing.T) {
	service := setupTestEmailService(t)

	os.Unsetenv("FRONTEND_URL")
	username := "testuser"
	html := service.buildWelcomeEmailHTML(username)

	assert.Contains(t, html, "http://localhost:5173")
}

func TestEmailService_SendNotificationEmail_NoSMTP(t *testing.T) {
	service := setupTestEmailService(t)

	err := service.SendNotificationEmail("test@example.com", "Test Subject", "Test message", "track_like")
	assert.NoError(t, err)
}

func TestEmailService_buildNotificationEmailHTML_TrackLike(t *testing.T) {
	service := setupTestEmailService(t)

	message := "Someone liked your track"
	html := service.buildNotificationEmailHTML(message, "track_like")

	assert.Contains(t, html, "<!DOCTYPE html>")
	assert.Contains(t, html, "<html>")
	assert.Contains(t, html, message)
	assert.Contains(t, html, "❤️")
	assert.Contains(t, html, "View on Veza")
}

func TestEmailService_buildNotificationEmailHTML_NewFollower(t *testing.T) {
	service := setupTestEmailService(t)

	message := "You have a new follower"
	html := service.buildNotificationEmailHTML(message, "new_follower")

	assert.Contains(t, html, message)
	assert.Contains(t, html, "👤")
}

func TestEmailService_buildNotificationEmailHTML_PlaylistUpdate(t *testing.T) {
	service := setupTestEmailService(t)

	message := "A playlist was updated"
	html := service.buildNotificationEmailHTML(message, "playlist_update")

	assert.Contains(t, html, message)
	assert.Contains(t, html, "🎵")
}

func TestEmailService_buildNotificationEmailHTML_CommentReply(t *testing.T) {
	service := setupTestEmailService(t)

	message := "Someone replied to your comment"
	html := service.buildNotificationEmailHTML(message, "comment_reply")

	assert.Contains(t, html, message)
	assert.Contains(t, html, "💬")
}

func TestEmailService_buildNotificationEmailHTML_Default(t *testing.T) {
	service := setupTestEmailService(t)

	message := "You have a notification"
	html := service.buildNotificationEmailHTML(message, "unknown_type")

	assert.Contains(t, html, message)
	assert.Contains(t, html, "🔔")
}

func TestEmailService_buildNotificationEmailHTML_WithFRONTEND_URL(t *testing.T) {
	service := setupTestEmailService(t)

	os.Setenv("FRONTEND_URL", "https://app.veza.com")
	message := "Test notification"
	html := service.buildNotificationEmailHTML(message, "track_like")

	assert.Contains(t, html, "https://app.veza.com")
}

func TestEmailService_buildNotificationEmailHTML_DefaultURL(t *testing.T) {
	service := setupTestEmailService(t)

	os.Unsetenv("FRONTEND_URL")
	message := "Test notification"
	html := service.buildNotificationEmailHTML(message, "track_like")

	assert.Contains(t, html, "http://localhost:5173")
}

func TestEmailService_sendEmail_NoSMTP(t *testing.T) {
	service := setupTestEmailService(t)

	// Without SMTP configured, should not error (just logs)
	err := service.sendEmail("test@example.com", "Test Subject", "Test Body")
	assert.NoError(t, err)
}

func TestEmailService_generateVerificationToken(t *testing.T) {
	service := setupTestEmailService(t)

	token1, err1 := service.generateVerificationToken()
	assert.NoError(t, err1)
	assert.NotEmpty(t, token1)

	token2, err2 := service.generateVerificationToken()
	assert.NoError(t, err2)
	assert.NotEmpty(t, token2)

	// Tokens should be different
	assert.NotEqual(t, token1, token2)
}

func TestEmailService_generateVerificationToken_Length(t *testing.T) {
	service := setupTestEmailService(t)

	token, err := service.generateVerificationToken()
	assert.NoError(t, err)
	assert.Greater(t, len(token), 20) // Base64 encoded 32 bytes should be ~44 chars
}

func TestEmailService_SendVerificationEmailWithUserID_NoSMTP(t *testing.T) {
	t.Skip("Skipping test that requires real database connection")
	// This test requires a real database to store verification tokens
	// It's tested in integration tests instead
}

func TestEmailService_buildVerificationEmailHTML_ContainsToken(t *testing.T) {
	service := setupTestEmailService(t)

	testToken := "test-verification-token-12345"
	verifyURL := "https://app.veza.com/verify-email?token=" + testToken
	html := service.buildVerificationEmailHTML(verifyURL)

	assert.Contains(t, html, testToken)
	assert.Contains(t, html, "verify-email?token="+testToken)
}

func TestEmailService_buildVerificationEmailHTML_URLAppearsTwice(t *testing.T) {
	service := setupTestEmailService(t)

	verifyURL := "https://app.veza.com/verify-email?token=test-token"
	html := service.buildVerificationEmailHTML(verifyURL)

	// URL should appear at least twice (button and text)
	urlCount := strings.Count(html, verifyURL)
	assert.GreaterOrEqual(t, urlCount, 2, "Verify URL should appear at least twice (button and text)")
}

func TestEmailService_buildWelcomeEmailHTML_ContainsUsername(t *testing.T) {
	service := setupTestEmailService(t)

	username := "testuser123"
	html := service.buildWelcomeEmailHTML(username)

	assert.Contains(t, html, username)
}

func TestEmailService_buildNotificationEmailHTML_ContainsMessage(t *testing.T) {
	service := setupTestEmailService(t)

	message := "Custom notification message"
	html := service.buildNotificationEmailHTML(message, "track_like")

	assert.Contains(t, html, message)
}

func TestEmailService_buildNotificationEmailHTML_NotificationPreferences(t *testing.T) {
	service := setupTestEmailService(t)

	message := "Test notification"
	html := service.buildNotificationEmailHTML(message, "track_like")

	assert.Contains(t, html, "notification preferences")
	assert.Contains(t, html, "account settings")
}

func TestEmailService_EmailService_Fields(t *testing.T) {
	service := setupTestEmailService(t)

	assert.NotNil(t, service.db)
	assert.NotNil(t, service.logger)
	// SMTP fields may be empty if not configured
}

func TestEmailService_buildVerificationEmailHTML_ExpirationMessage(t *testing.T) {
	service := setupTestEmailService(t)

	verifyURL := "https://app.veza.com/verify-email?token=test"
	html := service.buildVerificationEmailHTML(verifyURL)

	assert.Contains(t, html, "24 hours")
}

func TestEmailService_buildPasswordResetEmail_ExpirationMessage(t *testing.T) {
	service := setupTestEmailService(t)

	resetURL := "https://app.veza.com/reset-password?token=test"
	html := service.buildPasswordResetEmail(resetURL)

	assert.Contains(t, html, "1 hour")
}
