package mail

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

	"doormile/config"
)

func SendOTPEmail(cfg *config.Config, toEmail, code string) error {
	subject := "Your Doormile verification code"
	body := fmt.Sprintf(
		"Your Doormile verification code is %s.\r\n\r\nIt expires in 5 minutes. If you didn't request this, you can ignore this email.",
		code,
	)

	msg := []byte(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",
		cfg.SMTPFrom, toEmail, subject, body,
	))

	auth := smtp.PlainAuth("", cfg.SMTPUser, cfg.SMTPPassword, cfg.SMTPHost)

	// Port 465 is implicit TLS (encrypted from the first byte); everything else
	// (587, 25) goes through smtp.SendMail's opportunistic STARTTLS upgrade.
	if cfg.SMTPPort == "465" {
		return sendImplicitTLS(cfg, auth, toEmail, msg)
	}

	addr := fmt.Sprintf("%s:%s", cfg.SMTPHost, cfg.SMTPPort)
	return smtp.SendMail(addr, auth, cfg.SMTPFrom, []string{toEmail}, msg)
}

func sendImplicitTLS(cfg *config.Config, auth smtp.Auth, toEmail string, msg []byte) error {
	addr := fmt.Sprintf("%s:%s", cfg.SMTPHost, cfg.SMTPPort)

	conn, err := tls.Dial("tcp", addr, &tls.Config{ServerName: cfg.SMTPHost})
	if err != nil {
		return fmt.Errorf("tls dial failed: %w", err)
	}
	defer conn.Close()

	client, err := smtp.NewClient(conn, cfg.SMTPHost)
	if err != nil {
		return fmt.Errorf("smtp client init failed: %w", err)
	}
	defer client.Close()

	if err := client.Auth(auth); err != nil {
		return fmt.Errorf("smtp auth failed: %w", err)
	}
	if err := client.Mail(cfg.SMTPFrom); err != nil {
		return err
	}
	if err := client.Rcpt(toEmail); err != nil {
		return err
	}
	w, err := client.Data()
	if err != nil {
		return err
	}
	if _, err := w.Write(msg); err != nil {
		return err
	}
	if err := w.Close(); err != nil {
		return err
	}
	return client.Quit()
}
