"""diff_relations — compara dos snapshots de relaciones con key compuesta."""


def diff_relations(
    before: list[dict],
    after: list[dict],
    key: tuple[str, str, str] = ("source_id", "target_id", "relation_type"),
    ignore_fields: list[str] | None = None,
    compare_fields: list[str] | None = None,
) -> dict:
    """Compara relaciones entre dos snapshots usando key compuesta.

    Las relaciones se identifican por (source_id, target_id, relation_type)
    porque no tienen un ID unico propio. Detecta relaciones añadidas,
    eliminadas y modificadas (mismo source/target/type, distinta metadata).

    Args:
        before: Lista de relaciones del snapshot anterior.
        after: Lista de relaciones del snapshot posterior.
        key: Tupla de campos que forman la key compuesta.
             Default ("source_id", "target_id", "relation_type").
        ignore_fields: Campos a excluir de la comparacion.
                       Default ["created_at", "updated_at"].
        compare_fields: Si se da, solo compara estos campos.

    Returns:
        Dict con keys: added, removed, modified, unchanged, summary.
        modified contiene lista de {"key": str, "changes": {"field": {"old": ..., "new": ...}}}.
    """
    if ignore_fields is None:
        ignore_fields = ["created_at", "updated_at"]

    def make_key(rel: dict) -> str:
        return "|".join(str(rel.get(k, "")) for k in key)

    before_map = {make_key(r): r for r in before}
    after_map = {make_key(r): r for r in after}

    before_keys = set(before_map.keys())
    after_keys = set(after_map.keys())

    added = [after_map[k] for k in after_keys - before_keys]
    removed = [before_map[k] for k in before_keys - after_keys]

    modified = []
    unchanged = 0

    for k in before_keys & after_keys:
        b = before_map[k]
        a = after_map[k]

        if compare_fields is not None:
            fields_to_check = compare_fields
        else:
            all_fields = set(b.keys()) | set(a.keys())
            key_set = set(key)
            fields_to_check = [f for f in all_fields if f not in ignore_fields and f not in key_set]

        changes = {}
        for field in fields_to_check:
            old_val = b.get(field)
            new_val = a.get(field)
            if old_val != new_val:
                changes[field] = {"old": old_val, "new": new_val}

        if changes:
            modified.append({"key": k, "changes": changes})
        else:
            unchanged += 1

    n_added = len(added)
    n_removed = len(removed)
    n_modified = len(modified)
    summary = f"{n_added} added, {n_removed} removed, {n_modified} modified, {unchanged} unchanged"

    return {
        "added": added,
        "removed": removed,
        "modified": modified,
        "unchanged": unchanged,
        "summary": summary,
    }
