"""Wikipedia pageview decline segmented by ARTICLE CLASS, from the open Pageviews API.
The class lists are a hand-picked sample, not a random one --
the essay's "what this does not support" paragraph states the bounds; read it before
quoting any class figure as a population statistic.

  python wikipedia_pageview_by_class.py
"""
import json
import time
import urllib.parse
import urllib.request

UA = "vibeagentmaking-research/1.0 (+https://vibeagentmaking.com/)"
BASE = "https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article/en.wikipedia/all-access"

CLASSES = {
    "reference-lookup (the 'what is X' class an AI summary absorbs)": [
        "Photosynthesis", "Mitochondrion", "Osmosis", "Standard_deviation",
        "Pythagorean_theorem", "Mitosis", "Supply_and_demand", "Newton's_laws_of_motion",
    ],
    "news/event-driven": [
        "Ukraine", "Taiwan", "Inflation", "NATO", "Federal_Reserve",
    ],
    "long-tail deep dive": [
        "Battle_of_Kursk", "Peloponnesian_War", "Byzantine_Empire",
        "History_of_the_Netherlands", "Antikythera_mechanism",
    ],
    "control: navigational / non-substantive": [
        "Main_Page", "Wikipedia", "List_of_countries_by_population_(United_Nations)",
    ],
}


def series(title, agent="user"):
    t = urllib.parse.quote(title, safe="")
    url = f"{BASE}/{agent}/{t}/monthly/2023010100/2026080100"
    req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/json"})
    for a in range(3):
        try:
            with urllib.request.urlopen(req, timeout=60) as r:
                d = json.load(r)
            return {i["timestamp"][:6]: i["views"] for i in d.get("items", [])}, None
        except Exception as exc:
            if a == 2:
                return None, f"{type(exc).__name__}: {exc}"
            time.sleep(2)


def window(m, year, months=("03", "04", "05", "06", "07")):
    vals = [m.get(f"{year}{mo}") for mo in months]
    return sum(v for v in vals if v) if any(vals) else None, sum(1 for v in vals if v)


print(f"{'article':46} {'Mar-Jul24':>11} {'Mar-Jul25':>11} {'Mar-Jul26':>11}  {'25v24':>7} {'26v25':>7} {'26v24':>7}")
results = {}
for cls, arts in CLASSES.items():
    print(f"\n== {cls}")
    rows = []
    for t in arts:
        m, err = series(t)
        if err:
            print(f"{t:46} ERROR {err[:40]}")
            continue
        a, na = window(m, "2024")
        b, nb = window(m, "2025")
        c, nc = window(m, "2026")
        if not (a and b and c) or min(na, nb, nc) < 5:
            print(f"{t:46} INCOMPLETE months {na}/{nb}/{nc}")
            continue
        d1 = (b - a) / a * 100
        d2 = (c - b) / b * 100
        d3 = (c - a) / a * 100
        rows.append((t, a, b, c, d1, d2, d3))
        print(f"{t:46} {a:11,} {b:11,} {c:11,}  {d1:+6.1f}% {d2:+6.1f}% {d3:+6.1f}%")
    if rows:
        for lbl, i in (("CLASS TOTAL", None),):
            A = sum(r[1] for r in rows); B = sum(r[2] for r in rows); C = sum(r[3] for r in rows)
            print(f"{'-> ' + lbl + f' (n={len(rows)})':46} {A:11,} {B:11,} {C:11,}"
                  f"  {(B-A)/A*100:+6.1f}% {(C-B)/B*100:+6.1f}% {(C-A)/A*100:+6.1f}%")
        results[cls] = (A, B, C, len(rows))
json.dump(results, open("wmf_class.json", "w"), indent=1)
