"""Coreference simple por normalizacion y substring para entidades nombradas."""

from __future__ import annotations

import re
from collections import defaultdict


def merge_entity_aliases(entity_names: list[str]) -> dict[str, str]:
    """Build alias map: original_name -> canonical_name.

    Two-pass algorithm:
    Step 1 - Normalize: lowercase + strip punctuation -> cluster by normalized form.
             Canonical per cluster = longest original casing.
    Step 2 - Substring merge: short names absorbed by longer ones if short_name
             appears as whole word inside long_name (normalized) AND
             short_name has >= 4 normalized chars (prevents false positives
             like 'US' absorbing everything that contains 'us').

    Args:
        entity_names: List of entity name strings (may have duplicates or
                      different casings, e.g. ["BBVA", "bbva", "Banco Bilbao..."]).

    Returns:
        Dict mapping each input name to its final canonical form.
        Identity mapping for names that are not aliases of anything else.
    """
    if not entity_names:
        return {}

    def normalize(s: str) -> str:
        s = re.sub(r"[\.,;:\"'`()\[\]]", "", s.strip())
        s = re.sub(r"\s+", " ", s)
        return s.strip().lower()

    # Paso 1: agrupar por forma normalizada, elegir el mas largo como canonical
    norm_groups: dict[str, list[str]] = defaultdict(list)
    for n in entity_names:
        norm_groups[normalize(n)].append(n)

    canonical: dict[str, str] = {}
    for nrm, group in norm_groups.items():
        winner = max(group, key=lambda x: (len(x), x))
        for n in group:
            canonical[n] = winner

    # Paso 2: substring merge sobre los canonicos (long absorbe short si short dentro de long)
    canon_set = sorted(set(canonical.values()), key=len, reverse=True)
    absorbed: dict[str, str] = {}

    for long_n in canon_set:
        long_norm = normalize(long_n)
        for short_n in canon_set:
            if short_n == long_n or short_n in absorbed:
                continue
            short_norm = normalize(short_n)
            if len(short_norm) < 4:
                continue
            if re.search(r"\b" + re.escape(short_norm) + r"\b", long_norm):
                absorbed[short_n] = long_n

    return {orig: absorbed.get(canon, canon) for orig, canon in canonical.items()}
