package mailer

import (
	"context"
	"fmt"
	"net"
	"net/mail"
	"net/smtp"
	"strconv"
	"strings"
	"time"

	"trustcontact/internal/config"
)

type SMTPMailer struct {
	host     string
	port     int
	username string
	password string
	from     string
	fromName string
}

func NewSMTPMailer(cfg *config.Config) (*SMTPMailer, error) {
	if strings.TrimSpace(cfg.SMTP.Host) == "" {
		return nil, fmt.Errorf("smtp host is required")
	}
	if cfg.SMTP.Port <= 0 {
		return nil, fmt.Errorf("smtp port must be > 0")
	}
	if strings.TrimSpace(cfg.SMTP.From) == "" {
		return nil, fmt.Errorf("smtp from is required")
	}

	return &SMTPMailer{
		host:     cfg.SMTP.Host,
		port:     cfg.SMTP.Port,
		username: cfg.SMTP.Username,
		password: cfg.SMTP.Password,
		from:     cfg.SMTP.From,
		fromName: cfg.SMTP.FromName,
	}, nil
}

func (m *SMTPMailer) Send(ctx context.Context, to, subject, htmlBody, textBody string) error {
	if ctx != nil {
		if err := ctx.Err(); err != nil {
			return err
		}
	}

	addr := net.JoinHostPort(m.host, strconv.Itoa(m.port))
	msg := m.buildMessage(to, subject, htmlBody, textBody)

	var auth smtp.Auth
	if m.username != "" {
		auth = smtp.PlainAuth("", m.username, m.password, m.host)
	}

	if err := smtp.SendMail(addr, auth, m.from, []string{to}, []byte(msg)); err != nil {
		return err
	}

	if ctx != nil {
		if err := ctx.Err(); err != nil {
			return err
		}
	}

	return nil
}

func (m *SMTPMailer) buildMessage(to, subject, htmlBody, textBody string) string {
	boundary := fmt.Sprintf("mixed-%d", time.Now().UTC().UnixNano())
	fromAddr := (&mail.Address{Name: m.fromName, Address: m.from}).String()
	toAddr := (&mail.Address{Address: to}).String()

	headers := []string{
		fmt.Sprintf("From: %s", fromAddr),
		fmt.Sprintf("To: %s", toAddr),
		fmt.Sprintf("Subject: %s", subject),
		"MIME-Version: 1.0",
		fmt.Sprintf("Content-Type: multipart/alternative; boundary=%q", boundary),
		"",
	}

	parts := []string{
		fmt.Sprintf("--%s", boundary),
		"Content-Type: text/plain; charset=UTF-8",
		"",
		textBody,
		fmt.Sprintf("--%s", boundary),
		"Content-Type: text/html; charset=UTF-8",
		"",
		htmlBody,
		fmt.Sprintf("--%s--", boundary),
		"",
	}

	return strings.Join(append(headers, parts...), "\r\n")
}
