package email

import (
	"bytes"
	"crypto/tls"
	"fmt"

	"net"
	"net/mail"
	"net/smtp"
	"os/exec"
)

const (
	SMTPHost = "smtp.migadu.com"
	SMTPPort = 465
)

func SendLocalEmail(username, subject, body string) error {
	cmd := exec.Command("/usr/sbin/sendmail", username)
	cmd.Stdin = bytes.NewBufferString(fmt.Sprintf("Subject: %s\n\n%s", subject, body))

	if err := cmd.Run(); err != nil {
		return fmt.Errorf("failed to send local email: %w", err)
	}

	return nil
}

type ExternalMailer struct {
	Password string
}

func NewExternalMailer(pw string) *ExternalMailer {
	if pw == "" {
		panic("why?")
	}
	return &ExternalMailer{
		Password: pw,
	}
}

func (m *ExternalMailer) Send(address, subj, body string) error {
	from := mail.Address{Name: "Tilde Town Admins", Address: "root@tilde.town"}
	to := mail.Address{Name: "", Address: address}

	// Setup headers
	headers := make(map[string]string)
	headers["From"] = from.String()
	headers["To"] = to.String()
	headers["Subject"] = subj

	// Setup message
	message := ""
	for k, v := range headers {
		message += fmt.Sprintf("%s: %s\r\n", k, v)
	}
	message += "\r\n" + body

	// Connect to the SMTP Server
	servername := fmt.Sprintf("%s:%d", SMTPHost, SMTPPort)

	host, _, _ := net.SplitHostPort(servername)

	auth := smtp.PlainAuth("", "root@tilde.town", m.Password, host)

	// TLS config
	tlsconfig := &tls.Config{
		InsecureSkipVerify: true,
		ServerName:         host,
	}

	// Here is the key, you need to call tls.Dial instead of smtp.Dial
	// for smtp servers running on 465 that require an ssl connection
	// from the very beginning (no starttls)
	conn, err := tls.Dial("tcp", servername, tlsconfig)
	if err != nil {
		return fmt.Errorf("failed dial: %w", err)
	}

	c, err := smtp.NewClient(conn, host)
	if err != nil {
		return fmt.Errorf("failed to make smtp client: %w", err)
	}

	// Auth
	if err = c.Auth(auth); err != nil {
		return fmt.Errorf("failed to make auth: %w", err)
	}

	// To && From
	if err = c.Mail(from.Address); err != nil {
		return fmt.Errorf("failed to create mail: %w", err)
	}

	if err = c.Rcpt(to.Address); err != nil {
		return fmt.Errorf("failed to add rcpt: %w", err)
	}

	// Data
	w, err := c.Data()
	if err != nil {
		return fmt.Errorf("failed to send data: %w", err)
	}

	_, err = w.Write([]byte(message))
	if err != nil {
		return fmt.Errorf("failed to write: %w", err)
	}

	err = w.Close()
	if err != nil {
		return fmt.Errorf("failed to close: %w", err)
	}

	c.Quit()

	return nil
}
