"""Filtra los flujos relevantes de un HAR para reconstruir una accion HTTP.

Primer paso del patron "grabar -> destilar -> reproducir": dado un HAR
(formato estandar W3C, el que exporta `query_mitm_flows --har` de mitmproxy),
descarta el ruido (recursos estaticos, dominios de analytics/telemetria) y
opcionalmente restringe por host y metodo, dejando solo los entries que
importan para reproducir una accion como funcion del registry.

Funcion pura: recibe el HAR ya parseado como dict, no hace I/O y no muta los
dicts de entrada (devuelve un subconjunto de los entries originales tal cual).
"""

from urllib.parse import urlsplit

# Extensiones de recursos estaticos (sobre el path, ignorando querystring).
_STATIC_EXTENSIONS = (
    ".css",
    ".js",
    ".mjs",
    ".map",
    ".png",
    ".jpg",
    ".jpeg",
    ".gif",
    ".svg",
    ".webp",
    ".ico",
    ".woff",
    ".woff2",
    ".ttf",
    ".eot",
)

# Prefijos de mimeType considerados estaticos.
_STATIC_MIME_PREFIXES = (
    "image/",
    "font/",
    "text/css",
)

# mimeTypes exactos considerados estaticos (JavaScript en sus dos formas).
_STATIC_MIME_EXACT = (
    "application/javascript",
    "text/javascript",
)

# Blocklist heuristica de dominios de telemetria/analytics (substring sobre host).
_ANALYTICS_BLOCKLIST = (
    "google-analytics.com",
    "googletagmanager.com",
    "analytics.google.com",
    "doubleclick.net",
    "facebook.com/tr",
    "connect.facebook.net",
    "sentry.io",
    "segment.io",
    "segment.com",
    "mixpanel.com",
    "hotjar.com",
    "fullstory.com",
    "clarity.ms",
    "cdn.amplitude.com",
    "stats.g.doubleclick.net",
    "datadoghq.com",
    "bugsnag.com",
)


def _is_static(entry: dict) -> bool:
    """True si el entry HAR es un recurso estatico (por mimeType o extension)."""
    mime = (
        entry.get("response", {})
        .get("content", {})
        .get("mimeType", "")
    )
    mime = (mime or "").split(";", 1)[0].strip().lower()
    if mime:
        if mime.startswith(_STATIC_MIME_PREFIXES):
            return True
        if mime in _STATIC_MIME_EXACT:
            return True

    url = entry.get("request", {}).get("url", "") or ""
    path = urlsplit(url).path.lower()
    return path.endswith(_STATIC_EXTENSIONS)


def _is_analytics(host: str) -> bool:
    """True si el host coincide (substring) con la blocklist de analytics."""
    host = (host or "").lower()
    return any(blocked in host for blocked in _ANALYTICS_BLOCKLIST)


def har_filter_flows(
    har: dict,
    *,
    hosts: list[str] | None = None,
    methods: list[str] | None = None,
    drop_static: bool = True,
    drop_analytics: bool = True,
) -> list[dict]:
    """Devuelve solo los entries HAR relevantes para reproducir una accion HTTP.

    Args:
        har: HAR ya parseado como dict (formato W3C). Se leen los entries de
            `har["log"]["entries"]`; si la estructura no existe, devuelve [].
        hosts: si no es None, mantiene solo entries cuyo host (de urlsplit)
            este en la lista (match exacto de host).
        methods: si no es None, mantiene solo entries cuyo metodo HTTP este en
            la lista (ambos lados normalizados a mayusculas).
        drop_static: si True, descarta recursos estaticos (CSS/JS/imagenes/
            fuentes) por mimeType o por extension de la ruta.
        drop_analytics: si True, descarta entries cuyo host caiga en la
            blocklist de dominios de telemetria/analytics.

    Returns:
        Sublista de los dicts de entrada (los entries HAR originales, sin
        mutar) que pasan todos los filtros.
    """
    entries = har.get("log", {}).get("entries")
    if not isinstance(entries, list):
        return []

    methods_upper = (
        {m.upper() for m in methods} if methods is not None else None
    )
    hosts_set = set(hosts) if hosts is not None else None

    result: list[dict] = []
    for entry in entries:
        request = entry.get("request", {})
        url = request.get("url", "") or ""
        host = urlsplit(url).hostname or ""

        if drop_static and _is_static(entry):
            continue
        if drop_analytics and _is_analytics(host):
            continue
        if hosts_set is not None and host not in hosts_set:
            continue
        if methods_upper is not None:
            method = (request.get("method", "") or "").upper()
            if method not in methods_upper:
                continue

        result.append(entry)

    return result
