package service

import (
	"bytes"
	"encoding/base64"
	"fmt"
	"mime/quotedprintable"
	"strings"

	sestypes "github.com/aws/aws-sdk-go-v2/service/sesv2/types"

	"wucher/internal/queue"
	"wucher/internal/shared/pkg/uuidv7"
)

func buildSESRawContent(from string, to, cc, replyTo []string, job queue.EmailJob) (*sestypes.EmailContent, error) {
	mixedBoundary := randomMIMEBoundary("mixed")
	relatedBoundary := randomMIMEBoundary("related")
	alternativeBoundary := randomMIMEBoundary("alt")

	var buf bytes.Buffer
	writeMIMEHeader(&buf, "From", from)
	if len(to) > 0 {
		writeMIMEHeader(&buf, "To", strings.Join(to, ", "))
	}
	if len(cc) > 0 {
		writeMIMEHeader(&buf, "Cc", strings.Join(cc, ", "))
	}
	if len(replyTo) > 0 {
		writeMIMEHeader(&buf, "Reply-To", strings.Join(replyTo, ", "))
	}
	writeMIMEHeader(&buf, "Subject", sanitizeSubject(job.Subject))
	writeMIMEHeader(&buf, "MIME-Version", "1.0")
	writeMIMEHeader(&buf, "Content-Type", fmt.Sprintf(`multipart/mixed; boundary="%s"`, mixedBoundary))
	buf.WriteString("\r\n")

	writeBoundary(&buf, mixedBoundary)
	writeMIMEHeader(&buf, "Content-Type", fmt.Sprintf(`multipart/related; boundary="%s"`, relatedBoundary))
	buf.WriteString("\r\n")

	writeBoundary(&buf, relatedBoundary)
	writeMIMEHeader(&buf, "Content-Type", fmt.Sprintf(`multipart/alternative; boundary="%s"`, alternativeBoundary))
	buf.WriteString("\r\n")

	if textBody := strings.TrimSpace(job.TextBodyValue()); textBody != "" {
		writeBoundary(&buf, alternativeBoundary)
		writeTextPart(&buf, "text/plain", textBody)
	}
	if htmlBody := strings.TrimSpace(job.HTMLBody); htmlBody != "" {
		writeBoundary(&buf, alternativeBoundary)
		writeTextPart(&buf, "text/html", htmlBody)
	}
	writeClosingBoundary(&buf, alternativeBoundary)

	for i := range job.Attachments {
		writeBoundary(&buf, relatedBoundary)
		writeAttachmentPart(&buf, job.Attachments[i])
	}
	writeClosingBoundary(&buf, relatedBoundary)
	writeClosingBoundary(&buf, mixedBoundary)

	return &sestypes.EmailContent{
		Raw: &sestypes.RawMessage{Data: buf.Bytes()},
	}, nil
}

func writeTextPart(buf *bytes.Buffer, contentType, body string) {
	writeMIMEHeader(buf, "Content-Type", contentType+`; charset="UTF-8"`)
	writeMIMEHeader(buf, "Content-Transfer-Encoding", "quoted-printable")
	buf.WriteString("\r\n")
	qp := quotedprintable.NewWriter(buf)
	_, _ = qp.Write([]byte(body))
	_ = qp.Close()
	buf.WriteString("\r\n")
}

func writeAttachmentPart(buf *bytes.Buffer, attachment queue.EmailAttachment) {
	filename := attachment.Filename
	if filename == "" {
		filename = "attachment"
	}
	writeMIMEHeader(buf, "Content-Type", fmt.Sprintf(`%s; name="%s"`, attachment.ContentType, escapeMIMEHeaderValue(filename)))
	writeMIMEHeader(buf, "Content-Transfer-Encoding", "base64")
	disposition := "attachment"
	if attachment.Inline {
		disposition = "inline"
	}
	writeMIMEHeader(buf, "Content-Disposition", fmt.Sprintf(`%s; filename="%s"`, disposition, escapeMIMEHeaderValue(filename)))
	if attachment.Inline && strings.TrimSpace(attachment.ContentID) != "" {
		writeMIMEHeader(buf, "Content-ID", "<"+strings.TrimSpace(attachment.ContentID)+">")
	}
	buf.WriteString("\r\n")
	writeBase64Lines(buf, attachment.Content)
}

func writeBase64Lines(buf *bytes.Buffer, payload []byte) {
	encoded := base64.StdEncoding.EncodeToString(payload)
	for len(encoded) > 76 {
		buf.WriteString(encoded[:76])
		buf.WriteString("\r\n")
		encoded = encoded[76:]
	}
	if encoded != "" {
		buf.WriteString(encoded)
		buf.WriteString("\r\n")
	}
}

func writeMIMEHeader(buf *bytes.Buffer, key, value string) {
	buf.WriteString(key)
	buf.WriteString(": ")
	buf.WriteString(value)
	buf.WriteString("\r\n")
}

func writeBoundary(buf *bytes.Buffer, boundary string) {
	buf.WriteString("--")
	buf.WriteString(boundary)
	buf.WriteString("\r\n")
}

func writeClosingBoundary(buf *bytes.Buffer, boundary string) {
	buf.WriteString("--")
	buf.WriteString(boundary)
	buf.WriteString("--\r\n")
}

func randomMIMEBoundary(prefix string) string {
	id, err := uuidv7.String(uuidv7.MustNew())
	if err != nil {
		return prefix + "_fallback"
	}
	return prefix + "_" + strings.ReplaceAll(id, "-", "")
}

func escapeMIMEHeaderValue(value string) string {
	return strings.ReplaceAll(strings.TrimSpace(value), `"`, `'`)
}
