// Package notifications provides SMTP email delivery for budget alert notifications.
package notifications

import (
	"crypto/tls"
	"fmt"
	"net"
	"net/smtp"
	"strings"
)

// Config holds SMTP relay configuration.
type Config struct {
	Host     string
	Port     int
	Username string
	Password string
	From     string
	FromName string
}

// Mailer sends transactional emails via SMTP (STARTTLS, PLAIN auth).
// Tested against Mailtrap sandbox; compatible with any RFC 4954 relay.
type Mailer struct {
	cfg Config
}

// New creates a Mailer. Returns an error if the config is obviously invalid.
func New(cfg Config) (*Mailer, error) {
	if cfg.Host == "" {
		return nil, fmt.Errorf("smtp host is required")
	}
	if cfg.Port == 0 {
		cfg.Port = 587
	}
	return &Mailer{cfg: cfg}, nil
}

// Message is a single outbound email.
type Message struct {
	To      string // single recipient address
	Subject string
	HTML    string // HTML body
}

// Send delivers msg via SMTP with STARTTLS + PLAIN auth.
func (m *Mailer) Send(msg Message) error {
	from := m.cfg.From
	if m.cfg.FromName != "" {
		from = fmt.Sprintf("%s <%s>", m.cfg.FromName, m.cfg.From)
	}

	headers := strings.Join([]string{
		fmt.Sprintf("From: %s", from),
		fmt.Sprintf("To: %s", msg.To),
		fmt.Sprintf("Subject: %s", msg.Subject),
		"MIME-Version: 1.0",
		`Content-Type: text/html; charset="UTF-8"`,
		"",
		"",
	}, "\r\n")
	body := []byte(headers + msg.HTML)

	addr := fmt.Sprintf("%s:%d", m.cfg.Host, m.cfg.Port)
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return fmt.Errorf("smtp dial %s: %w", addr, err)
	}

	client, err := smtp.NewClient(conn, m.cfg.Host)
	if err != nil {
		return fmt.Errorf("smtp client: %w", err)
	}
	defer client.Close() //nolint:errcheck

	// Upgrade to TLS via STARTTLS if the server supports it (all Mailtrap ports do).
	if ok, _ := client.Extension("STARTTLS"); ok {
		if err = client.StartTLS(&tls.Config{ServerName: m.cfg.Host}); err != nil {
			return fmt.Errorf("starttls: %w", err)
		}
	}

	auth := smtp.PlainAuth("", m.cfg.Username, m.cfg.Password, m.cfg.Host)
	if err = client.Auth(auth); err != nil {
		return fmt.Errorf("smtp auth: %w", err)
	}
	if err = client.Mail(m.cfg.From); err != nil {
		return fmt.Errorf("smtp MAIL FROM: %w", err)
	}
	if err = client.Rcpt(msg.To); err != nil {
		return fmt.Errorf("smtp RCPT TO: %w", err)
	}

	wc, err := client.Data()
	if err != nil {
		return fmt.Errorf("smtp DATA: %w", err)
	}
	if _, err = wc.Write(body); err != nil {
		return fmt.Errorf("smtp write body: %w", err)
	}
	return wc.Close()
}
