"""Exercice fictif Dawap : diagnostic local, sans calcul officiel Amazon.

Python 3.10+, bibliothèque standard. Aucun appel réseau ou fichier personnel.
"""
from fractions import Fraction


def audit(rows):
    seen = set()
    counts = {"conforme": 0, "hors_horaires": 0, "inconnu": 0, "hors_perimetre": 0}
    for identifier, state in rows:
        if identifier in seen:
            raise ValueError("Identifiant d'expédition répété")
        if state not in counts:
            raise ValueError("État non reconnu")
        seen.add(identifier)
        counts[state] += 1
    scope = len(rows) - counts["hors_perimetre"]
    observed = counts["conforme"] + counts["hors_horaires"]
    return {
        "total": len(rows), "scope": scope, "observed": observed,
        "unknown": counts["inconnu"],
        "compliance": Fraction(counts["conforme"], observed) if observed else None,
        "coverage": Fraction(observed, scope) if scope else None,
        "lower_bound": Fraction(counts["conforme"], scope) if scope else None,
    }


def main():
    states = ["conforme"] * 36 + ["hors_horaires"] * 2 + ["inconnu"] * 2 + ["hors_perimetre"] * 10
    rows = [(f"EXP-{i:03}", s) for i, s in enumerate(states, 1)]
    result = audit(rows)
    assert result == {
        "total": 50, "scope": 40, "observed": 38, "unknown": 2,
        "compliance": Fraction(18, 19), "coverage": Fraction(19, 20),
        "lower_bound": Fraction(9, 10),
    }
    assert audit(list(reversed(rows))) == result
    assert audit([])["compliance"] is None
    assert audit([])["coverage"] is None
    assert audit([("X", "inconnu")])["compliance"] is None
    assert audit([("X", "inconnu")])["coverage"] == 0
    assert audit([("X", "hors_perimetre")])["lower_bound"] is None
    changed = [(i, "conforme" if i == "EXP-039" else s) for i, s in rows]
    assert audit(changed)["compliance"] == Fraction(37, 39)
    for bad in [[("X", "conforme"), ("X", "hors_horaires")], [("X", "vide")]]:
        try:
            audit(bad)
        except ValueError:
            pass
        else:
            raise AssertionError("Entrée invalide acceptée")
    # Une valeur arrondie ne vaut pas franchissement du seuil.
    assert Fraction(896, 1000) < Fraction(9, 10)
    assert round(float(Fraction(896, 1000) * 100)) == 90
    assert 9 + 12 / 60 * 30 + 5 == 20
    assert 3 * 100 / 20 == 15
    print("PASS : 50 expéditions fictives ; 40 dans le périmètre local")
    print("Conformité observée 94,74 % ; couverture 95 % ; borne basse locale 90 %")
    print("Doublons, états invalides, ensembles vides et arrondis contrôlés")
    print("Aucun calcul officiel BHDR, aucune action Amazon")


if __name__ == "__main__":
    main()
