package services

import (
	"context"
	"encoding/json"
	"fmt"
	"regexp"
	"strings"
	"time"

	"github.com/breakpilot/consent-service/internal/models"
	"github.com/google/uuid"
)

// RenderTemplate renders a template with variables
func (s *EmailTemplateService) RenderTemplate(version *models.EmailTemplateVersion, variables map[string]string) (*models.EmailPreviewResponse, error) {
	subject := version.Subject
	bodyHTML := version.BodyHTML
	bodyText := version.BodyText

	// Replace variables in format {{variable_name}}
	re := regexp.MustCompile(`\{\{(\w+)\}\}`)

	replaceFunc := func(content string) string {
		return re.ReplaceAllStringFunc(content, func(match string) string {
			varName := strings.Trim(match, "{}")
			if val, ok := variables[varName]; ok {
				return val
			}
			return match // Keep placeholder if variable not provided
		})
	}

	return &models.EmailPreviewResponse{
		Subject:  replaceFunc(subject),
		BodyHTML: replaceFunc(bodyHTML),
		BodyText: replaceFunc(bodyText),
	}, nil
}

// LogEmailSend logs a sent email
func (s *EmailTemplateService) LogEmailSend(ctx context.Context, log *models.EmailSendLog) error {
	_, err := s.db.Exec(ctx, `
		INSERT INTO email_send_logs
		(id, user_id, version_id, recipient, subject, status, error_msg, variables, sent_at, created_at)
		VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
	`, log.ID, log.UserID, log.VersionID, log.Recipient, log.Subject, log.Status,
	   log.ErrorMsg, log.Variables, log.SentAt, log.CreatedAt)
	if err != nil {
		return fmt.Errorf("failed to log email send: %w", err)
	}
	return nil
}

// GetEmailStats returns email statistics
func (s *EmailTemplateService) GetEmailStats(ctx context.Context) (*models.EmailStats, error) {
	var stats models.EmailStats

	err := s.db.QueryRow(ctx, `
		SELECT
			COUNT(*) as total_sent,
			COUNT(*) FILTER (WHERE status = 'delivered') as delivered,
			COUNT(*) FILTER (WHERE status = 'bounced') as bounced,
			COUNT(*) FILTER (WHERE status = 'failed') as failed,
			COUNT(*) FILTER (WHERE created_at > NOW() - INTERVAL '7 days') as recent_sent
		FROM email_send_logs
	`).Scan(&stats.TotalSent, &stats.Delivered, &stats.Bounced, &stats.Failed, &stats.RecentSent)
	if err != nil {
		return nil, fmt.Errorf("failed to get email stats: %w", err)
	}

	if stats.TotalSent > 0 {
		stats.DeliveryRate = float64(stats.Delivered) / float64(stats.TotalSent) * 100
	}

	return &stats, nil
}

// GetDefaultTemplateContent returns default content for a template type
func (s *EmailTemplateService) GetDefaultTemplateContent(templateType, language string) (subject, bodyHTML, bodyText string) {
	// Default templates in German
	if language == "de" {
		switch templateType {
		case models.EmailTypeWelcome:
			return s.getWelcomeTemplateDE()
		case models.EmailTypeEmailVerification:
			return s.getEmailVerificationTemplateDE()
		case models.EmailTypePasswordReset:
			return s.getPasswordResetTemplateDE()
		case models.EmailTypePasswordChanged:
			return s.getPasswordChangedTemplateDE()
		case models.EmailType2FAEnabled:
			return s.get2FAEnabledTemplateDE()
		case models.EmailType2FADisabled:
			return s.get2FADisabledTemplateDE()
		case models.EmailTypeNewDeviceLogin:
			return s.getNewDeviceLoginTemplateDE()
		case models.EmailTypeSuspiciousActivity:
			return s.getSuspiciousActivityTemplateDE()
		case models.EmailTypeAccountLocked:
			return s.getAccountLockedTemplateDE()
		case models.EmailTypeAccountUnlocked:
			return s.getAccountUnlockedTemplateDE()
		case models.EmailTypeDeletionRequested:
			return s.getDeletionRequestedTemplateDE()
		case models.EmailTypeDeletionConfirmed:
			return s.getDeletionConfirmedTemplateDE()
		case models.EmailTypeDataExportReady:
			return s.getDataExportReadyTemplateDE()
		case models.EmailTypeEmailChanged:
			return s.getEmailChangedTemplateDE()
		case models.EmailTypeNewVersionPublished:
			return s.getNewVersionPublishedTemplateDE()
		case models.EmailTypeConsentReminder:
			return s.getConsentReminderTemplateDE()
		case models.EmailTypeConsentDeadlineWarning:
			return s.getConsentDeadlineWarningTemplateDE()
		case models.EmailTypeAccountSuspended:
			return s.getAccountSuspendedTemplateDE()
		}
	}

	// Default English fallback
	return "No template", "<p>No template available</p>", "No template available"
}

