package email

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

// Config 存储 SMTP 发件配置。
type Config struct {
	SMTPHost string // 例：smtp.qq.com
	SMTPPort string // 例：465（SSL）或 587（STARTTLS）
	From     string // 发件人邮箱地址
	Password string // SMTP 密码或授权码
	FromName string // 显示名称，例："萌芽小店"
}

// IsConfigured 判断配置是否充足，可以尝试发送邮件。
func (c *Config) IsConfigured() bool {
	return c.From != "" && c.Password != "" && c.SMTPHost != ""
}

// OrderNotifyData 包含发送订单通知邮件所需的数据。
type OrderNotifyData struct {
	ToEmail     string
	ToName      string
	ProductName string
	OrderID     string
	Quantity    int
	Codes       []string // 手动发货时为空
	IsManual    bool
}

// SendOrderNotify 发送订单发货通知邮件。
// 若配置不完整或收件人为空，则静默跳过，返回 nil。
func SendOrderNotify(cfg Config, data OrderNotifyData) error {
	if !cfg.IsConfigured() || data.ToEmail == "" {
		return nil
	}

	if cfg.SMTPPort == "" {
		cfg.SMTPPort = "465"
	}
	if cfg.SMTPHost == "" {
		cfg.SMTPHost = "smtp.qq.com"
	}
	fromName := cfg.FromName
	if fromName == "" {
		fromName = "萌芽小店"
	}

	subject := "【萌芽小店】您的订单已发货"
	if data.IsManual {
		subject = "【萌芽小店】您的订单正在处理中"
	}

	body := buildBody(data)
	msg := buildMIMEMessage(cfg.From, fromName, data.ToEmail, subject, body)

	addr := fmt.Sprintf("%s:%s", cfg.SMTPHost, cfg.SMTPPort)
	auth := smtp.PlainAuth("", cfg.From, cfg.Password, cfg.SMTPHost)

	// QQ 邮箱使用 SSL（端口 465），需直接 TLS 拨号。
	if cfg.SMTPPort == "465" {
		return sendSSL(addr, cfg.SMTPHost, auth, cfg.From, data.ToEmail, msg)
	}
	return smtp.SendMail(addr, auth, cfg.From, []string{data.ToEmail}, []byte(msg))
}

func buildBody(data OrderNotifyData) string {
	var sb strings.Builder
	now := time.Now().Format("2006 年 01 月 02 日 15:04:05")

	recipient := data.ToName
	if recipient == "" {
		recipient = "用户"
	}

	sb.WriteString("尊敬的 ")
	sb.WriteString(recipient)
	sb.WriteString("，\n\n")
	sb.WriteString("    您好！感谢您在萌芽小店的支持与购买。\n\n")

	sb.WriteString("────────────────────────────────\n")
	sb.WriteString("  订单信息\n")
	sb.WriteString("────────────────────────────────\n")
	sb.WriteString(fmt.Sprintf("  商品名称：%s\n", data.ProductName))
	sb.WriteString(fmt.Sprintf("  订单编号：%s\n", data.OrderID))
	sb.WriteString(fmt.Sprintf("  购买数量：%d 件\n", data.Quantity))
	sb.WriteString(fmt.Sprintf("  通知时间：%s\n", now))
	sb.WriteString("────────────────────────────────\n\n")

	if data.IsManual {
		sb.WriteString("  您的订单已成功提交，目前正在等待人工审核与处理。\n")
		sb.WriteString("  工作人员将尽快为您安排发货，请耐心等候。\n")
		sb.WriteString("  发货完成后，我们将另行发送邮件通知。\n\n")
	} else {
		sb.WriteString("  您的订单已完成自动发货，发货内容如下：\n\n")
		if len(data.Codes) > 0 {
			for i, code := range data.Codes {
				sb.WriteString(fmt.Sprintf("  [%d] %s\n", i+1, code))
			}
			sb.WriteString("\n")
		}
		sb.WriteString("  请妥善保管以上发货内容，切勿泄露给他人。\n\n")
	}

	sb.WriteString("  如有任何疑问，请联系在线客服，我们将竭诚为您服务。\n\n")
	sb.WriteString("────────────────────────────────\n")
	sb.WriteString("  此邮件由系统自动发送，请勿直接回复。\n")
	sb.WriteString("────────────────────────────────\n")
	return sb.String()
}

// buildMIMEMessage 构建符合 MIME 规范的邮件报文，支持 UTF-8 中文。
func buildMIMEMessage(from, fromName, to, subject, body string) string {
	encodedFromName := fmt.Sprintf("=?UTF-8?B?%s?=", encodeBase64(fromName))
	encodedSubject := fmt.Sprintf("=?UTF-8?B?%s?=", encodeBase64(subject))
	return fmt.Sprintf(
		"From: %s <%s>\r\nTo: %s\r\nSubject: %s\r\nMIME-Version: 1.0\r\nContent-Type: text/plain; charset=UTF-8\r\nContent-Transfer-Encoding: base64\r\n\r\n%s",
		encodedFromName, from, to, encodedSubject, encodeBase64(body),
	)
}

func encodeBase64(s string) string {
	const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
	b := []byte(s)
	var buf strings.Builder
	for i := 0; i < len(b); i += 3 {
		remaining := len(b) - i
		b0 := b[i]
		b1 := byte(0)
		b2 := byte(0)
		if remaining > 1 {
			b1 = b[i+1]
		}
		if remaining > 2 {
			b2 = b[i+2]
		}
		buf.WriteByte(chars[b0>>2])
		buf.WriteByte(chars[((b0&0x03)<<4)|(b1>>4)])
		if remaining > 1 {
			buf.WriteByte(chars[((b1&0x0f)<<2)|(b2>>6)])
		} else {
			buf.WriteByte('=')
		}
		if remaining > 2 {
			buf.WriteByte(chars[b2&0x3f])
		} else {
			buf.WriteByte('=')
		}
	}
	return buf.String()
}

// sendSSL 通过 TLS 直接拨号发送邮件（适用于 465 端口 SSL 连接，如 QQ 邮箱）。
func sendSSL(addr, host string, auth smtp.Auth, from, to string, msg string) error {
	tlsConfig := &tls.Config{
		ServerName: host,
		MinVersion: tls.VersionTLS12,
	}
	conn, err := tls.Dial("tcp", addr, tlsConfig)
	if err != nil {
		return fmt.Errorf("tls 拨号失败: %w", err)
	}
	defer conn.Close()

	client, err := smtp.NewClient(conn, host)
	if err != nil {
		return fmt.Errorf("创建 SMTP 客户端失败: %w", err)
	}
	defer client.Quit() //nolint:errcheck

	if err = client.Auth(auth); err != nil {
		return fmt.Errorf("SMTP 认证失败: %w", err)
	}
	if err = client.Mail(from); err != nil {
		return fmt.Errorf("SMTP MAIL FROM 失败: %w", err)
	}
	if err = client.Rcpt(to); err != nil {
		return fmt.Errorf("SMTP RCPT TO 失败: %w", err)
	}
	w, err := client.Data()
	if err != nil {
		return fmt.Errorf("SMTP DATA 失败: %w", err)
	}
	if _, err = fmt.Fprint(w, msg); err != nil {
		return fmt.Errorf("写入邮件内容失败: %w", err)
	}
	return w.Close()
}
