package email

import (
	"log"
	"os"
	"strconv"
	"time"

	gomail "github.com/wneessen/go-mail"
)

type Config struct {
	Host     string
	Port     int
	Username string
	Password string
	From     string
}

type Service struct {
	cfg Config
}

func NewService(cfg Config) *Service {
	return &Service{cfg: cfg}
}

func NewServiceFromEnv() *Service {
	port, _ := strconv.Atoi(os.Getenv("SMTP_PORT"))
	if port == 0 {
		port = 587
	}
	return &Service{
		cfg: Config{
			Host:     os.Getenv("SMTP_HOST"),
			Port:     port,
			Username: os.Getenv("SMTP_USERNAME"),
			Password: os.Getenv("SMTP_PASSWORD"),
			From:     os.Getenv("SMTP_FROM"),
		},
	}
}

type Payload struct {
	To      []string
	Subject string
	Body    string
}

func (s *Service) Send(payload Payload) error {
	m := gomail.NewMsg()

	if err := m.From(s.cfg.From); err != nil {
		return err
	}

	if err := m.To(payload.To...); err != nil {
		return err
	}

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

	// Detect local Mailpit SMTP
	isLocalSMTP :=
		s.cfg.Host == "localhost" ||
			s.cfg.Host == "127.0.0.1" ||
			s.cfg.Port == 1025

	var (
		c   *gomail.Client
		err error
	)

	if isLocalSMTP {
		log.Printf("📨 MAILPIT MODE (%s:%d)", s.cfg.Host, s.cfg.Port)

		c, err = gomail.NewClient(
			s.cfg.Host,
			gomail.WithPort(s.cfg.Port),
			gomail.WithSMTPAuth(gomail.SMTPAuthNoAuth),
			gomail.WithTLSPolicy(gomail.NoTLS),
		)
	} else {
		log.Printf("📨 PRODUCTION SMTP MODE (%s:%d)", s.cfg.Host, s.cfg.Port)

		c, err = gomail.NewClient(
			s.cfg.Host,
			gomail.WithPort(s.cfg.Port),
			gomail.WithSMTPAuth(gomail.SMTPAuthPlain),
			gomail.WithUsername(s.cfg.Username),
			gomail.WithPassword(s.cfg.Password),
			gomail.WithTLSPolicy(gomail.TLSMandatory),
		)
	}

	if err != nil {
		return err
	}

	if err := c.DialAndSend(m); err != nil {
		log.Printf("SMTP ERROR: %+v", err)
		return err
	}

	log.Printf("✅ EMAIL SENT: %v", payload.To)

	return nil
}

func (s *Service) SendWithRetry(payload Payload, retries int) {
	go func() {
		for i := 0; i < retries; i++ {
			err := s.Send(payload)
			if err == nil {
				return
			}
			log.Printf("Email retry %d/%d failed: %v", i+1, retries, err)
			time.Sleep(time.Duration(1<<uint(i)) * time.Second)
		}
	}()
}
