"""Tests para dav_get_collection.

Smoke deterministas: monkeypatchean urllib.request.urlopen para capturar el
Request (method REPORT, Depth, auth, cuerpo del query) y devolver un XML
multistatus simulado con contenido inline. Cubren ambos perfiles (vcard / ical),
el des-escapado de entidades XML, los sinonimos de content_type, el content_type
invalido y el path de error HTTP.
"""

import base64
import sys

import infra.dav_get_collection  # noqa: F401

mod = sys.modules["infra.dav_get_collection"]
dav_get_collection = mod.dav_get_collection

# Multistatus de un addressbook-query: 2 vCards inline. El segundo contiene una
# entidad XML (&lt;) que debe des-escaparse a '<' en el campo data.
_VCARD_XML = (
    '<?xml version="1.0"?>'
    '<ns0:multistatus xmlns:ns0="DAV:" xmlns:ns1="urn:ietf:params:xml:ns:carddav">'
    "<ns0:response><ns0:href>/enmanuel/contacts/addressbook/ada.vcf</ns0:href>"
    "<ns0:propstat><ns0:status>HTTP/1.1 200 OK</ns0:status><ns0:prop>"
    '<ns0:getetag>"etag-ada"</ns0:getetag>'
    "<ns1:address-data>BEGIN:VCARD\nFN:Ada\nUID:ada\nEND:VCARD\n</ns1:address-data>"
    "</ns0:prop></ns0:propstat></ns0:response>"
    "<ns0:response><ns0:href>/enmanuel/contacts/addressbook/alan.vcf</ns0:href>"
    "<ns0:propstat><ns0:status>HTTP/1.1 200 OK</ns0:status><ns0:prop>"
    '<ns0:getetag>"etag-alan"</ns0:getetag>'
    "<ns1:address-data>BEGIN:VCARD\nFN:Alan &lt;turing&gt;\nUID:alan\nEND:VCARD\n</ns1:address-data>"
    "</ns0:prop></ns0:propstat></ns0:response>"
    "</ns0:multistatus>"
)

# Multistatus de un calendar-query: 1 VEVENT inline.
_ICAL_XML = (
    '<?xml version="1.0"?>'
    '<ns0:multistatus xmlns:ns0="DAV:" xmlns:ns1="urn:ietf:params:xml:ns:caldav">'
    "<ns0:response><ns0:href>/enmanuel/calendars/calendar/e1.ics</ns0:href>"
    "<ns0:propstat><ns0:status>HTTP/1.1 200 OK</ns0:status><ns0:prop>"
    '<ns0:getetag>"etag-e1"</ns0:getetag>'
    "<ns1:calendar-data>BEGIN:VCALENDAR\nBEGIN:VEVENT\nSUMMARY:Cita\nUID:e1\nEND:VEVENT\nEND:VCALENDAR\n</ns1:calendar-data>"
    "</ns0:prop></ns0:propstat></ns0:response>"
    "</ns0:multistatus>"
)


class _FakeResp:
    def __init__(self, payload: str):
        self._payload = payload
        self.status = 207

    def __enter__(self):
        return self

    def __exit__(self, *a):
        return False

    def read(self):
        return self._payload.encode("utf-8")


def _capture(monkeypatch, payload: str):
    captured = {}

    def fake_urlopen(req, timeout=None, context=None):
        captured["url"] = req.full_url
        captured["method"] = req.get_method()
        captured["headers"] = {k.lower(): v for k, v in req.header_items()}
        captured["body"] = req.data.decode("utf-8") if req.data else ""
        return _FakeResp(payload)

    monkeypatch.setattr(mod.urllib.request, "urlopen", fake_urlopen)
    return captured


def test_vcard_construye_report_addressbook_query(monkeypatch):
    cap = _capture(monkeypatch, _VCARD_XML)
    dav_get_collection(
        "https://dav.example.com",
        "enmanuel",
        "secret-pw",
        "/enmanuel/contacts/addressbook/",
        content_type="vcard",
    )
    assert cap["method"] == "REPORT"
    assert cap["headers"]["depth"] == "1"
    assert "addressbook-query" in cap["body"]
    assert "address-data" in cap["body"]
    assert "urn:ietf:params:xml:ns:carddav" in cap["body"]


