package commerce

import (
	"context"
	"crypto/tls"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"html"
	"net"
	"net/smtp"
	"strings"
	"time"

	"gorm.io/gorm"

	"qycw/go-server/internal/plugins"
)

type businessEmailConfig struct {
	Enabled       bool
	Provider      string
	Host          string
	Port          int
	User          string
	Password      string
	FromEmail     string
	FromName      string
	Security      string
	AuthEnabled   bool
	ValidateCerts bool
	ReplyTo       string
	FrontendURL   string
}

type businessEmailMessage struct {
	Subject      string
	TextBody     string
	HTMLBody     string
	Template     string
	TemplateData map[string]any
}

type businessEmailRow struct {
	Label string
	Value string
}

func SendOrderPlacedEmail(ctx context.Context, db *gorm.DB, userID int64, outOrderNo string, totalAmount int, snapshot JSONRaw, pluginSvc ...*plugins.Service) error {
	user, cfg, err := emailUserAndConfig(ctx, db, userID)
	if err != nil || user.Email == nil || strings.TrimSpace(*user.Email) == "" {
		return err
	}
	lines := []string{
		fmt.Sprintf("%s，您好：", displayUsername(user)),
		"",
		"您的订单已成功提交，我们正在为您开通以下服务：",
		"",
	}
	items := orderEmailItems(snapshot)
	for _, item := range items {
		lines = append(lines, "  - "+item)
	}
	lines = append(lines,
		"",
		fmt.Sprintf("订单号：%s", outOrderNo),
		fmt.Sprintf("实付金额：￥%.2f", float64(totalAmount)/100),
		"",
		"开通完成后我们会再次通知您。",
		strings.TrimRight(cfg.FrontendURL, "/")+"/console/instances",
	)
	message := newBusinessEmailMessage(
		"commerce.order_placed",
		"【清云互联】订单已提交，正在为您开通服务",
		strings.Join(lines, "\n"),
		"订单已提交",
		"您的订单已成功提交，我们正在为您开通相关服务。",
		[]businessEmailRow{{Label: "订单号", Value: outOrderNo}, {Label: "服务内容", Value: strings.Join(items, "；")}, {Label: "实付金额", Value: fmt.Sprintf("￥%.2f", float64(totalAmount)/100)}},
		"开通完成后我们会再次通知您。",
		"查看实例",
		strings.TrimRight(cfg.FrontendURL, "/")+"/console/instances",
	)
	message.TemplateData["order_no"] = outOrderNo
	message.TemplateData["total_amount"] = totalAmount
	message.TemplateData["items"] = items
	return sendBusinessEmail(ctx, cfg, firstPluginService(pluginSvc), *user.Email, message)
}

func SendInstanceActiveEmail(ctx context.Context, db *gorm.DB, instance Instance, pluginSvc ...*plugins.Service) error {
	user, cfg, err := emailUserAndConfig(ctx, db, instance.UserID)
	if err != nil || user.Email == nil || strings.TrimSpace(*user.Email) == "" {
		return err
	}
	var product Product
	_ = db.WithContext(ctx).Where("id = ?", instance.ProductID).First(&product).Error
	lines := []string{
		fmt.Sprintf("%s，您好：", displayUsername(user)),
		"",
		fmt.Sprintf("您购买的“%s”已成功开通，以下是连接信息：", defaultText(product.Name, fmt.Sprintf("服务 #%d", instance.ID))),
		"",
	}
	if instance.MainIP != nil {
		lines = append(lines, "  主 IP："+*instance.MainIP)
	}
	if instance.SSHPort != nil {
		lines = append(lines, fmt.Sprintf("  SSH 端口：%d", *instance.SSHPort))
	}
	if instance.Hostname != nil {
		lines = append(lines, "  主机名："+*instance.Hostname)
	}
	if instance.ExpiresAt != nil {
		lines = append(lines, "  到期时间："+instance.ExpiresAt.Format("2006-01-02"))
	}
	lines = append(lines, "", "登录密码请在控制台实例详情中查看。", strings.TrimRight(cfg.FrontendURL, "/")+"/console/instances")
	rows := []businessEmailRow{{Label: "服务", Value: defaultText(product.Name, fmt.Sprintf("服务 #%d", instance.ID))}}
	if instance.MainIP != nil {
		rows = append(rows, businessEmailRow{Label: "主 IP", Value: *instance.MainIP})
	}
	if instance.SSHPort != nil {
		rows = append(rows, businessEmailRow{Label: "SSH 端口", Value: fmt.Sprint(*instance.SSHPort)})
	}
	if instance.Hostname != nil {
		rows = append(rows, businessEmailRow{Label: "主机名", Value: *instance.Hostname})
	}
	if instance.ExpiresAt != nil {
		rows = append(rows, businessEmailRow{Label: "到期时间", Value: instance.ExpiresAt.Format("2006-01-02 15:04:05")})
	}
	message := newBusinessEmailMessage("commerce.instance_active", "【清云互联】您的云服务已成功开通", strings.Join(lines, "\n"), "服务开通成功", "您的云服务已经准备就绪。", rows, "登录密码请在控制台实例详情中查看。", "查看实例", strings.TrimRight(cfg.FrontendURL, "/")+"/console/instances")
	message.TemplateData["instance_id"] = instance.ID
	return sendBusinessEmail(ctx, cfg, firstPluginService(pluginSvc), *user.Email, message)
}

