"""
Test unitari per app.parsers.receipt_extractor.

Copertura:
  - Estrazione EML annidato (message/rfc822) da ricevuta PEC
  - Campi estratti dall'EML annidato (message_id, subject, from, to)
  - Estrazione XML strutturato (daticert.xml)
  - Messaggio senza EML annidato (ritorna None)
  - Messaggio non-multipart (ritorna None)
  - Payload come lista di Message (forma canonica RFC)
  - Payload come bytes/stringa
  - Ricevute di tutti i tipi (accettazione, avvenuta-consegna, ecc.)
"""

import email

import pytest

from app.parsers.receipt_extractor import (
    NestedEmlInfo,
    extract_nested_eml,
    extract_receipt_xml,
)


# ─── Fixture EML ──────────────────────────────────────────────────────────────

# Ricevuta di accettazione (Aruba style) con EML annidato
ACCETTAZIONE_EML = b"""\
From: posta-certificata@pec.aruba.it
To: mittente@pec.it
Subject: ACCETTAZIONE: Test PEC
X-Ricevuta: accettazione
X-Riferimento-Message-ID: <orig-001@pec.it>
Date: Wed, 18 Mar 2026 14:01:00 +0100
Content-Type: multipart/mixed; boundary="====acc===="

--====acc====
Content-Type: text/plain; charset=utf-8

Il messaggio e' stato accettato dal gestore.

--====acc====
Content-Type: application/xml; name="daticert.xml"
Content-Disposition: attachment; filename="daticert.xml"

<?xml version="1.0" encoding="UTF-8"?>
<PostaCertificata versione="2.3">
  <Intestazione>
    <Identificativo>acc-12345</Identificativo>
    <TipoRicevuta>accettazione</TipoRicevuta>
  </Intestazione>
</PostaCertificata>

--====acc====
Content-Type: message/rfc822
Content-Disposition: inline

From: mittente@pec.it
To: destinatario@pec.it
Subject: Test PEC originale
Message-ID: <orig-001@pec.it>
Date: Wed, 18 Mar 2026 14:00:00 +0100
Content-Type: text/plain; charset=utf-8

Corpo del messaggio originale inviato.

--====acc====--
"""

# Ricevuta di avvenuta consegna con EML annidato
AVVENUTA_CONSEGNA_EML = b"""\
From: posta-certificata@pec.aruba.it
To: mittente@pec.it
Subject: CONSEGNA: Test PEC
X-Ricevuta: avvenuta-consegna
X-Riferimento-Message-ID: <orig-002@pec.it>
Date: Wed, 18 Mar 2026 14:10:00 +0100
Content-Type: multipart/mixed; boundary="====cons===="

--====cons====
Content-Type: text/plain; charset=utf-8

Il messaggio e' stato consegnato al destinatario.

--====cons====
Content-Type: application/xml; name="daticert.xml"
Content-Disposition: attachment; filename="daticert.xml"

<?xml version="1.0"?><PostaCertificata versione="2.3"/>

--====cons====
Content-Type: message/rfc822
Content-Disposition: inline

From: mittente@pec.it
To: destinatario@pec.it
Subject: Test PEC originale
Message-ID: <orig-002@pec.it>
Date: Wed, 18 Mar 2026 14:00:00 +0100
Content-Type: text/plain; charset=utf-8

Corpo originale.

--====cons====--
"""

# Messaggio PEC originale (non ricevuta, senza EML annidato)
POSTA_CERTIFICATA_EML = b"""\
From: mittente@pec.it
To: destinatario@pec.it
Subject: Messaggio PEC originale
Message-ID: <msg-123@pec.it>
Date: Wed, 18 Mar 2026 14:00:00 +0100
Content-Type: text/plain; charset=utf-8

Questo e' il corpo del messaggio PEC.
"""

# Messaggio multipart senza EML annidato
MULTIPART_NO_NESTED = b"""\
From: a@pec.it
To: b@pec.it
Subject: PEC con allegato PDF (nessun EML annidato)
Date: Wed, 18 Mar 2026 10:00:00 +0100
Content-Type: multipart/mixed; boundary="====notest===="

--====notest====
Content-Type: text/plain; charset=utf-8

Corpo.

--====notest====
Content-Type: application/pdf; name="doc.pdf"
Content-Disposition: attachment; filename="doc.pdf"
Content-Transfer-Encoding: base64

JVBERi0xLjQ=

--====notest====--
"""

