"""Tests para hoppscotch_login.

Deterministas: monkeypatchean requests.Session para no tocar la red. Simulan el
flujo magic link completo (signin -> mailpit list -> mailpit message -> verify)
y verifican que se devuelven los JWT, asi como los caminos de error.
"""

import sys

import infra.hoppscotch_login  # noqa: F401  (registra el submodulo en sys.modules)

# El __init__ del paquete rebinds el nombre `hoppscotch_login` a la funcion,
# que sombrea el submodulo. Recuperamos el submodulo real desde sys.modules
# para monkeypatchear su simbolo `requests`.
mod = sys.modules["infra.hoppscotch_login"]


class _FakeResponse:
    """Respuesta HTTP mockeada minima: status_code, json(), text."""

    def __init__(self, status_code=200, json_data=None, text=""):
        self.status_code = status_code
        self._json = json_data
        self.text = text

    def json(self):
        if self._json is None:
            raise ValueError("no json")
        return self._json


class _FakeCookies:
    def __init__(self, store):
        self._store = store

    def get(self, name):
        return self._store.get(name)


class _FakeSession:
    """Session mockeada: despacha por (method, path) a respuestas predefinidas."""

    def __init__(self, routes, cookie_store):
        self._routes = routes
        self.cookies = _FakeCookies(cookie_store)
        self.calls = []

    def _dispatch(self, method, url, **kwargs):
        self.calls.append((method, url, kwargs))
        for (m, fragment), resp in self._routes.items():
            if m == method and fragment in url:
                return resp
        raise AssertionError(f"unexpected {method} {url}")

    def post(self, url, **kwargs):
        return self._dispatch("POST", url, **kwargs)

    def get(self, url, **kwargs):
        return self._dispatch("GET", url, **kwargs)

    def close(self):
        pass


def _install_session(monkeypatch, routes, cookie_store):
    session = _FakeSession(routes, cookie_store)
    monkeypatch.setattr(mod.requests, "Session", lambda: session)
    return session


def test_golden_login_devuelve_tokens(monkeypatch):
    routes = {
        ("POST", "/v1/auth/signin"): _FakeResponse(
            201, {"deviceIdentifier": "dev-123"}
        ),
        ("GET", "/api/v1/messages"): _FakeResponse(
            200,
            {
                "messages": [
                    {
                        "ID": "msg-1",
                        "Subject": "Sign in to Hoppscotch",
                        "To": [{"Address": "admin@example.com"}],
                    }
                ]
            },
        ),
        ("GET", "/api/v1/message/msg-1"): _FakeResponse(
            200,
            {
                "Text": "Click here",
                "HTML": (
                    "<a href='http://localhost:3170/?token="
                    "eyJhbGciOi.JhbGci_Q-zz'>Sign in</a>"
                ),
            },
        ),
        ("POST", "/v1/auth/verify"): _FakeResponse(200, {"ok": True}),
    }
    _install_session(
        monkeypatch,
        routes,
        {"access_token": "ACCESS-JWT", "refresh_token": "REFRESH-JWT"},
    )

    result = mod.hoppscotch_login("admin@example.com")

    assert result["status"] == "ok"
    assert result["access_token"] == "ACCESS-JWT"
    assert result["refresh_token"] == "REFRESH-JWT"
    assert result["email"] == "admin@example.com"


def test_verify_recibe_token_extraido_y_device_identifier(monkeypatch):
    routes = {
        ("POST", "/v1/auth/signin"): _FakeResponse(
            201, {"deviceIdentifier": "dev-xyz"}
        ),
        ("GET", "/api/v1/messages"): _FakeResponse(
            200,
            {
                "messages": [
                    {
                        "ID": "m9",
                        "Subject": "Sign in",
                        "To": [{"Address": "admin@example.com"}],
                    }
                ]
            },
        ),
        ("GET", "/api/v1/message/m9"): _FakeResponse(
            200,
            {"Text": "verify at ?token=abc.DEF-123_456", "HTML": ""},
        ),
        ("POST", "/v1/auth/verify"): _FakeResponse(200, {}),
    }
    session = _install_session(
        monkeypatch, routes, {"access_token": "A", "refresh_token": "R"}
    )

    result = mod.hoppscotch_login("admin@example.com")
    assert result["status"] == "ok"

    # El POST a verify llevo el token extraido del correo + el deviceIdentifier.
    verify_call = next(
        c for c in session.calls if c[0] == "POST" and "verify" in c[1]
    )
    sent = verify_call[2]["json"]
    assert sent["token"] == "abc.DEF-123_456"
    assert sent["deviceIdentifier"] == "dev-xyz"


def test_error_signin_no_201(monkeypatch):
    routes = {
        ("POST", "/v1/auth/signin"): _FakeResponse(
            500, None, text="boom"
        ),
    }
    _install_session(monkeypatch, routes, {})

    result = mod.hoppscotch_login("admin@example.com")
    assert result["status"] == "error"
    assert "signin returned 500" in result["error"]


def test_error_correo_no_encontrado(monkeypatch):
    routes = {
        ("POST", "/v1/auth/signin"): _FakeResponse(
            201, {"deviceIdentifier": "d"}
        ),
        ("GET", "/api/v1/messages"): _FakeResponse(
            200,
            {
                "messages": [
                    {
                        "ID": "x",
                        "Subject": "Newsletter",
                        "To": [{"Address": "other@example.com"}],
                    }
                ]
            },
        ),
    }
    _install_session(monkeypatch, routes, {})

    result = mod.hoppscotch_login("admin@example.com")
    assert result["status"] == "error"
    assert "no 'Sign in' email" in result["error"]


def test_error_token_no_en_correo(monkeypatch):
    routes = {
        ("POST", "/v1/auth/signin"): _FakeResponse(
            201, {"deviceIdentifier": "d"}
        ),
        ("GET", "/api/v1/messages"): _FakeResponse(
            200,
            {
                "messages": [
                    {
                        "ID": "m",
                        "Subject": "Sign in",
                        "To": [{"Address": "admin@example.com"}],
                    }
                ]
            },
        ),
        ("GET", "/api/v1/message/m"): _FakeResponse(
            200, {"Text": "no token here", "HTML": "<p>nada</p>"}
        ),
    }
    _install_session(monkeypatch, routes, {})

    result = mod.hoppscotch_login("admin@example.com")
    assert result["status"] == "error"
    assert "token not found" in result["error"]
