from typing import Any, Dict, List, Optional, Set


def _co_variants(customs_office: str) -> Set[str]:
    co = (customs_office or "").strip()
    if not co:
        return set()
    out: Set[str] = {co}
    if len(co) == 1 and co.isdigit():
        out.add(co.zfill(2))
    if len(co) >= 2:
        out.add(co[:2])
        out.add(co[-2:])
    if len(co) >= 3:
        out.add(co[:3])
    return {x for x in out if x}


def _same_customs_office(csv_customs: str, candidate_customs: str) -> bool:
    csv_variants = _co_variants(csv_customs)
    cand_variants = _co_variants(candidate_customs)
    if not csv_variants or not cand_variants:
        return False
    return bool(csv_variants.intersection(cand_variants))


def resolve_pedimento_candidates(
    customs_office: str,
    license_val: str,
    pedimento_number: str,
    patente_lookup: Optional[str],
    pedimento_rows: List[Dict[str, Any]],
) -> Dict[str, Any]:
    """
    Resuelve candidatos de pedimento por componentes reales.
    Prioriza match exacto por aduana/patente/numero y usa fallback por patente/numero.
    """
    candidates: List[Dict[str, Any]] = []
    seen_ids: Set[Any] = set()

    lookup_licenses: List[str] = []
    lic = (license_val or "").strip()
    if lic:
        lookup_licenses.append(lic)
    patente = (patente_lookup or "").strip()
    if patente and patente not in lookup_licenses:
        lookup_licenses.append(patente)

    for info in (pedimento_rows or []):
        row_num = (info.get("pedimento_number") or "").strip()
        row_lic = (info.get("license") or "").strip()
        if row_num != (pedimento_number or "").strip():
            continue
        if lookup_licenses and row_lic not in lookup_licenses:
            continue
        pid = info.get("id")
        if pid not in seen_ids:
            candidates.append(info)
            seen_ids.add(pid)

    if not candidates:
        return {"status": "not_found", "pedimento": None, "candidates": []}

    customs_filtered = [
        c for c in candidates
        if _same_customs_office(customs_office, (c.get("customs_office") or ""))
    ]
    if len(customs_filtered) == 1:
        return {"status": "ok", "pedimento": customs_filtered[0], "candidates": customs_filtered}
    if len(customs_filtered) > 1:
        return {"status": "ambiguous", "pedimento": None, "candidates": customs_filtered}

    if len(candidates) == 1:
        return {"status": "ok", "pedimento": candidates[0], "candidates": candidates}

    return {"status": "ambiguous", "pedimento": None, "candidates": candidates}
