import Testing
import Foundation
@testable import SMTPClient
import Models

@Suite("MessageFormatter")
struct MessageFormatterTests {

	// MARK: - Basic Message Formatting

	@Test("formatted message contains all required headers")
	func basicHeaders() {
		let message = OutgoingMessage(
			from: EmailAddress(name: "Alice", address: "alice@example.com"),
			to: [EmailAddress(address: "bob@example.com")],
			subject: "Hello",
			bodyText: "Hi Bob",
			messageId: "test-id@example.com"
		)

		let formatted = MessageFormatter.format(message)

		#expect(formatted.contains("From: \"Alice\" <alice@example.com>"))
		#expect(formatted.contains("To: bob@example.com"))
		#expect(formatted.contains("Subject: Hello"))
		#expect(formatted.contains("Message-ID: <test-id@example.com>"))
		#expect(formatted.contains("MIME-Version: 1.0"))
		#expect(formatted.contains("Content-Type: text/plain; charset=utf-8"))
		#expect(formatted.contains("Content-Transfer-Encoding: quoted-printable"))
		#expect(formatted.contains("Date: "))
	}

	// MARK: - Reply Headers

	@Test("reply includes In-Reply-To and References headers")
	func replyHeaders() {
		let message = OutgoingMessage(
			from: EmailAddress(address: "alice@example.com"),
			to: [EmailAddress(address: "bob@example.com")],
			subject: "Re: Hello",
			bodyText: "Thanks!",
			inReplyTo: "original-id@example.com",
			references: "<original-id@example.com>",
			messageId: "reply-id@example.com"
		)

		let formatted = MessageFormatter.format(message)

		#expect(formatted.contains("In-Reply-To: <original-id@example.com>"))
		#expect(formatted.contains("References: <original-id@example.com>"))
	}

	// MARK: - BCC Omitted

	@Test("BCC recipients are not included in formatted output")
	func bccOmitted() {
		let message = OutgoingMessage(
			from: EmailAddress(address: "alice@example.com"),
			to: [EmailAddress(address: "bob@example.com")],
			bcc: [EmailAddress(address: "secret@example.com")],
			subject: "Test",
			bodyText: "Body",
			messageId: "test@example.com"
		)

		let formatted = MessageFormatter.format(message)

		#expect(!formatted.contains("Bcc"))
		#expect(!formatted.contains("secret@example.com"))
	}

	// MARK: - Multiple CC Recipients

	@Test("multiple CC recipients formatted correctly")
	func multipleCc() {
		let message = OutgoingMessage(
			from: EmailAddress(address: "alice@example.com"),
			to: [EmailAddress(address: "bob@example.com")],
			cc: [
				EmailAddress(name: "Carol", address: "carol@example.com"),
				EmailAddress(address: "dave@example.com"),
			],
			subject: "Test",
			bodyText: "Body",
			messageId: "test@example.com"
		)

		let formatted = MessageFormatter.format(message)

		#expect(formatted.contains("Cc: \"Carol\" <carol@example.com>, dave@example.com"))
	}

	// MARK: - Quoted-Printable Encoding

	@Test("non-ASCII characters are quoted-printable encoded")
	func quotedPrintableNonAscii() {
		let encoded = MessageFormatter.quotedPrintableEncode("Grüße")

		// ü = C3 BC, ß = C3 9F, e is plain
		#expect(encoded.contains("=C3=BC"))  // ü
		#expect(encoded.contains("=C3=9F"))  // ß
		#expect(encoded.contains("Gr"))
		#expect(encoded.contains("e"))
	}

	@Test("equals sign is encoded in quoted-printable")
	func quotedPrintableEquals() {
		let encoded = MessageFormatter.quotedPrintableEncode("a=b")
		#expect(encoded == "a=3Db")
	}

	@Test("plain ASCII text passes through unchanged")
	func quotedPrintableAscii() {
		let encoded = MessageFormatter.quotedPrintableEncode("Hello World")
		#expect(encoded == "Hello World")
	}

	// MARK: - Domain Extraction

	@Test("domain extracted from email address")
	func domainExtraction() {
		#expect(MessageFormatter.domainFromEmail("alice@example.com") == "example.com")
		#expect(MessageFormatter.domainFromEmail("user@sub.domain.org") == "sub.domain.org")
	}

	@Test("domain extraction handles missing @ gracefully")
	func domainExtractionNoAt() {
		#expect(MessageFormatter.domainFromEmail("noatsign") == "noatsign")
	}

	// MARK: - Message-ID Generation

	@Test("generated message ID contains domain")
	func messageIdGeneration() {
		let id = MessageFormatter.generateMessageId(domain: "example.com")
		#expect(id.hasSuffix("@example.com"))
		#expect(id.count > "@example.com".count)
	}

	@Test("generated message IDs are unique")
	func messageIdUniqueness() {
		let id1 = MessageFormatter.generateMessageId(domain: "example.com")
		let id2 = MessageFormatter.generateMessageId(domain: "example.com")
		#expect(id1 != id2)
	}

	// MARK: - Address Formatting

	@Test("address with name formatted as quoted name angle-bracket")
	func addressWithName() {
		let addr = EmailAddress(name: "Alice Smith", address: "alice@example.com")
		#expect(MessageFormatter.formatAddress(addr) == "\"Alice Smith\" <alice@example.com>")
	}

	@Test("address without name formatted as bare address")
	func addressWithoutName() {
		let addr = EmailAddress(address: "alice@example.com")
		#expect(MessageFormatter.formatAddress(addr) == "alice@example.com")
	}

	@Test("address with empty name formatted as bare address")
	func addressEmptyName() {
		let addr = EmailAddress(name: "", address: "alice@example.com")
		#expect(MessageFormatter.formatAddress(addr) == "alice@example.com")
	}

	// MARK: - RFC 2822 Date

	@Test("RFC 2822 date format is valid")
	func rfc2822DateFormat() {
		let dateString = MessageFormatter.formatRFC2822Date(Date())
		// Should match pattern like "Fri, 14 Mar 2026 10:30:00 +0100"
		#expect(dateString.contains(","))
		#expect(dateString.count > 20)
	}
}