func SendInstanceFailedEmail(ctx context.Context, db *gorm.DB, instance Instance, reason string, pluginSvc ...*plugins.Service) error {
	user, cfg, err := emailUserAndConfig(ctx, db, instance.UserID)
	if err != nil || user.Email == nil || strings.TrimSpace(*user.Email) == "" {
		return err
	}
	var product Product
	_ = db.WithContext(ctx).Where("id = ?", instance.ProductID).First(&product).Error
	lines := []string{
		fmt.Sprintf("%s，您好：", displayUsername(user)),
		"",
		fmt.Sprintf("非常抱歉，您购买的“%s”开通失败。", defaultText(product.Name, fmt.Sprintf("服务 #%d", instance.ID))),
		"",
		fmt.Sprintf("失败原因：%s", reason),
		"",
		"我们的客服会尽快介入处理。",
		strings.TrimRight(cfg.FrontendURL, "/") + "/console",
	}
	message := newBusinessEmailMessage(
		"commerce.instance_failed",
		"【清云互联】服务开通失败",
		strings.Join(lines, "\n"),
		"服务开通失败",
		"很抱歉，系统未能完成本次服务开通。",
		[]businessEmailRow{{Label: "服务", Value: defaultText(product.Name, fmt.Sprintf("服务 #%d", instance.ID))}, {Label: "失败原因", Value: reason}},
		"客服人员会根据失败记录继续处理。",
		"进入控制台",
		strings.TrimRight(cfg.FrontendURL, "/")+"/console",
	)
	message.TemplateData["instance_id"] = instance.ID
	message.TemplateData["reason"] = reason
	return sendBusinessEmail(ctx, cfg, firstPluginService(pluginSvc), *user.Email, message)
}

func SendInstanceLifecycleEmail(ctx context.Context, db *gorm.DB, instance Instance, subject string, content string, pluginSvc ...*plugins.Service) error {
	user, cfg, err := emailUserAndConfig(ctx, db, instance.UserID)
	if err != nil || user.Email == nil || strings.TrimSpace(*user.Email) == "" {
		return err
	}
	var product Product
	_ = db.WithContext(ctx).Where("id = ?", instance.ProductID).First(&product).Error
	lines := []string{
		fmt.Sprintf("%s，您好：", displayUsername(user)),
		"",
		content,
		"",
		fmt.Sprintf("服务：%s", defaultText(product.Name, fmt.Sprintf("实例 #%d", instance.ID))),
	}
	if instance.MainIP != nil {
		lines = append(lines, "主 IP："+*instance.MainIP)
	}
	if instance.ExpiresAt != nil {
		lines = append(lines, "到期时间："+instance.ExpiresAt.Format("2006-01-02 15:04:05"))
	}
	lines = append(lines, "", strings.TrimRight(cfg.FrontendURL, "/")+"/console/instances")
	rows := []businessEmailRow{{Label: "服务", Value: defaultText(product.Name, fmt.Sprintf("实例 #%d", instance.ID))}}
	if instance.MainIP != nil {
		rows = append(rows, businessEmailRow{Label: "主 IP", Value: *instance.MainIP})
	}
	if instance.ExpiresAt != nil {
		rows = append(rows, businessEmailRow{Label: "到期时间", Value: instance.ExpiresAt.Format("2006-01-02 15:04:05")})
	}
	message := newBusinessEmailMessage("commerce.instance_lifecycle", "【清云互联】"+subject, strings.Join(lines, "\n"), subject, content, rows, "请及时登录控制台检查服务状态。", "查看实例", strings.TrimRight(cfg.FrontendURL, "/")+"/console/instances")
	message.TemplateData["instance_id"] = instance.ID
	message.TemplateData["content"] = content
	return sendBusinessEmail(ctx, cfg, firstPluginService(pluginSvc), *user.Email, message)
}

