// Package mailer sends transactional email (currently just the password
// reset link). Stdlib net/smtp only — no external mail dependency.
package mailer

import (
	"context"
	"fmt"
	"log/slog"
	"net/mail"
	"net/smtp"
)

// Mailer sends a plain-text email. Implementations must not block past ctx's
// deadline in spirit, though net/smtp has no native context support.
type Mailer interface {
	Send(ctx context.Context, to, subject, body string) error
}

// SMTPMailer delivers via a real SMTP server using net/smtp's PLAIN auth.
// Used whenever SMTP_HOST is configured.
type SMTPMailer struct {
	Host string
	Port string
	User string
	Pass string
	From string
}

func (m *SMTPMailer) Send(_ context.Context, to, subject, body string) error {
	addr := fmt.Sprintf("%s:%s", m.Host, m.Port)
	var auth smtp.Auth
	if m.User != "" {
		auth = smtp.PlainAuth("", m.User, m.Pass, m.Host)
	}

	// Extract bare email address for envelope MAIL FROM to avoid 501 syntax error
	// when From is formatted with display name (e.g. "KeluargaMart <no-reply@domain.com>").
	envelopeFrom := m.From
	if parsed, err := mail.ParseAddress(m.From); err == nil {
		envelopeFrom = parsed.Address
	}

	msg := fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\nMIME-Version: 1.0\r\nContent-Type: text/plain; charset=\"utf-8\"\r\n\r\n%s\r\n",
		m.From, to, subject, body)
	return smtp.SendMail(addr, auth, envelopeFrom, []string{to}, []byte(msg))
}

// LogMailer is the dev/CI fallback used when SMTP_HOST is unset: it writes
// the would-be email (including any link/token in the body) to the
// structured server logger instead of sending it, so a developer can
// complete a flow like password reset by reading the logs. It must never be
// selected once SMTP_HOST is configured — production requires real SMTP or
// password reset silently degrades to log-only, which is a deployment gap,
// not an acceptable prod posture.
type LogMailer struct {
	Log *slog.Logger
}

func (m *LogMailer) Send(_ context.Context, to, subject, body string) error {
	m.Log.Info("[DEV MAIL — SMTP not configured] email not sent, logging instead",
		"to", to, "subject", subject, "body", body)
	return nil
}
