"""Recette fictive de correspondance après fusion ; aucun appel CRM/ERP.

Les entrées sont normalisées pour la démonstration, pas des réponses HubSpot.
La confirmation est une lecture simulée déjà qualifiée par l'adaptateur.
"""
from itertools import permutations


def plan(portal, event_ids, confirmed, links):
    if confirmed is None:
        return {"state": "relire", "writes": []}
    current, lineage = confirmed
    lineage = set(lineage)
    if current not in lineage or not set(event_ids) <= lineage:
        return {"state": "relire", "writes": []}
    candidates = {links[(portal, i)] for i in lineage if (portal, i) in links}
    if len(candidates) != 1:
        return {"state": "arbitrer", "candidates": sorted(candidates), "writes": []}
    client = next(iter(candidates))
    return {"state": "pret", "current": current, "erp": client,
            "writes": sorted((portal, i, current, client) for i in lineage)}


def main():
    links = {("P1", "101"): "E42", ("P1", "102"): "E42", ("P2", "101"): "E77"}
    confirmed = ("201", ["101", "102", "201"])
    expected = plan("P1", ["101", "102"], confirmed, links)
    assert expected["state"] == "pret" and expected["erp"] == "E42"
    assert expected["current"] == "201"
    for order in permutations(confirmed[1]):
        assert plan("P1", ["102", "101"], ("201", order), links) == expected
    # Deuxième fusion déjà acquise : l'ancienne notification ne rétablit pas 201.
    late = plan("P1", ["101", "102"], ("301", ["101", "102", "201", "301"]), links)
    assert late["current"] == "301" and len(late["writes"]) == 4
    conflict = dict(links, **{})
    conflict[("P1", "102")] = "E99"
    assert plan("P1", ["101", "102"], confirmed, conflict)["state"] == "arbitrer"
    assert plan("P1", ["101"], None, links)["writes"] == []
    assert plan("P2", ["101"], ("201", ["101", "201"]), links)["erp"] == "E77"
    assert plan("P3", ["101"], confirmed, links)["state"] == "arbitrer"
    assert plan("P1", ["999"], confirmed, links)["state"] == "relire"
    assert plan("P1", ["101"], ("999", ["101"]), links)["state"] == "relire"
    # Application locale idempotente des seules correspondances, sans création client.
    registry = {}
    for _ in range(2):
        for portal, alias, current, client in expected["writes"]:
            registry[(portal, alias)] = (current, client)
    assert len(registry) == 3
    assert {v[1] for v in registry.values()} == {"E42"}
    print("PASS : nouveau contact canonique 201, client ERP E42 conservé")
    print("PASS : événement tardif dirigé vers 301 ; 6 permutations équivalentes")
    print("PASS : conflits, lecture absente, portail distinct et rejeu contrôlés")
    print("Aucun contact, compte client, facture ou consentement créé ou modifié")


if __name__ == "__main__":
    main()
