package smtpserver

import (
	"crypto/tls"
	"strings"
	"time"

	"github.com/emersion/go-smtp"
	"gopkg.in/ini.v1"
)

// ResolveBanner mirrors CustomSMTP's server_banner handling (the '""' literal-quotes
// convention for "explicitly empty"). go-smtp's greeting is always
// "220 <Domain> ESMTP Service Ready" with no hook to drop the " ESMTP Service Ready"
// suffix the way aiosmtpd's raw __ident__ override can — so when no custom banner is
// configured, this falls back to heloHostname (a normal, protocol-correct greeting)
// rather than Python's degenerate literally-empty banner. This is a disclosed, cosmetic
// interface deviation: no test tooling in this project inspects the SMTP banner text.
func ResolveBanner(cfg *ini.File, heloHostname string) string {
	raw := cfg.Section("Server").Key("server_banner").String()
	if raw == `""` {
		raw = ""
	}
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return heloHostname
	}
	return raw
}

// NewPlainServer mirrors server_runner.py's PlainController: no TLS context at all, so
// STARTTLS is never offered, and AUTH is advertised and usable in plaintext
// (auth_require_tls=False).
func NewPlainServer(backend *Backend, addr, banner string) *smtp.Server {
	s := smtp.NewServer(backend)
	s.Addr = addr
	s.Domain = banner
	s.AllowInsecureAuth = true
	s.ReadTimeout = 5 * time.Minute
	s.WriteTimeout = 5 * time.Minute
	return s
}

// NewTLSServer mirrors server_runner.py's TLSController: implicit/direct TLS (like
// SMTPS on port 465) — the whole connection is encrypted from the first byte, not
// STARTTLS-negotiated. Call ListenAndServeTLS (not ListenAndServe) to run it.
func NewTLSServer(backend *Backend, addr, banner string, tlsConfig *tls.Config) *smtp.Server {
	s := smtp.NewServer(backend)
	s.Addr = addr
	s.Domain = banner
	s.TLSConfig = tlsConfig
	// The session is always already TLS on this listener, so AUTH is always allowed
	// either way (auth_require_tls=True in Python, which is trivially satisfied here).
	s.AllowInsecureAuth = true
	s.ReadTimeout = 5 * time.Minute
	s.WriteTimeout = 5 * time.Minute
	return s
}
