package clients

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

	"github.com/spf13/viper"
	"github.com/rs/zerolog/log"
)

type SMTPSettings struct {
	Host        string
	Port        int
	Username    string
	Password    string
	Encryption  string // "tls", "ssl", "none"
	FromAddress string
	FromName    string
}

var smtpSettings SMTPSettings

func InitSMTPSettings() {
	smtpSettings = SMTPSettings{
		Host:        viper.GetString("smtp.host"),
		Port:        viper.GetInt("smtp.port"),
		Username:    viper.GetString("smtp.username"),
		Password:    viper.GetString("smtp.password"),
		Encryption:  viper.GetString("smtp.encryption"),
		FromAddress: viper.GetString("smtp.from_address"),
		FromName:    viper.GetString("smtp.from_name"),
	}

	if smtpSettings.Host == "" || smtpSettings.Port == 0 || smtpSettings.FromAddress == "" {
		log.Warn().Msg("SMTP configuration incomplete. Email sending may not work.")
	} else {
		log.Info().Msgf("SMTP client initialized for %s:%d", smtpSettings.Host, smtpSettings.Port)
	}
}

func GetSMTPSettings() SMTPSettings {
	return smtpSettings
}

// SendEmail sends an email using the configured SMTP settings.
func SendEmail(toAddress, subject, body string) error {
	if smtpSettings.Host == "" {
		return fmt.Errorf("SMTP client not initialized or host is empty")
	}

	addr := fmt.Sprintf("%s:%d", smtpSettings.Host, smtpSettings.Port)

	// Setup authentication
	auth := smtp.PlainAuth("", smtpSettings.Username, smtpSettings.Password, smtpSettings.Host)

	// Construct the email message
	mime := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n"
	msg := []byte("From: " + smtpSettings.FromName + " <" + smtpSettings.FromAddress + ">\r\n" +
		"To: " + toAddress + "\r\n" +
		"Subject: " + subject + "\r\n" +
		mime + "\r\n" +
		body + "\r\n")

	var err error
	switch smtpSettings.Encryption {
	case "tls":
		// TLS encryption
		err = sendMailTLS(addr, auth, smtpSettings.FromAddress, []string{toAddress}, msg)
	case "ssl":
		// SSL encryption (usually port 465)
		err = smtp.SendMail(addr, auth, smtpSettings.FromAddress, []string{toAddress}, msg)
	case "none":
		// No encryption (usually port 25 or 587 without STARTTLS)
		err = smtp.SendMail(addr, auth, smtpSettings.FromAddress, []string{toAddress}, msg)
	default:
		return fmt.Errorf("unsupported SMTP encryption type: %s", smtpSettings.Encryption)
	}

	if err != nil {
		return fmt.Errorf("failed to send email: %w", err)
	}
	log.Info().Msgf("Email sent successfully to %s", toAddress)
	return nil
}

// sendMailTLS sends an email over a TLS connection.
func sendMailTLS(addr string, auth smtp.Auth, from string, to []string, msg []byte) error {
	conn, err := tls.Dial("tcp", addr, nil)
	if err != nil {
		return err
	}
	defer conn.Close()

	client, err := smtp.NewClient(conn, smtpSettings.Host)
	if err != nil {
		return err
	}
	defer client.Close()

	if auth != nil {
		if ok, _ := client.Extension("AUTH"); ok {
			if err = client.Auth(auth); err != nil {
				return err
			}
		}
	}

	if err = client.Mail(from); err != nil {
		return err
	}
	for _, addr := range to {
		if err = client.Rcpt(addr); err != nil {
			return err
		}
	}
	w, err := client.Data()
	if err != nil {
		return err
	}
	_, err = w.Write(msg)
	if err != nil {
		return err
	}
	err = w.Close()
	if err != nil {
		return err
	}
	return client.Quit()
}