// InitDefaultTemplates creates default email templates if they don't exist
func (s *EmailTemplateService) InitDefaultTemplates(ctx context.Context) error {
	templateTypes := []struct {
		Type        string
		Name        string
		Description string
		SortOrder   int
	}{
		{models.EmailTypeWelcome, "Willkommens-E-Mail", "Wird nach erfolgreicher Registrierung gesendet", 1},
		{models.EmailTypeEmailVerification, "E-Mail-Verifizierung", "Enthält Link zur E-Mail-Bestätigung", 2},
		{models.EmailTypePasswordReset, "Passwort zurücksetzen", "Enthält Link zum Passwort-Reset", 3},
		{models.EmailTypePasswordChanged, "Passwort geändert", "Bestätigung der Passwortänderung", 4},
		{models.EmailType2FAEnabled, "2FA aktiviert", "Bestätigung der 2FA-Aktivierung", 5},
		{models.EmailType2FADisabled, "2FA deaktiviert", "Warnung über 2FA-Deaktivierung", 6},
		{models.EmailTypeNewDeviceLogin, "Neuer Login", "Benachrichtigung über Login von neuem Gerät", 7},
		{models.EmailTypeSuspiciousActivity, "Verdächtige Aktivität", "Warnung über verdächtige Kontoaktivität", 8},
		{models.EmailTypeAccountLocked, "Konto gesperrt", "Benachrichtigung über Kontosperrung", 9},
		{models.EmailTypeAccountUnlocked, "Konto entsperrt", "Bestätigung der Kontoentsperrung", 10},
		{models.EmailTypeDeletionRequested, "Löschung angefordert", "Bestätigung der Löschanfrage", 11},
		{models.EmailTypeDeletionConfirmed, "Löschung bestätigt", "Bestätigung der Kontolöschung", 12},
		{models.EmailTypeDataExportReady, "Datenexport bereit", "Benachrichtigung über fertigen Datenexport", 13},
		{models.EmailTypeEmailChanged, "E-Mail geändert", "Bestätigung der E-Mail-Änderung", 14},
		{models.EmailTypeNewVersionPublished, "Neue Version veröffentlicht", "Benachrichtigung über neue Dokumentversion", 15},
		{models.EmailTypeConsentReminder, "Zustimmungs-Erinnerung", "Erinnerung an ausstehende Zustimmung", 16},
		{models.EmailTypeConsentDeadlineWarning, "Frist-Warnung", "Dringende Warnung vor ablaufender Frist", 17},
		{models.EmailTypeAccountSuspended, "Konto suspendiert", "Benachrichtigung über Kontosuspendierung", 18},
	}

	for _, tt := range templateTypes {
		// Check if template exists
		var exists bool
		err := s.db.QueryRow(ctx, `SELECT EXISTS(SELECT 1 FROM email_templates WHERE type = $1)`, tt.Type).Scan(&exists)
		if err != nil {
			return fmt.Errorf("failed to check template existence: %w", err)
		}

		if !exists {
			desc := tt.Description
			_, err = s.db.Exec(ctx, `
				INSERT INTO email_templates (id, type, name, description, is_active, sort_order, created_at, updated_at)
				VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
			`, uuid.New(), tt.Type, tt.Name, &desc, true, tt.SortOrder, time.Now(), time.Now())
			if err != nil {
				return fmt.Errorf("failed to create template %s: %w", tt.Type, err)
			}

			// Create default German version
			template, err := s.GetTemplateByType(ctx, tt.Type)
			if err != nil {
				return fmt.Errorf("failed to get template %s: %w", tt.Type, err)
			}

			subject, bodyHTML, bodyText := s.GetDefaultTemplateContent(tt.Type, "de")
			_, err = s.db.Exec(ctx, `
				INSERT INTO email_template_versions
				(id, template_id, version, language, subject, body_html, body_text, status, published_at, created_at, updated_at)
				VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
			`, uuid.New(), template.ID, "1.0.0", "de", subject, bodyHTML, bodyText, "published", time.Now(), time.Now(), time.Now())
			if err != nil {
				return fmt.Errorf("failed to create template version %s: %w", tt.Type, err)
			}
		}
	}

	return nil
}

