package mailruntime

import (
	stdhtml "html"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/extension/providers/mail/protocol"
)

func replyDraftContent(
	intro Body,
	sender string,
	source protocol.Message,
	replyAll bool,
) (DraftContent, error) {
	sourceText, err := quotedSourceText(source.Body)
	if err != nil {
		return DraftContent{}, err
	}
	primary := source.From
	if sameAddressIdentity(primary, sender) {
		primary = firstAddressOtherThan(
			append(
				append([]string(nil), source.To...),
				source.CC...,
			),
			sender,
		)
	}
	content := DraftContent{
		To:      []string{primary},
		Subject: prefixedSubject("Re:", source.Subject),
		Body:    intro,
	}
	if replyAll {
		content.CC = uniqueAddressesExcluding(
			append(
				append([]string(nil), source.To...),
				source.CC...,
			),
			sender,
			primary,
		)
	}
	header := "On " +
		source.SentAt.UTC().Format("2006-01-02 15:04:05Z07:00") +
		", " + source.From + " wrote:"
	if intro.Format == "html" {
		content.Body.Content += "<br><br><p>" +
			stdhtml.EscapeString(header) +
			"</p><blockquote><pre>" +
			stdhtml.EscapeString(sourceText) +
			"</pre></blockquote>"
	} else {
		content.Body.Content += "\n\n" + header + "\n" +
			quotePlainText(sourceText)
	}
	if err := validateDraftContent(content); err != nil {
		return DraftContent{}, err
	}
	return content, nil
}

func forwardDraftContent(
	intro DraftContent,
	source protocol.Message,
) (DraftContent, error) {
	sourceText, err := quotedSourceText(source.Body)
	if err != nil {
		return DraftContent{}, err
	}
	intro.Subject = prefixedSubject("Fwd:", source.Subject)
	header := "--- Forwarded message ---\n" +
		"From: " + source.From + "\n" +
		"Date: " +
		source.SentAt.UTC().Format("2006-01-02 15:04:05Z07:00") +
		"\nSubject: " + source.Subject + "\n" +
		"To: " + strings.Join(source.To, ", ") + "\n\n"
	if intro.Body.Format == "html" {
		intro.Body.Content += "<hr><pre>" +
			stdhtml.EscapeString(header+sourceText) +
			"</pre>"
	} else {
		intro.Body.Content += "\n\n" + header + sourceText
	}
	if err := validateDraftContent(intro); err != nil {
		return DraftContent{}, err
	}
	return intro, nil
}

func quotedSourceText(body protocol.Body) (string, error) {
	normalized, err := normalizeReadBody(body)
	if err != nil {
		return "", err
	}
	if normalized.Format == "sanitized_html" {
		return htmlToPlainText(normalized.Content)
	}
	return normalized.Content, nil
}

func quotePlainText(value string) string {
	lines := strings.Split(value, "\n")
	for index := range lines {
		lines[index] = "> " + lines[index]
	}
	return strings.Join(lines, "\n")
}

func prefixedSubject(prefix string, subject string) string {
	trimmed := strings.TrimSpace(subject)
	if strings.HasPrefix(strings.ToLower(trimmed), strings.ToLower(prefix)) {
		return boundedUTF8(trimmed, 998)
	}
	return boundedUTF8(prefix+" "+trimmed, 998)
}

func firstAddressOtherThan(values []string, excluded string) string {
	for _, value := range values {
		if !sameAddressIdentity(value, excluded) {
			return value
		}
	}
	return ""
}

func uniqueAddressesExcluding(
	values []string,
	excluded ...string,
) []string {
	seen := make(map[string]struct{}, len(values)+len(excluded))
	for _, value := range excluded {
		key, err := addressIdentity(value)
		if err == nil {
			seen[key] = struct{}{}
		}
	}
	result := make([]string, 0, len(values))
	for _, value := range values {
		key, err := addressIdentity(value)
		if err != nil {
			continue
		}
		if _, exists := seen[key]; exists {
			continue
		}
		seen[key] = struct{}{}
		result = append(result, value)
	}
	return result
}

func sameAddressIdentity(left string, right string) bool {
	leftKey, leftErr := addressIdentity(left)
	rightKey, rightErr := addressIdentity(right)
	return leftErr == nil && rightErr == nil && leftKey == rightKey
}