func emailUserAndConfig(ctx context.Context, db *gorm.DB, userID int64) (UserAccount, businessEmailConfig, error) {
	var user UserAccount
	if err := db.WithContext(ctx).Where("id = ?", userID).First(&user).Error; err != nil {
		return user, businessEmailConfig{}, err
	}
	cfg, err := loadBusinessEmailConfig(ctx, db)
	return user, cfg, err
}

func loadBusinessEmailConfig(ctx context.Context, db *gorm.DB) (businessEmailConfig, error) {
	cfg := businessEmailConfig{Provider: "mode.email.aliyunemail.provider:create_provider", Port: 465, Security: "ssl", AuthEnabled: true, ValidateCerts: true, FromName: "QingYun Cloud", FrontendURL: "http://localhost:5173"}
	var settings []SystemSetting
	if err := db.WithContext(ctx).Where("`key` LIKE ? OR `key` IN ?", "notification.email.%", []string{"platform.frontend_url"}).Find(&settings).Error; err != nil {
		return cfg, err
	}
	for _, item := range settings {
		switch item.Key {
		case "notification.email.enabled":
			cfg.Enabled = settingBool(item.Value, false)
		case "notification.email.provider":
			cfg.Provider = settingStringCommerce(item.Value, cfg.Provider)
		case "notification.email.smtp_host":
			cfg.Host = settingStringCommerce(item.Value, "")
		case "notification.email.smtp_port":
			cfg.Port = settingInt(item.Value, cfg.Port)
		case "notification.email.smtp_user":
			cfg.User = settingStringCommerce(item.Value, "")
		case "notification.email.smtp_password":
			cfg.Password = settingStringCommerce(item.Value, "")
		case "notification.email.smtp_from_email":
			cfg.FromEmail = settingStringCommerce(item.Value, "")
		case "notification.email.smtp_from_name":
			cfg.FromName = settingStringCommerce(item.Value, cfg.FromName)
		case "notification.email.smtp_security":
			cfg.Security = strings.ToLower(settingStringCommerce(item.Value, cfg.Security))
		case "notification.email.smtp_auth_enabled":
			cfg.AuthEnabled = settingBool(item.Value, true)
		case "notification.email.smtp_validate_certs":
			cfg.ValidateCerts = settingBool(item.Value, true)
		case "notification.email.smtp_reply_to":
			cfg.ReplyTo = settingStringCommerce(item.Value, "")
		case "platform.frontend_url":
			cfg.FrontendURL = settingStringCommerce(item.Value, cfg.FrontendURL)
		}
	}
	return cfg, nil
}

