package smtputil

import (
	"crypto/tls"
	"fmt"
	"net/smtp"
	"strings"
	"time"
)

type SMTPConfig struct {
	Host     string
	Port     int
	Username string
	Password string
	From     string
	UseTLS   bool
}

type EmailMessage struct {
	To      []string
	Subject string
	Body    string
	HTML    bool
}

type SMTPResult struct {
	Success bool   `json:"success"`
	Error   string `json:"error,omitempty"`
}

type SMTPClient struct {
	config  SMTPConfig
	timeout time.Duration
}

func NewSMTPClient(config SMTPConfig, timeout time.Duration) *SMTPClient {
	if timeout <= 0 {
		timeout = 30 * time.Second
	}
	return &SMTPClient{
		config:  config,
		timeout: timeout,
	}
}

func (c *SMTPClient) Send(msg EmailMessage) *SMTPResult {
	result := &SMTPResult{Success: false}

	if len(msg.To) == 0 {
		result.Error = "收件人不能为空"
		return result
	}

	if c.config.Host == "" {
		result.Error = "SMTP服务器地址不能为空"
		return result
	}

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

	var auth smtp.Auth
	if c.config.Username != "" && c.config.Password != "" {
		auth = smtp.PlainAuth("", c.config.Username, c.config.Password, c.config.Host)
	}

	from := c.config.From
	if from == "" {
		from = c.config.Username
	}

	contentType := "text/plain"
	if msg.HTML {
		contentType = "text/html"
	}

	headers := make(map[string]string)
	headers["From"] = from
	headers["To"] = strings.Join(msg.To, ", ")
	headers["Subject"] = msg.Subject
	headers["MIME-Version"] = "1.0"
	headers["Content-Type"] = fmt.Sprintf("%s; charset=UTF-8", contentType)
	headers["Date"] = time.Now().Format(time.RFC1123Z)

	var message strings.Builder
	for k, v := range headers {
		message.WriteString(fmt.Sprintf("%s: %s\r\n", k, v))
	}
	message.WriteString("\r\n")
	message.WriteString(msg.Body)

	if c.config.UseTLS {
		tlsConfig := &tls.Config{
			InsecureSkipVerify: false,
			ServerName:         c.config.Host,
		}

		conn, err := tls.Dial("tcp", addr, tlsConfig)
		if err != nil {
			result.Error = fmt.Sprintf("TLS连接失败: %v", err)
			return result
		}
		defer conn.Close()

		client, err := smtp.NewClient(conn, c.config.Host)
		if err != nil {
			result.Error = fmt.Sprintf("创建SMTP客户端失败: %v", err)
			return result
		}
		defer client.Close()

		if auth != nil {
			if err := client.Auth(auth); err != nil {
				result.Error = fmt.Sprintf("SMTP认证失败: %v", err)
				return result
			}
		}

		if err := client.Mail(from); err != nil {
			result.Error = fmt.Sprintf("设置发件人失败: %v", err)
			return result
		}

		for _, to := range msg.To {
			if err := client.Rcpt(to); err != nil {
				result.Error = fmt.Sprintf("设置收件人失败: %v", err)
				return result
			}
		}

		w, err := client.Data()
		if err != nil {
			result.Error = fmt.Sprintf("准备邮件数据失败: %v", err)
			return result
		}

		_, err = w.Write([]byte(message.String()))
		if err != nil {
			result.Error = fmt.Sprintf("写入邮件内容失败: %v", err)
			return result
		}

		if err := w.Close(); err != nil {
			result.Error = fmt.Sprintf("关闭邮件写入失败: %v", err)
			return result
		}

		if err := client.Quit(); err != nil {
			result.Error = fmt.Sprintf("关闭SMTP连接失败: %v", err)
			return result
		}
	} else {
		err := smtp.SendMail(addr, auth, from, msg.To, []byte(message.String()))
		if err != nil {
			result.Error = fmt.Sprintf("发送邮件失败: %v", err)
			return result
		}
	}

	result.Success = true
	return result
}
