package services

import (
	"context"
	"fmt"
	"log"
	"os"
	"strconv"
	"time"

	"github.com/google/uuid"
	gomail "github.com/wneessen/go-mail"

	"lune/talentscale/internal/modules/billing/repositories"
	"lune/talentscale/internal/modules/billing/templates"
)

// EmailService handles transactional email sending with retry and logging
type EmailService struct {
	host     string
	port     int
	username string
	password string
	from     string
	repo     repositories.BillingRepository
}

// NewEmailService creates a new email service instance
func NewEmailService(repo repositories.BillingRepository) *EmailService {
	port, _ := strconv.Atoi(getEnvDefault("SMTP_PORT", "1025"))
	return &EmailService{
		host:     getEnvDefault("SMTP_HOST", "localhost"),
		port:     port,
		username: getEnvDefault("SMTP_USERNAME", ""),
		password: getEnvDefault("SMTP_PASSWORD", ""),
		from:     getEnvDefault("SMTP_FROM", "noreply@localhost"),
		repo:     repo,
	}
}

func getEnvDefault(key, defaultVal string) string {
	if v := os.Getenv(key); v != "" {
		return v
	}
	return defaultVal
}

// EmailPayload contains all data needed to render and send an email
type EmailPayload struct {
	To        []string
	Subject   string
	HTMLBody  string
	EmailType string
	CompanyID uuid.UUID
}

// SendWithRetry sends an email with exponential backoff retry (max 3 attempts)
func (s *EmailService) SendWithRetry(payload EmailPayload) {
	go func() {
		var lastErr error
		maxRetries := 3

		for attempt := 1; attempt <= maxRetries; attempt++ {
			err := s.send(payload)
			if err == nil {
				// Log success for each recipient
				for _, recipient := range payload.To {
					s.logEmail(recipient, payload.EmailType, payload.Subject, "sent", nil)
				}
				return
			}

			lastErr = err
			log.Printf("⚠️ Email send attempt %d/%d failed: %v", attempt, maxRetries, err)

			// Exponential backoff: 2s, 4s, 8s
			backoff := time.Duration(1<<uint(attempt)) * time.Second
			time.Sleep(backoff)
		}

		// All retries failed
		errMsg := lastErr.Error()
		for _, recipient := range payload.To {
			s.logEmail(recipient, payload.EmailType, payload.Subject, "failed", &errMsg)
		}
		log.Printf("❌ Email permanently failed after %d retries: %v", maxRetries, lastErr)
	}()
}

// send performs the actual SMTP send
func (s *EmailService) send(payload EmailPayload) error {
	log.Println("🔥 NEW EMAIL SERVICE VERSION ACTIVE")
	m := gomail.NewMsg()

	if err := m.From(s.from); err != nil {
		return fmt.Errorf("set from: %w", err)
	}

	if err := m.To(payload.To...); err != nil {
		return fmt.Errorf("set to: %w", err)
	}

	m.Subject(payload.Subject)
	m.SetBodyString(gomail.TypeTextHTML, payload.HTMLBody)

	// Detect local Mailpit mode
	// isLocalSMTP := s.host == "localhost" || s.port == 1025
	isLocalSMTP := true

	var (
		c   *gomail.Client
		err error
	)

	if isLocalSMTP {
		log.Printf("📨 SMTP MODE: LOCAL MAILPIT (%s:%d)", s.host, s.port)

		// Mailpit: no auth + no mandatory TLS
		c, err = gomail.NewClient(
			s.host,
			gomail.WithPort(s.port),
			gomail.WithSMTPAuth(gomail.SMTPAuthNoAuth),
			// gomail.WithTLSPolicy(gomail.NoTLS),
			gomail.WithTLSPolicy(gomail.NoTLS),
		)
		log.Printf("error gomail.NewClient : %+v", err)
	} else {
		log.Printf("📨 SMTP MODE: PRODUCTION SMTP (%s:%d)", s.host, s.port)

		// Production SMTP
		c, err = gomail.NewClient(
			s.host,
			gomail.WithPort(s.port),
			gomail.WithSMTPAuth(gomail.SMTPAuthPlain),
			gomail.WithUsername(s.username),
			gomail.WithPassword(s.password),
			// gomail.WithTLSPolicy(gomail.TLSMandatory),
			gomail.WithTLSPolicy(gomail.NoTLS),
		)
	}

	if err != nil {
		return fmt.Errorf("create mail client: %w", err)
	}

	if err := c.DialAndSend(m); err != nil {
		log.Printf("HOST=%s PORT=%d", s.host, s.port)
		log.Printf("TO=%v", payload.To)
		log.Printf("FROM=%s", s.from)
		log.Printf("SMTP ERROR: %+v", err)
		return fmt.Errorf("dial and send: %w", err)
	}

	log.Printf("✅ Email sent successfully to=%v", payload.To)

	return nil
}

// logEmail saves email activity to the database
func (s *EmailService) logEmail(recipient, emailType, subject, status string, errMsg *string) {
	now := time.Now()
	var sentAt *time.Time
	if status == "sent" {
		sentAt = &now
	}

	emailLog := &repositories.EmailLogRow{
		ID:           uuid.New(),
		Recipient:    recipient,
		EmailType:    emailType,
		Subject:      subject,
		Status:       status,
		ErrorMessage: errMsg,
		SentAt:       sentAt,
		CreatedAt:    now,
	}

	ctx := context.Background()
	if err := s.repo.CreateEmailLog(ctx, emailLog); err != nil {
		log.Printf("⚠️ Failed to log email: %v", err)
	}
}

// ─── Transactional Email Methods ─────────────────────────────────────────────

// SendInvoiceCreated sends invoice creation notification
func (s *EmailService) SendInvoiceCreated(recipients []string, data templates.InvoiceEmailData) {
	html := templates.RenderInvoiceCreated(data)
	s.SendWithRetry(EmailPayload{
		To:        recipients,
		Subject:   fmt.Sprintf("[TalentScale] Invoice %s Created", data.InvoiceNumber),
		HTMLBody:  html,
		EmailType: "invoice_created",
	})
}

// SendPaymentSuccess sends payment success notification
func (s *EmailService) SendPaymentSuccess(recipients []string, data templates.PaymentEmailData) {
	html := templates.RenderPaymentSuccess(data)
	s.SendWithRetry(EmailPayload{
		To:        recipients,
		Subject:   "[TalentScale] Payment Successful — Subscription Activated",
		HTMLBody:  html,
		EmailType: "payment_success",
	})
}

// SendPaymentFailed sends payment failure notification
func (s *EmailService) SendPaymentFailed(recipients []string, data templates.PaymentEmailData) {
	html := templates.RenderPaymentFailed(data)
	s.SendWithRetry(EmailPayload{
		To:        recipients,
		Subject:   "[TalentScale] Payment Failed",
		HTMLBody:  html,
		EmailType: "payment_failed",
	})
}

// SendSubscriptionActivated sends subscription activation notification
func (s *EmailService) SendSubscriptionActivated(recipients []string, data templates.SubscriptionEmailData) {
	html := templates.RenderSubscriptionActivated(data)
	s.SendWithRetry(EmailPayload{
		To:        recipients,
		Subject:   "[TalentScale] Subscription Activated",
		HTMLBody:  html,
		EmailType: "subscription_activated",
	})
}