func sendBusinessEmail(ctx context.Context, cfg businessEmailConfig, pluginSvc *plugins.Service, to string, message businessEmailMessage) error {
	if !cfg.Enabled {
		return nil
	}
	if pluginID := plugins.PluginIDFromProvider(cfg.Provider); pluginID != "" {
		if pluginSvc == nil {
			return fmt.Errorf("email plugin runtime is not enabled")
		}
		resp, err := pluginSvc.SendEmail(ctx, pluginID, plugins.EmailSendRequest{
			To:           to,
			Subject:      message.Subject,
			TextBody:     message.TextBody,
			HTMLBody:     message.HTMLBody,
			Template:     message.Template,
			TemplateData: message.TemplateData,
			Config:       pluginSvc.MergeConfig(ctx, pluginID, businessEmailPluginConfig(cfg)),
		})
		if err != nil {
			return err
		}
		if !resp.OK {
			if strings.TrimSpace(resp.Message) != "" {
				return fmt.Errorf("%s", strings.TrimSpace(resp.Message))
			}
			return fmt.Errorf("email plugin send failed")
		}
		return nil
	}
	if cfg.Host == "" || cfg.FromEmail == "" {
		return nil
	}
	addr := net.JoinHostPort(cfg.Host, fmt.Sprint(cfg.Port))
	body := message.TextBody
	contentType := "text/plain"
	if strings.TrimSpace(message.HTMLBody) != "" {
		body = message.HTMLBody
		contentType = "text/html"
	}
	headers := []string{
		fmt.Sprintf("From: %s <%s>", encodeBusinessHeader(cfg.FromName), cfg.FromEmail),
		fmt.Sprintf("To: <%s>", to),
		fmt.Sprintf("Subject: %s", encodeBusinessHeader(message.Subject)),
		"MIME-Version: 1.0",
		"Content-Type: " + contentType + "; charset=UTF-8",
	}
	if cfg.ReplyTo != "" {
		headers = append(headers, fmt.Sprintf("Reply-To: <%s>", cfg.ReplyTo))
	}
	emailBytes := []byte(strings.Join(append(headers, "", body), "\r\n"))
	var auth smtp.Auth
	if cfg.AuthEnabled && cfg.User != "" {
		auth = smtp.PlainAuth("", cfg.User, cfg.Password, cfg.Host)
	}
	if cfg.Security == "ssl" {
		conn, err := tls.Dial("tcp", addr, &tls.Config{ServerName: cfg.Host, InsecureSkipVerify: !cfg.ValidateCerts})
		if err != nil {
			return err
		}
		defer conn.Close()
		client, err := smtp.NewClient(conn, cfg.Host)
		if err != nil {
			return err
		}
		defer client.Close()
		return sendBusinessWithClient(client, cfg, auth, to, emailBytes)
	}
	if cfg.Security == "starttls" {
		client, err := smtp.Dial(addr)
		if err != nil {
			return err
		}
		defer client.Close()
		if ok, _ := client.Extension("STARTTLS"); ok {
			if err := client.StartTLS(&tls.Config{ServerName: cfg.Host, InsecureSkipVerify: !cfg.ValidateCerts}); err != nil {
				return err
			}
		}
		return sendBusinessWithClient(client, cfg, auth, to, emailBytes)
	}
	return smtp.SendMail(addr, auth, cfg.FromEmail, []string{to}, emailBytes)
}

func newBusinessEmailMessage(template string, subject string, textBody string, title string, lead string, rows []businessEmailRow, note string, ctaLabel string, ctaURL string) businessEmailMessage {
	rowData := make([]map[string]string, 0, len(rows))
	for _, row := range rows {
		rowData = append(rowData, map[string]string{"label": row.Label, "value": row.Value})
	}
	return businessEmailMessage{
		Subject:  subject,
		TextBody: textBody,
		HTMLBody: renderBusinessEmailHTML(title, lead, rows, note, ctaLabel, ctaURL),
		Template: template,
		TemplateData: map[string]any{
			"title": title, "lead": lead, "rows": rowData, "note": note, "cta_label": ctaLabel, "cta_url": ctaURL,
		},
	}
}

func renderBusinessEmailHTML(title string, lead string, rows []businessEmailRow, note string, ctaLabel string, ctaURL string) string {
	var rowHTML strings.Builder
	for index, row := range rows {
		border := ""
		if index > 0 {
			border = "border-top:1px solid #e4e9ed;"
		}
		rowHTML.WriteString(fmt.Sprintf(`<tr><td style="padding:12px 16px;color:#5b6873;width:96px;%s">%s</td><td style="padding:12px 16px;font-weight:600;%s">%s</td></tr>`, border, html.EscapeString(row.Label), border, html.EscapeString(row.Value)))
	}
	cta := ""
	if strings.TrimSpace(ctaURL) != "" {
		cta = fmt.Sprintf(`<a href="%s" style="display:inline-block;padding:12px 20px;background:#1677ff;color:#fff;text-decoration:none;font-weight:600">%s</a>`, html.EscapeString(ctaURL), html.EscapeString(ctaLabel))
	}
	return fmt.Sprintf(`<!doctype html><html><body style="margin:0;background:#f3f5f7;font-family:Arial,'Microsoft YaHei',sans-serif;color:#17212b"><table role="presentation" width="100%%" cellspacing="0" cellpadding="0"><tr><td align="center" style="padding:32px 16px"><table role="presentation" width="100%%" cellspacing="0" cellpadding="0" style="max-width:620px;background:#fff;border:1px solid #dfe5ea"><tr><td style="padding:24px 28px;background:#17212b;color:#fff;font-size:20px;font-weight:700">清云互联</td></tr><tr><td style="padding:30px 28px"><h1 style="margin:0 0 18px;font-size:24px">%s</h1><p style="margin:0 0 20px;line-height:1.8">%s</p><table role="presentation" width="100%%" cellspacing="0" cellpadding="0" style="background:#f7f9fa;border:1px solid #e4e9ed">%s</table><p style="margin:20px 0;line-height:1.8">%s</p>%s<p style="margin:28px 0 0;color:#7a8792;font-size:13px;line-height:1.7">此邮件由系统自动发送，请勿直接回复。</p></td></tr></table></td></tr></table></body></html>`, html.EscapeString(title), html.EscapeString(lead), rowHTML.String(), html.EscapeString(note), cta)
}

