"""Compacta una lista de AXNode CDP descartando nodos irrelevantes."""


def trim_ax_tree(nodes: list[dict]) -> list[dict]:
    """Compacta lista de AXNode (formato CDP Accessibility.getFullAXTree).

    Descarta:
      - Nodos con ignored=true.
      - role 'generic' o 'none' sin name no-vacio Y sin childIds.
      - role 'StaticText' con name vacio.

    Colapsa: si un nodo tiene exactamente 1 hijo y el mismo role, fusiona
    el hijo en el padre (hereda childIds del hijo, descarta el nodo hijo).

    Preserva: nodeId, parentId, childIds, role.value, name.value, value.value.

    Args:
        nodes: Lista de AXNode en formato CDP. Cada nodo es un dict con
               campos 'nodeId', 'ignored', 'role', 'name', 'childIds', etc.

    Returns:
        Lista reducida de AXNode con la misma estructura de campos.
    """
    if not nodes:
        return []

    def _role(node: dict) -> str:
        r = node.get("role", {})
        if isinstance(r, dict):
            return r.get("value", "")
        return str(r)

    def _name(node: dict) -> str:
        n = node.get("name", {})
        if isinstance(n, dict):
            return n.get("value", "")
        return str(n) if n else ""

    def _child_ids(node: dict) -> list[str]:
        return node.get("childIds", [])

    # Paso 1: descartar nodos ignorados y roles descartables
    def _should_discard(node: dict) -> bool:
        if node.get("ignored", False):
            return True
        role = _role(node)
        name = _name(node)
        child_ids = _child_ids(node)
        if role in ("generic", "none") and not name and not child_ids:
            return True
        if role == "StaticText" and not name:
            return True
        return False

    kept = [n for n in nodes if not _should_discard(n)]

    # Construir lookup por nodeId para el paso de colapso
    by_id: dict[str, dict] = {n["nodeId"]: n for n in kept}

    # Paso 2: colapso de nodo con 1 solo hijo del mismo role
    # Iteramos hasta que no haya mas fusiones (convergencia)
    changed = True
    while changed:
        changed = False
        new_kept = []
        removed: set[str] = set()
        for node in by_id.values():
            if node["nodeId"] in removed:
                continue
            child_ids = _child_ids(node)
            if len(child_ids) == 1:
                child_id = child_ids[0]
                child = by_id.get(child_id)
                if child and _role(child) == _role(node):
                    # Fusionar: heredar childIds del hijo
                    merged = dict(node)
                    merged["childIds"] = _child_ids(child)
                    by_id[node["nodeId"]] = merged
                    removed.add(child_id)
                    changed = True
        if changed:
            by_id = {k: v for k, v in by_id.items() if k not in removed}

    # Preservar orden original
    original_order = [n["nodeId"] for n in nodes]
    result = []
    seen: set[str] = set()
    for nid in original_order:
        if nid in by_id and nid not in seen:
            result.append(by_id[nid])
            seen.add(nid)

    return result