# Ricevuta di mancata consegna con EML annidato (Namirial style)
MANCATA_CONSEGNA_EML = b"""\
From: no-reply@namirial.com
To: mittente@pec.it
Subject: MANCATA CONSEGNA: Test
X-TipoRicevuta: mancata-consegna
X-Riferimento-Message-ID: <orig-003@pec.namirial.it>
Date: Wed, 18 Mar 2026 15:00:00 +0100
Content-Type: multipart/mixed; boundary="====mc===="

--====mc====
Content-Type: text/plain; charset=utf-8

Il messaggio non e' stato consegnato.

--====mc====
Content-Type: message/rfc822
Content-Disposition: inline

From: mittente@pec.namirial.it
To: destinatario@pec.it
Subject: Messaggio non consegnato
Message-ID: <orig-003@pec.namirial.it>
Date: Wed, 18 Mar 2026 14:30:00 +0100
Content-Type: text/plain; charset=utf-8

Corpo originale che non e' stato consegnato.

--====mc====--
"""


# ─── Test extract_nested_eml ──────────────────────────────────────────────────


class TestExtractNestedEml:

    def test_accettazione_eml_annidato_trovato(self):
        msg = email.message_from_bytes(ACCETTAZIONE_EML)
        result = extract_nested_eml(msg)
        assert result is not None

    def test_accettazione_message_id(self):
        msg = email.message_from_bytes(ACCETTAZIONE_EML)
        result = extract_nested_eml(msg)
        assert result is not None
        assert result.message_id == "<orig-001@pec.it>"

    def test_accettazione_subject(self):
        msg = email.message_from_bytes(ACCETTAZIONE_EML)
        result = extract_nested_eml(msg)
        assert result is not None
        assert result.subject == "Test PEC originale"

    def test_accettazione_from_address(self):
        msg = email.message_from_bytes(ACCETTAZIONE_EML)
        result = extract_nested_eml(msg)
        assert result is not None
        assert result.from_address == "mittente@pec.it"

    def test_accettazione_to_addresses(self):
        msg = email.message_from_bytes(ACCETTAZIONE_EML)
        result = extract_nested_eml(msg)
        assert result is not None
        assert "destinatario@pec.it" in result.to_addresses

    def test_accettazione_raw_bytes_non_vuoti(self):
        msg = email.message_from_bytes(ACCETTAZIONE_EML)
        result = extract_nested_eml(msg)
        assert result is not None
        assert len(result.raw_bytes) > 0

    def test_avvenuta_consegna_eml_trovato(self):
        msg = email.message_from_bytes(AVVENUTA_CONSEGNA_EML)
        result = extract_nested_eml(msg)
        assert result is not None
        assert result.message_id == "<orig-002@pec.it>"

    def test_mancata_consegna_namirial(self):
        """Test con ricevuta Namirial (X-TipoRicevuta)."""
        msg = email.message_from_bytes(MANCATA_CONSEGNA_EML)
        result = extract_nested_eml(msg)
        assert result is not None
        assert result.message_id == "<orig-003@pec.namirial.it>"
        assert result.subject == "Messaggio non consegnato"

    def test_messaggio_non_multipart_ritorna_none(self):
        """Un messaggio non-multipart non può avere EML annidato."""
        msg = email.message_from_bytes(POSTA_CERTIFICATA_EML)
        result = extract_nested_eml(msg)
        assert result is None

    def test_multipart_senza_nested_ritorna_none(self):
        """Un multipart senza parti message/rfc822 ritorna None."""
        msg = email.message_from_bytes(MULTIPART_NO_NESTED)
        result = extract_nested_eml(msg)
        assert result is None

    def test_risultato_e_nested_eml_info(self):
        msg = email.message_from_bytes(ACCETTAZIONE_EML)
        result = extract_nested_eml(msg)
        assert isinstance(result, NestedEmlInfo)

    def test_raw_bytes_e_valido_eml(self):
        """I raw_bytes estratti devono essere un EML valido (ri-parsabile)."""
        msg = email.message_from_bytes(ACCETTAZIONE_EML)
        result = extract_nested_eml(msg)
        assert result is not None
        # Verifica che i bytes siano ri-parsabili
        inner = email.message_from_bytes(result.raw_bytes)
        assert inner.get("Message-ID") == "<orig-001@pec.it>"


# ─── Test extract_receipt_xml ─────────────────────────────────────────────────