func businessEmailPluginConfig(cfg businessEmailConfig) map[string]any {
	return map[string]any{
		"smtp_host":           cfg.Host,
		"smtp_port":           cfg.Port,
		"smtp_username":       cfg.User,
		"smtp_password":       cfg.Password,
		"smtp_from":           cfg.FromEmail,
		"smtp_from_name":      cfg.FromName,
		"smtp_security":       cfg.Security,
		"smtp_auth_enabled":   cfg.AuthEnabled,
		"smtp_validate_certs": cfg.ValidateCerts,
		"smtp_reply_to":       cfg.ReplyTo,
	}
}

func sendBusinessWithClient(client *smtp.Client, cfg businessEmailConfig, auth smtp.Auth, to string, message []byte) error {
	if cfg.AuthEnabled && auth != nil {
		if err := client.Auth(auth); err != nil {
			return err
		}
	}
	if err := client.Mail(cfg.FromEmail); err != nil {
		return err
	}
	if err := client.Rcpt(to); err != nil {
		return err
	}
	writer, err := client.Data()
	if err != nil {
		return err
	}
	if _, err := writer.Write(message); err != nil {
		_ = writer.Close()
		return err
	}
	if err := writer.Close(); err != nil {
		return err
	}
	return client.Quit()
}

func orderEmailItems(snapshot JSONRaw) []string {
	var items []map[string]any
	_ = json.Unmarshal(snapshot, &items)
	out := []string{}
	for _, item := range items {
		name := strings.TrimSpace(fmt.Sprint(firstNonNil(item["product_name"], item["name"], "未知产品")))
		quantity := intValueCommerce(item["quantity"], 1)
		cycle := strings.TrimSpace(fmt.Sprint(item["cycle"]))
		unit := intValueCommerce(item["unit_price"], 0)
		out = append(out, fmt.Sprintf("%s x%d %s ￥%.2f/周期", name, quantity, cycle, float64(unit)/100))
	}
	if len(out) == 0 {
		out = append(out, "云服务")
	}
	return out
}

func settingStringCommerce(raw JSONRaw, fallback string) string {
	var decoded any
	if err := json.Unmarshal(raw, &decoded); err == nil {
		if text := strings.TrimSpace(fmt.Sprint(decoded)); text != "" && text != "<nil>" {
			return text
		}
	}
	text := strings.Trim(strings.TrimSpace(string(raw)), `"`)
	if text == "" {
		return fallback
	}
	return text
}

func settingBool(raw JSONRaw, fallback bool) bool {
	var decoded any
	if err := json.Unmarshal(raw, &decoded); err == nil {
		switch value := decoded.(type) {
		case bool:
			return value
		case string:
			return strings.EqualFold(value, "true") || value == "1" || strings.EqualFold(value, "yes") || strings.EqualFold(value, "on")
		}
	}
	return fallback
}

func intValueCommerce(value any, fallback int) int {
	switch typed := value.(type) {
	case int:
		return typed
	case int64:
		return int(typed)
	case float64:
		return int(typed)
	default:
		return fallback
	}
}

func displayUsername(user UserAccount) string {
	if strings.TrimSpace(user.Username) != "" {
		return user.Username
	}
	return fmt.Sprintf("用户%d", user.ID)
}

func defaultText(value string, fallback string) string {
	if strings.TrimSpace(value) == "" {
		return fallback
	}
	return value
}

func encodeBusinessHeader(value string) string {
	return "=?UTF-8?B?" + base64.StdEncoding.EncodeToString([]byte(value)) + "?="
}

var _ = time.Second

func firstPluginService(items []*plugins.Service) *plugins.Service {
	if len(items) == 0 {
		return nil
	}
	return items[0]
}