def test_ical_construye_report_calendar_query_con_filtro(monkeypatch):
    cap = _capture(monkeypatch, _ICAL_XML)
    dav_get_collection(
        "https://dav.example.com",
        "enmanuel",
        "secret-pw",
        "/enmanuel/calendars/calendar/",
        content_type="ical",
    )
    assert cap["method"] == "REPORT"
    assert "calendar-query" in cap["body"]
    assert 'comp-filter name="VCALENDAR"' in cap["body"]
    assert "urn:ietf:params:xml:ns:caldav" in cap["body"]


def test_basic_auth_header_correcto(monkeypatch):
    cap = _capture(monkeypatch, _VCARD_XML)
    dav_get_collection(
        "https://dav.example.com",
        "enmanuel",
        "secret-pw",
        "/enmanuel/contacts/addressbook/",
    )
    expected = "Basic " + base64.b64encode(b"enmanuel:secret-pw").decode("ascii")
    assert cap["headers"]["authorization"] == expected


def test_parsea_resources_con_data_inline(monkeypatch):
    _capture(monkeypatch, _VCARD_XML)
    res = dav_get_collection(
        "https://dav.example.com",
        "enmanuel",
        "secret-pw",
        "/enmanuel/contacts/addressbook/",
    )
    assert res["status"] == "ok"
    assert len(res["resources"]) == 2
    by_href = {r["href"]: r for r in res["resources"]}
    ada = by_href["/enmanuel/contacts/addressbook/ada.vcf"]
    assert ada["etag"] == '"etag-ada"'
    assert "BEGIN:VCARD" in ada["data"]
    assert "FN:Ada" in ada["data"]


def test_desescapa_entidades_xml_del_data(monkeypatch):
    _capture(monkeypatch, _VCARD_XML)
    res = dav_get_collection(
        "https://dav.example.com",
        "enmanuel",
        "secret-pw",
        "/enmanuel/contacts/addressbook/",
    )
    alan = next(r for r in res["resources"] if r["href"].endswith("alan.vcf"))
    # &lt;turing&gt; debe quedar des-escapado a <turing>.
    assert "FN:Alan <turing>" in alan["data"]


def test_ical_parsea_calendar_data(monkeypatch):
    _capture(monkeypatch, _ICAL_XML)
    res = dav_get_collection(
        "https://dav.example.com",
        "enmanuel",
        "secret-pw",
        "/enmanuel/calendars/calendar/",
        content_type="ical",
    )
    assert res["status"] == "ok"
    assert len(res["resources"]) == 1
    assert "BEGIN:VEVENT" in res["resources"][0]["data"]


def test_acepta_sinonimos_de_content_type(monkeypatch):
    _capture(monkeypatch, _VCARD_XML)
    for alias in ("contacts", "carddav", "addressbook"):
        res = dav_get_collection(
            "https://dav.example.com",
            "enmanuel",
            "secret-pw",
            "/enmanuel/contacts/addressbook/",
            content_type=alias,
        )
        assert res["status"] == "ok"


def test_content_type_invalido_devuelve_error(monkeypatch):
    _capture(monkeypatch, _VCARD_XML)
    res = dav_get_collection(
        "https://dav.example.com",
        "enmanuel",
        "secret-pw",
        "/enmanuel/contacts/addressbook/",
        content_type="json",
    )
    assert res["status"] == "error"
    assert res["http_status"] is None


def test_httperror_devuelve_status_error(monkeypatch):
    def fake_urlopen(req, timeout=None, context=None):
        raise mod.urllib.error.HTTPError(req.full_url, 401, "Unauthorized", {}, None)

    monkeypatch.setattr(mod.urllib.request, "urlopen", fake_urlopen)
    res = dav_get_collection(
        "https://dav.example.com",
        "enmanuel",
        "secret-pw",
        "/enmanuel/contacts/addressbook/",
    )
    assert res["status"] == "error"
    assert res["http_status"] == 401