class TestExtractReceiptXml:

    def test_daticert_xml_estratto(self):
        msg = email.message_from_bytes(ACCETTAZIONE_EML)
        xml = extract_receipt_xml(msg)
        assert xml is not None
        assert "PostaCertificata" in xml

    def test_xml_con_contenuto(self):
        msg = email.message_from_bytes(ACCETTAZIONE_EML)
        xml = extract_receipt_xml(msg)
        assert xml is not None
        assert "accettazione" in xml.lower()

    def test_xml_avvenuta_consegna(self):
        msg = email.message_from_bytes(AVVENUTA_CONSEGNA_EML)
        xml = extract_receipt_xml(msg)
        assert xml is not None
        assert "PostaCertificata" in xml

    def test_messaggio_senza_xml_ritorna_none(self):
        """Un messaggio PEC senza allegato XML ritorna None."""
        msg = email.message_from_bytes(POSTA_CERTIFICATA_EML)
        xml = extract_receipt_xml(msg)
        assert xml is None

    def test_multipart_senza_xml_ritorna_none(self):
        """Multipart con solo PDF, senza XML."""
        msg = email.message_from_bytes(MULTIPART_NO_NESTED)
        xml = extract_receipt_xml(msg)
        assert xml is None

    def test_mancata_consegna_senza_xml_ritorna_none(self):
        """Alcune ricevute (Namirial) non hanno daticert.xml."""
        msg = email.message_from_bytes(MANCATA_CONSEGNA_EML)
        xml = extract_receipt_xml(msg)
        # Questa ricevuta non ha XML allegato → None
        assert xml is None


# ─── Test NestedEmlInfo dataclass ─────────────────────────────────────────────


class TestNestedEmlInfoDataclass:

    def test_campi_base(self):
        info = NestedEmlInfo(
            raw_bytes=b"raw",
            message_id="<test@pec.it>",
            subject="Test",
            from_address="a@pec.it",
            to_addresses=["b@pec.it"],
        )
        assert info.raw_bytes == b"raw"
        assert info.message_id == "<test@pec.it>"
        assert info.subject == "Test"
        assert info.from_address == "a@pec.it"
        assert "b@pec.it" in info.to_addresses

    def test_to_addresses_default_lista_vuota(self):
        info = NestedEmlInfo(
            raw_bytes=b"",
            message_id=None,
            subject=None,
            from_address=None,
        )
        assert info.to_addresses == []

    def test_campi_opzionali_possono_essere_none(self):
        info = NestedEmlInfo(
            raw_bytes=b"data",
            message_id=None,
            subject=None,
            from_address=None,
        )
        assert info.message_id is None
        assert info.subject is None
        assert info.from_address is None


# ─── Test integrazione pec_parser + receipt_extractor ────────────────────────


class TestIntegrationPecParserAndExtractor:
    """
    Verifica che le informazioni estratte da receipt_extractor corrispondano
    al X-Riferimento-Message-ID usato da pec_parser per collegare i messaggi.
    """

    def test_riferimento_corrisponde_a_message_id_annidato(self):
        """
        X-Riferimento-Message-ID nella ricevuta deve corrispondere
        al Message-ID dell'EML annidato.
        """
        from app.parsers.pec_parser import classify_pec_message

        msg = email.message_from_bytes(ACCETTAZIONE_EML)

        # Classifica la ricevuta
        pec_class = classify_pec_message(msg)
        assert pec_class.riferimento_message_id == "<orig-001@pec.it>"

        # Estrae EML annidato
        nested = extract_nested_eml(msg)
        assert nested is not None
        assert nested.message_id == "<orig-001@pec.it>"

        # Deve corrispondere
        assert pec_class.riferimento_message_id == nested.message_id

    def test_avvenuta_consegna_corrispondenza_completa(self):
        from app.parsers.pec_parser import classify_pec_message

        msg = email.message_from_bytes(AVVENUTA_CONSEGNA_EML)

        pec_class = classify_pec_message(msg)
        assert pec_class.pec_type == "avvenuta_consegna"
        assert pec_class.riferimento_message_id == "<orig-002@pec.it>"

        nested = extract_nested_eml(msg)
        assert nested is not None
        assert nested.message_id == "<orig-002@pec.it>"

    def test_mancata_consegna_namirial_corrispondenza(self):
        from app.parsers.pec_parser import classify_pec_message

        msg = email.message_from_bytes(MANCATA_CONSEGNA_EML)

        pec_class = classify_pec_message(msg)
        assert pec_class.pec_type == "mancata_consegna"
        assert pec_class.riferimento_message_id == "<orig-003@pec.namirial.it>"

        nested = extract_nested_eml(msg)
        assert nested is not None
        assert nested.message_id == "<orig-003@pec.namirial.it>"
