"""Tests para hoppscotch_set_environment.

Deterministas: monkeypatchean requests.post (capa de red) y pass_get_secret.
Verifican crear vs actualizar (idempotencia por nombre), resolucion de secretos
`pass:` (fuerza secret=True, key en resolved_secrets, valor crudo fuera del
output), y abortar sin llamar la mutation si pass falla.

Hay un test e2e real marcado skip por defecto (self-host vivo).
"""

import json
import sys

import pytest

import infra.hoppscotch_set_environment  # noqa: F401

# El __init__ rebinds el nombre a la funcion; recuperamos el submodulo real.
mod = sys.modules["infra.hoppscotch_set_environment"]


class _FakeResponse:
    def __init__(self, status_code=200, json_data=None):
        self.status_code = status_code
        self._json = json_data

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


def _make_post(call_log, list_envs, mutation_result):
    """Construye un fake requests.post que distingue listado de mutation.

    El listado lleva 'teamEnvironments' en la query; cualquier otra es mutation.
    Cada llamada se registra en call_log para inspeccion.
    """

    def fake_post(url, **kwargs):
        payload = kwargs["json"]
        query = payload["query"]
        call_log.append({"url": url, "kwargs": kwargs, "query": query})
        if "teamEnvironments" in query:
            return _FakeResponse(
                200, {"data": {"team": {"teamEnvironments": list_envs}}}
            )
        # mutation (create o update)
        field = (
            "updateTeamEnvironment"
            if "updateTeamEnvironment" in query
            else "createTeamEnvironment"
        )
        return _FakeResponse(200, {"data": {field: mutation_result}})

    return fake_post


def test_crea_cuando_no_existe(monkeypatch):
    calls = []
    monkeypatch.setattr(
        mod.requests,
        "post",
        _make_post(calls, list_envs=[], mutation_result={"id": "env-1", "name": "test_env"}),
    )

    result = mod.hoppscotch_set_environment(
        "team-1",
        "test_env",
        [{"key": "foo", "value": "bar", "secret": False}],
        access_token="ACCESS-JWT",
    )

    assert result["status"] == "ok"
    assert result["id"] == "env-1"
    assert result["action"] == "created"
    assert result["resolved_secrets"] == []

    # Segunda llamada = mutation createTeamEnvironment con las variables.
    mutation = calls[1]
    assert "createTeamEnvironment" in mutation["query"]
    assert mutation["kwargs"]["cookies"] == {"access_token": "ACCESS-JWT"}
    gql_vars = mutation["kwargs"]["json"]["variables"]
    assert gql_vars["n"] == "test_env"
    assert gql_vars["t"] == "team-1"
    sent_vars = json.loads(gql_vars["v"])
    assert sent_vars == [{"key": "foo", "value": "bar", "secret": False}]


def test_actualiza_cuando_existe(monkeypatch):
    calls = []
    monkeypatch.setattr(
        mod.requests,
        "post",
        _make_post(
            calls,
            list_envs=[{"id": "env-existing", "name": "test_env"}],
            mutation_result={"id": "env-existing", "name": "test_env"},
        ),
    )

    result = mod.hoppscotch_set_environment(
        "team-1",
        "test_env",
        [{"key": "foo", "value": "bar"}],
        access_token="A",
    )

    assert result["status"] == "ok"
    assert result["id"] == "env-existing"
    assert result["action"] == "updated"

    mutation = calls[1]
    assert "updateTeamEnvironment" in mutation["query"]
    gql_vars = mutation["kwargs"]["json"]["variables"]
    assert gql_vars["id"] == "env-existing"


def test_resuelve_secreto_desde_pass(monkeypatch):
    calls = []
    monkeypatch.setattr(
        mod.requests,
        "post",
        _make_post(calls, list_envs=[], mutation_result={"id": "env-2", "name": "e"}),
    )

    def fake_pass(path, **kwargs):
        assert path == "apis/lpd"
        return {"status": "ok", "value": "TOP-SECRET-VALUE"}

    monkeypatch.setattr(mod, "pass_get_secret", fake_pass)

    result = mod.hoppscotch_set_environment(
        "team-1",
        "e",
        [
            {"key": "plain", "value": "visible", "secret": False},
            {"key": "apikey", "value": "pass:apis/lpd", "secret": False},
        ],
        access_token="A",
    )

    assert result["status"] == "ok"
    # El key resuelto aparece, pero NUNCA el valor crudo.
    assert result["resolved_secrets"] == ["apikey"]
    assert "TOP-SECRET-VALUE" not in json.dumps(result)

    # La variable resuelta viaja con el valor real y secret=True forzado.
    mutation = calls[1]
    sent_vars = json.loads(mutation["kwargs"]["json"]["variables"]["v"])
    by_key = {v["key"]: v for v in sent_vars}
    assert by_key["apikey"]["value"] == "TOP-SECRET-VALUE"
    assert by_key["apikey"]["secret"] is True
    assert by_key["plain"]["value"] == "visible"
    assert by_key["plain"]["secret"] is False


def test_error_pass_no_llama_mutation(monkeypatch):
    calls = []

    def fake_post(url, **kwargs):
        calls.append(kwargs["json"]["query"])
        return _FakeResponse(200, {"data": {"team": {"teamEnvironments": []}}})

    monkeypatch.setattr(mod.requests, "post", fake_post)

    def fake_pass(path, **kwargs):
        return {"status": "error", "error": "pass not installed"}

    monkeypatch.setattr(mod, "pass_get_secret", fake_pass)

    result = mod.hoppscotch_set_environment(
        "team-1",
        "e",
        [{"key": "apikey", "value": "pass:apis/lpd"}],
        access_token="A",
    )

    assert result["status"] == "error"
    assert "apikey" in result["error"]
    # No se hizo ninguna llamada de red (ni listado ni mutation): aborta antes.
    assert calls == []


@pytest.mark.skip(reason="e2e real contra self-host vivo")
def test_e2e_create_then_update_live():
    """End-to-end real contra el Hoppscotch self-host vivo.

    login -> set_environment("test_env") -> created -> set_environment de nuevo
    -> updated. Limpia el env al final con deleteTeamEnvironment.
    """
    sys.path.insert(0, "python/functions")
    from infra.hoppscotch_login import hoppscotch_login
    import requests

    team_id = "cmq8kn0v500030xls1nvminjy"
    token = hoppscotch_login("admin@example.com")["access_token"]

    first = mod.hoppscotch_set_environment(
        team_id,
        "test_env",
        [{"key": "foo", "value": "bar", "secret": False}],
        access_token=token,
    )
    assert first["status"] == "ok"
    assert first["action"] == "created"
    env_id = first["id"]

    second = mod.hoppscotch_set_environment(
        team_id,
        "test_env",
        [{"key": "foo", "value": "baz", "secret": False}],
        access_token=token,
    )
    assert second["status"] == "ok"
    assert second["action"] == "updated"
    assert second["id"] == env_id

    # Cleanup: borra el env de prueba.
    del_q = "mutation($id:ID!){ deleteTeamEnvironment(id:$id) }"
    requests.post(
        "http://localhost:3170/graphql",
        json={"query": del_q, "variables": {"id": env_id}},
        cookies={"access_token": token},
        timeout=15.0,
    )
