import Testing
@testable import IMailSync

@Suite("MIMEParser")
struct MIMEParserTests {

    // MARK: - Header parsing

    @Test("Parses Message-ID stripping angle brackets")
    func messageId() {
        let raw = """
        Message-ID: <abc123@mail.example.com>
        Subject: Hello

        Body
        """
        let msg = MIMEParser.parse(raw)
        #expect(msg.messageId == "abc123@mail.example.com")
    }

    @Test("Parses basic text/plain message")
    func plainTextBody() {
        let raw = """
        Content-Type: text/plain; charset=utf-8
        Subject: Test

        Hello, world!
        """
        let msg = MIMEParser.parse(raw)
        #expect(msg.text?.trimmingCharacters(in: .whitespacesAndNewlines) == "Hello, world!")
        #expect(msg.html == nil)
    }

    @Test("Parses From header into address and name")
    func fromHeader() {
        let raw = """
        From: Quinn Test <quinn@example.com>

        """
        let msg = MIMEParser.parse(raw)
        #expect(msg.from?.address == "quinn@example.com")
        #expect(msg.from?.name == "Quinn Test")
    }

    @Test("Parses bare email address in From")
    func fromHeaderBare() {
        let raw = """
        From: quinn@example.com

        """
        let msg = MIMEParser.parse(raw)
        #expect(msg.from?.address == "quinn@example.com")
        #expect(msg.from?.name == nil)
    }

    @Test("Parses multiple To recipients")
    func toRecipients() {
        let raw = """
        To: Alice <alice@example.com>, bob@example.com

        """
        let msg = MIMEParser.parse(raw)
        #expect(msg.to.count == 2)
        #expect(msg.to[0].address == "alice@example.com")
        #expect(msg.to[0].name == "Alice")
        #expect(msg.to[1].address == "bob@example.com")
        #expect(msg.to[1].name == nil)
    }

    // MARK: - Multipart

    @Test("Extracts text and html from multipart/alternative")
    func multipartAlternative() {
        let boundary = "----=_Part_1"
        let raw = """
        Content-Type: multipart/alternative; boundary="\(boundary)"

        --\(boundary)
        Content-Type: text/plain; charset=utf-8

        Plain text body

        --\(boundary)
        Content-Type: text/html; charset=utf-8

        <html><body>HTML body</body></html>

        --\(boundary)--
        """
        let msg = MIMEParser.parse(raw)
        #expect(msg.text?.contains("Plain text body") == true)
        #expect(msg.html?.contains("HTML body") == true)
    }

    @Test("Detects attachments in multipart/mixed")
    func multipartMixedAttachment() {
        let boundary = "----=_Part_2"
        let raw = """
        Content-Type: multipart/mixed; boundary="\(boundary)"

        --\(boundary)
        Content-Type: text/plain

        Message body

        --\(boundary)
        Content-Type: application/pdf
        Content-Disposition: attachment; filename="file.pdf"

        <binary>

        --\(boundary)--
        """
        let msg = MIMEParser.parse(raw)
        #expect(msg.hasAttachments == true)
    }

    // MARK: - RFC 2047

    @Test("Decodes Base64-encoded RFC 2047 subject")
    func rfc2047Base64() {
        // =?UTF-8?B?SGVsbG8gV29ybGQ=?= decodes to "Hello World"
        let raw = """
        Subject: =?UTF-8?B?SGVsbG8gV29ybGQ=?=

        """
        let msg = MIMEParser.parse(raw)
        #expect(msg.subject == "Hello World")
    }

    @Test("Decodes Q-encoded RFC 2047 subject")
    func rfc2047QEncoded() {
        // =?iso-8859-1?Q?Caf=E9?= decodes to "Café"
        let raw = """
        Subject: =?iso-8859-1?Q?Caf=E9?=

        """
        let msg = MIMEParser.parse(raw)
        #expect(msg.subject?.hasPrefix("Caf") == true)
    }

    // MARK: - References

    @Test("Parses References header into array")
    func referencesHeader() {
        let raw = """
        References: <ref1@example.com> <ref2@example.com>

        """
        let msg = MIMEParser.parse(raw)
        #expect(msg.references.count == 2)
        #expect(msg.references[0] == "ref1@example.com")
        #expect(msg.references[1] == "ref2@example.com")
    }

    @Test("Parses In-Reply-To stripping angle brackets")
    func inReplyTo() {
        let raw = """
        In-Reply-To: <parent@example.com>

        """
        let msg = MIMEParser.parse(raw)
        #expect(msg.inReplyTo == "parent@example.com")
    }
}
