"""Tests para hoppscotch_run_request.

Deterministas: monkeypatchean requests.request (ejecucion HTTP) y requests.post
(mutation createUserHistory). Verifican la resolucion de placedores `<<>>`/`{{}}`
para EJECUTAR, que el History recibe la request SIN resolver, y los caminos de
record_history=False y de error de transporte.
"""

import json
import sys
from datetime import timedelta

import infra.hoppscotch_run_request  # noqa: F401

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


class _FakeResponse:
    """Respuesta minima para requests.request (ejecucion)."""

    def __init__(self, status_code=200, text="OK", headers=None, elapsed_ms=12):
        self.status_code = status_code
        self.text = text
        self.headers = headers or {"Content-Type": "text/plain"}
        self.elapsed = timedelta(milliseconds=elapsed_ms)


class _FakeGraphQLResponse:
    """Respuesta minima para requests.post (createUserHistory)."""

    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 _patch_history_ok(monkeypatch, captured):
    def fake_post(url, **kwargs):
        captured["history_url"] = url
        captured["history_kwargs"] = kwargs
        return _FakeGraphQLResponse(
            200, {"data": {"createUserHistory": {"id": "hist-42"}}}
        )

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


def test_ejecuta_resolviendo_variables_angle(monkeypatch):
    captured = {}

    def fake_request(method, url, **kwargs):
        captured["method"] = method
        captured["url"] = url
        captured["kwargs"] = kwargs
        return _FakeResponse(200, text="pong")

    monkeypatch.setattr(mod.requests, "request", fake_request)
    _patch_history_ok(monkeypatch, captured)

    result = mod.hoppscotch_run_request(
        "GET",
        "<<baseURL>>/x",
        variables={"baseURL": "https://h"},
        access_token="A",
    )

    # La request ejecutada lleva la url resuelta.
    assert captured["url"] == "https://h/x"
    assert result["status"] == "ok"
    assert result["status_code"] == 200
    assert result["response_body"] == "pong"
    assert result["duration_ms"] == 12


def test_ejecuta_resolviendo_variables_brace(monkeypatch):
    captured = {}

    def fake_request(method, url, **kwargs):
        captured["url"] = url
        return _FakeResponse(200)

    monkeypatch.setattr(mod.requests, "request", fake_request)
    _patch_history_ok(monkeypatch, captured)

    mod.hoppscotch_run_request(
        "GET",
        "{{baseURL}}/x",
        variables={"baseURL": "https://h"},
        access_token="A",
    )

    # {{var}} resuelve igual que <<var>>.
    assert captured["url"] == "https://h/x"


def test_record_history_registra_request_sin_resolver(monkeypatch):
    captured = {}

    def fake_request(method, url, **kwargs):
        return _FakeResponse(200, text="body", headers={"X-Test": "1"})

    monkeypatch.setattr(mod.requests, "request", fake_request)
    _patch_history_ok(monkeypatch, captured)

    result = mod.hoppscotch_run_request(
        "GET",
        "<<baseURL>>/api/status",
        title="Status",
        variables={"baseURL": "https://h"},
        access_token="ACCESS-JWT",
        record_history=True,
    )

    assert result["recorded"] is True
    assert result["history_id"] == "hist-42"

    # El POST de History fue al endpoint GraphQL con la cookie access_token.
    assert captured["history_url"].endswith("/graphql")
    assert captured["history_kwargs"]["cookies"] == {"access_token": "ACCESS-JWT"}

    payload = captured["history_kwargs"]["json"]
    assert "createUserHistory" in payload["query"]
    variables = payload["variables"]
    assert variables["t"] == "REST"

    # reqData es el json string de un HoppRESTRequest v:"2" con la url SIN resolver.
    req = json.loads(variables["d"])
    assert req["v"] == "2"
    assert req["method"] == "GET"
    assert req["endpoint"] == "<<baseURL>>/api/status"
    assert req["name"] == "Status"

    # resMetadata minimo: statusCode + duration.
    res_meta = json.loads(variables["m"])
    assert res_meta == {"statusCode": 200, "duration": 12}


def test_record_history_false_no_llama_create_user_history(monkeypatch):
    calls = {"post": 0}

    def fake_request(method, url, **kwargs):
        return _FakeResponse(200)

    def fake_post(url, **kwargs):
        calls["post"] += 1
        return _FakeGraphQLResponse(200, {"data": {"createUserHistory": {"id": "x"}}})

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

    result = mod.hoppscotch_run_request(
        "GET",
        "https://h/x",
        access_token="A",
        record_history=False,
    )

    assert result["recorded"] is False
    assert result["history_id"] is None
    assert calls["post"] == 0


def test_request_exception_status_error(monkeypatch):
    def fake_request(method, url, **kwargs):
        raise mod.requests.RequestException("boom")

    # Si llegara a postear seria un fallo del test: no debe.
    def fake_post(url, **kwargs):
        raise AssertionError("no debe registrar history si la ejecucion fallo")

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

    result = mod.hoppscotch_run_request(
        "GET", "https://h/x", access_token="A"
    )

    assert result["status"] == "error"
    assert result["recorded"] is False
    assert "boom" in result["error"]


def test_variable_faltante_conserva_literal(monkeypatch):
    captured = {}

    def fake_request(method, url, **kwargs):
        captured["url"] = url
        return _FakeResponse(200)

    monkeypatch.setattr(mod.requests, "request", fake_request)
    _patch_history_ok(monkeypatch, captured)

    mod.hoppscotch_run_request(
        "GET",
        "<<baseURL>>/x",
        variables={"otra": "y"},
        access_token="A",
    )

    # baseURL no esta en variables -> el literal se conserva.
    assert captured["url"] == "<<baseURL>>/x"
