"""Exercice local de migration, données synthétiques, aucun accès réseau."""
from pathlib import Path
from collections import defaultdict
from datetime import datetime
from decimal import Decimal
import copy
import json

ROOT = Path(__file__).resolve().parent
END = "2026-09-03T00:00:00Z"

def timestamp(value):
    return datetime.fromisoformat(value.replace("Z", "+00:00"))

def tokens(value):
    if type(value) is not int or value < 0:
        raise ValueError("output_tokens doit être un entier positif ou nul")
    return value

def old_rows(report):
    if report["has_more"]:
        raise ValueError("export legacy incomplet")
    out = defaultdict(int)
    for bucket in report["data"]:
        for row in bucket["results"]:
            out[(bucket["starting_at"], row["model"])] += tokens(row["output_tokens"])
    return dict(out)

def new_rows(pages):
    if not pages:
        raise ValueError("aucune page collectée")
    out = defaultdict(int)
    expected = None
    watermark = pages[0]["response"]["data_refreshed_at"]
    if watermark is None or timestamp(watermark) < timestamp(END):
        raise ValueError("période pas encore entièrement rafraîchie")
    for index, page in enumerate(pages):
        if page["request_page"] != expected:
            raise ValueError("curseur de pagination incohérent")
        report = page["response"]
        if report["data_refreshed_at"] != watermark:
            raise ValueError("snapshots de données différents")
        for row in report["data"]:
            out[(row["starting_at"], row["group"]["model"])] += tokens(row["usage"]["output_tokens"])
        more = report["has_more"]
        if type(more) is not bool:
            raise ValueError("has_more doit être booléen")
        expected = report["next_page"]
        if more and not expected:
            raise ValueError("curseur suivant absent")
        if not more and index != len(pages) - 1:
            raise ValueError("pages supplémentaires après la fin")
    if more:
        raise ValueError("dernière page manquante")
    return dict(out)

def must_reject(pages, expected_message):
    try:
        new_rows(pages)
    except ValueError as error:
        assert expected_message in str(error), str(error)
        return str(error)
    raise AssertionError("collecte incorrecte acceptée")

def main():
    legacy = json.loads((ROOT / "legacy.json").read_text())
    pages = json.loads((ROOT / "analytics-pages.json").read_text())
    old, new = old_rows(legacy), new_rows(pages)
    assert old == new
    naive = sum(row["usage"]["output_tokens"] for row in pages[0]["response"]["data"])
    assert sum(new.values()) == 400 and naive == 350
    stale = copy.deepcopy(pages)
    for page in stale:
        page["response"]["data_refreshed_at"] = "2026-09-02T12:00:00Z"
    broken = copy.deepcopy(pages)
    broken[1]["request_page"] = "mauvais_curseur"
    print(json.dumps({
        "preuve": "Exercice local fictif, aucun appel à Anthropic",
        "output_tokens_legacy": sum(old.values()),
        "output_tokens_analytics_complet": sum(new.values()),
        "output_tokens_premiere_page_seule": naive,
        "meme_detail_jour_modele": old == new,
        "refus_page_manquante": must_reject(pages[:1], "dernière page manquante"),
        "refus_donnees_recentes": must_reject(stale, "pas encore entièrement"),
        "refus_curseur_incorrect": must_reject(broken, "curseur"),
        "centimes_vers_usd_fictifs": str(Decimal("12345.000000") / Decimal(100)),
        "limite": "Comparaison de output_tokens seulement ; ni coût total ni totalité du schéma API validés"
    }, ensure_ascii=False, indent=2))
if __name__ == "__main__":
    main()
