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

import json
import urllib.error
import urllib.request


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

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

    Args:
        url: URL del endpoint.
        body: Datos a serializar como JSON en el cuerpo del request.
        headers: Headers HTTP adicionales. Se fusionan con los defaults.
        timeout: Segundos maximo de espera (default 30).

    Returns:
        Respuesta parseada como dict o list.

    Raises:
        RuntimeError: Si status >= 400 o si el body de respuesta no es JSON valido.
    """
    all_headers: dict[str, str] = {
        "Content-Type": "application/json",
        "Accept": "application/json",
    }
    if headers:
        all_headers.update(headers)

    data = json.dumps(body, ensure_ascii=False).encode("utf-8")
    req = urllib.request.Request(url, data=data, headers=all_headers, method="POST")

    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_post_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_post_json: response is not valid JSON — {preview}"
        ) from e
