"""GET request JSON — HTTP client sin dependencias externas."""

import json
import urllib.error
import urllib.parse
import urllib.request


def http_get_json(
    url: str,
    headers: dict[str, str] | None = None,
    params: dict[str, str] | None = None,
    timeout: float = 30.0,
) -> dict:
    """Realiza un GET request y parsea la respuesta como JSON.

    Agrega automaticamente el header ``Accept: application/json``.
    Si el status es >= 400 lanza RuntimeError con status code, url y
    los primeros 200 caracteres del body para facilitar el debugging.

    Args:
        url: URL del endpoint.
        headers: Headers HTTP adicionales. Se fusionan con Accept por defecto.
        params: Query string params. Se serializa con urllib.parse.urlencode.
        timeout: Segundos maximo de espera (default 30).

    Returns:
        Respuesta parseada como dict o list.

    Raises:
        RuntimeError: Si status >= 400 o si el body no es JSON valido.
    """
    if params:
        url = f"{url}?{urllib.parse.urlencode(params)}"

    all_headers: dict[str, str] = {"Accept": "application/json"}
    if headers:
        all_headers.update(headers)

    req = urllib.request.Request(url, headers=all_headers, method="GET")

    try:
        with urllib.request.urlopen(req, timeout=timeout) as resp:
            raw = resp.read()
    except urllib.error.HTTPError as e:
        body_preview = e.read(200).decode("utf-8", errors="replace")
        short_url = url[:100] if len(url) > 100 else url
        raise RuntimeError(
            f"http_get_json: HTTP {e.code} at {short_url!r} — {body_preview}"
        ) from e

    try:
        return json.loads(raw)
    except json.JSONDecodeError as e:
        preview = raw[:200].decode("utf-8", errors="replace")
        raise RuntimeError(
            f"http_get_json: response is not valid JSON — {preview}"
        ) from e