// GetSendLogs returns email send logs with optional filtering
func (s *EmailTemplateService) GetSendLogs(ctx context.Context, limit, offset int) ([]models.EmailSendLog, int, error) {
	var total int
	err := s.db.QueryRow(ctx, `SELECT COUNT(*) FROM email_send_logs`).Scan(&total)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to count send logs: %w", err)
	}

	rows, err := s.db.Query(ctx, `
		SELECT id, user_id, version_id, recipient, subject, status, error_msg, variables, sent_at, delivered_at, created_at
		FROM email_send_logs
		ORDER BY created_at DESC
		LIMIT $1 OFFSET $2
	`, limit, offset)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to get send logs: %w", err)
	}
	defer rows.Close()

	var logs []models.EmailSendLog
	for rows.Next() {
		var log models.EmailSendLog
		err := rows.Scan(&log.ID, &log.UserID, &log.VersionID, &log.Recipient, &log.Subject,
			&log.Status, &log.ErrorMsg, &log.Variables, &log.SentAt, &log.DeliveredAt, &log.CreatedAt)
		if err != nil {
			return nil, 0, fmt.Errorf("failed to scan send log: %w", err)
		}
		logs = append(logs, log)
	}

	return logs, total, nil
}

// SendEmail sends an email using the specified template (stub - actual sending would use SMTP)
func (s *EmailTemplateService) SendEmail(ctx context.Context, templateType, language, recipient string, variables map[string]string, userID *uuid.UUID) error {
	// Get published version
	version, err := s.GetPublishedVersion(ctx, templateType, language)
	if err != nil {
		return fmt.Errorf("failed to get published version: %w", err)
	}

	// Render template
	rendered, err := s.RenderTemplate(version, variables)
	if err != nil {
		return fmt.Errorf("failed to render template: %w", err)
	}

	// Log the send attempt
	variablesJSON, _ := json.Marshal(variables)
	now := time.Now()
	sendLog := &models.EmailSendLog{
		ID:        uuid.New(),
		UserID:    userID,
		VersionID: version.ID,
		Recipient: recipient,
		Subject:   rendered.Subject,
		Status:    "queued",
		Variables: ptr(string(variablesJSON)),
		CreatedAt: now,
	}

	if err := s.LogEmailSend(ctx, sendLog); err != nil {
		return fmt.Errorf("failed to log email send: %w", err)
	}

	// TODO: Actual email sending via SMTP would go here
	// For now, we just log it as "sent"
	_, err = s.db.Exec(ctx, `
		UPDATE email_send_logs SET status = 'sent', sent_at = $1 WHERE id = $2
	`, now, sendLog.ID)
	if err != nil {
		return fmt.Errorf("failed to update send log status: %w", err)
	}

	return nil
}

func ptr(s string) *string {
	return &s
}
