"""CSJN API client — zero dependencies beyond stdlib.

Queries sjconsulta.csjn.gov.ar for sumarios (summaries) of Argentine Supreme Court
rulings. Session-based: GET consultation page for cookie, POST search, GET JSON results.
No captcha required for sumarios (fallos completos need reCAPTCHA Enterprise).
"""

from __future__ import annotations

import html as html_mod
import http.cookiejar
import json
import re
import urllib.error
import urllib.parse
import urllib.request
from datetime import datetime, timezone
from typing import Any

BASE_URL = "https://sjconsulta.csjn.gov.ar/sjconsulta"
CONSULTA_URL = f"{BASE_URL}/consultaSumarios/consulta.html"
BUSCAR_URL = f"{BASE_URL}/consultaSumarios/buscar.html"
PAGINAR_URL = f"{BASE_URL}/consultaSumarios/paginarSumarios.html"
ANALISIS_URL = f"{BASE_URL}/sumarios/abrirAnalisis.html"
VOCES_URL = f"{BASE_URL}/autocomplete/getVoces.html"

USER_AGENT = (
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
    "(KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36"
)


class CSJNError(Exception):
    pass


def _make_opener() -> tuple[urllib.request.OpenerDirector, http.cookiejar.CookieJar]:
    jar = http.cookiejar.CookieJar()
    opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jar))
    opener.addheaders = [("User-Agent", USER_AGENT)]
    return opener, jar


def _init_session(opener: urllib.request.OpenerDirector) -> None:
    try:
        opener.open(CONSULTA_URL, timeout=15)
    except urllib.error.URLError as e:
        raise CSJNError(f"Failed to init session: {e}") from e


def _strip_html(text: str) -> str:
    clean = re.sub(r"<[^>]+>", "", text)
    return html_mod.unescape(clean).strip()


def _epoch_to_date(epoch_ms: int | None) -> str | None:
    if not epoch_ms:
        return None
    try:
        dt = datetime.fromtimestamp(epoch_ms / 1000, tz=timezone.utc)
        return dt.strftime("%d/%m/%Y")
    except (ValueError, OSError):
        return None


def _extract_valor(obj: dict | None) -> str | None:
    if obj and isinstance(obj, dict):
        return obj.get("valor")
    return None


def _clean_result(r: dict) -> dict:
    out: dict[str, Any] = {
        "id": r.get("id"),
        "voces": r.get("voces", ""),
        "texto": _strip_html(r.get("texto", "")),
        "autos": r.get("autos") or r.get("caratulaWeb", ""),
        "fecha": r.get("fechaString") or _epoch_to_date(r.get("fechaFallo")),
        "tomo": r.get("tomo"),
        "pagina": r.get("pagina"),
        "expediente": r.get("numeroExpediente", ""),
        "id_fallo": r.get("idFallo"),
    }
    if r.get("sentenciaArbitraria"):
        out["sentencia_arbitraria"] = True
    if r.get("inconstitucional"):
        out["inconstitucional"] = True
    if r.get("holding"):
        out["holding"] = True
    if r.get("anioFallo"):
        out["anio"] = r["anioFallo"]
    if r.get("numeroID"):
        out["numero_id"] = r["numeroID"]
    return out


def search(
    query: str,
    *,
    autos: str = "",
    fecha_exacta: str = "",
    fecha_desde: str = "",
    fecha_hasta: str = "",
    limit: int = 10,
) -> dict[str, Any]:
    opener, _ = _make_opener()
    _init_session(opener)

    params = urllib.parse.urlencode({
        "filter.fullText": query,
        "filter.autos": autos,
        "filter.fechaExacta": fecha_exacta,
        "filter.fechaDesde": fecha_desde,
        "filter.fechaHasta": fecha_hasta,
    }).encode()

    req = urllib.request.Request(
        BUSCAR_URL,
        data=params,
        headers={
            "Content-Type": "application/x-www-form-urlencoded",
            "Referer": CONSULTA_URL,
        },
    )
    try:
        resp = opener.open(req, timeout=20)
        html = resp.read().decode("utf-8", errors="replace")
    except urllib.error.URLError as e:
        raise CSJNError(f"Search failed: {e}") from e

    m = re.search(r'totalResultados\s*=\s*"(\d+)"', html)
    total = int(m.group(1)) if m else 0

    if total == 0:
        return {"total": 0, "query": query, "results": []}

    results = []
    start = 0
    while len(results) < limit and start < total:
        pag_url = f"{PAGINAR_URL}?startIndex={start}"
        pag_req = urllib.request.Request(
            pag_url,
            headers={"X-Requested-With": "XMLHttpRequest"},
        )
        try:
            pag_resp = opener.open(pag_req, timeout=20)
            page_data = json.loads(pag_resp.read().decode("utf-8"))
        except (urllib.error.URLError, json.JSONDecodeError) as e:
            raise CSJNError(f"Pagination failed at offset {start}: {e}") from e

        if not page_data:
            break

        for item in page_data:
            if len(results) >= limit:
                break
            results.append(_clean_result(item))

        start += len(page_data)

    return {"total": total, "query": query, "results": results}


def get_analisis(id_sumario: int) -> dict[str, Any]:
    opener, _ = _make_opener()
    _init_session(opener)

    url = f"{ANALISIS_URL}?idSumario={id_sumario}"
    req = urllib.request.Request(
        url, headers={"X-Requested-With": "XMLHttpRequest"}
    )
    try:
        resp = opener.open(req, timeout=20)
        data = json.loads(resp.read().decode("utf-8"))
    except urllib.error.URLError as e:
        raise CSJNError(f"Failed to get analysis: {e}") from e
    except json.JSONDecodeError as e:
        raise CSJNError(f"Invalid JSON from analysis endpoint: {e}") from e

    out: dict[str, Any] = {
        "id": data.get("id"),
        "caratula": data.get("caratula", ""),
        "competencia": _extract_valor(data.get("competencia")),
        "sentido": _extract_valor(data.get("sentidoPronunciamiento")),
        "tipo_recurso": _extract_valor(data.get("tipoRecurso")),
        "materia": _extract_valor(data.get("materiaSecretaria")),
        "remision": _extract_valor(data.get("remision")),
        "inconstitucional": data.get("inconstitucional", False),
    }

    destacado = data.get("falloDestacado")
    if destacado:
        out["fallo_destacado"] = {
            "titulo": destacado.get("titulo", ""),
            "sintesis": _strip_html(destacado.get("cabecilla", "")),
        }

    return out


def autocomplete_voces(term: str) -> list[dict[str, Any]]:
    opener, _ = _make_opener()
    _init_session(opener)

    params = urllib.parse.urlencode({"term": term}).encode()
    req = urllib.request.Request(
        VOCES_URL,
        data=params,
        headers={
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            "X-Requested-With": "XMLHttpRequest",
        },
    )
    try:
        resp = opener.open(req, timeout=15)
        data = json.loads(resp.read().decode("utf-8"))
    except (urllib.error.URLError, json.JSONDecodeError) as e:
        raise CSJNError(f"Voces autocomplete failed: {e}") from e

    return [
        {"id": item["codigoValor"], "valor": item["valor"]}
        for item in data
        if item.get("valor")
    ]
