#!/usr/bin/env python3
"""Diff hub-route SHAPES between production (known-good) and staging.

Values legitimately differ (different clubs, different piles). What must not differ is
structure: a key production sends that staging omits, or a type/null mismatch, is a
candidate cause for the client rejecting FUT bootstrap.
"""
import json
import os

PROD, STAG = "/tmp/hub_prod", "/tmp/hub_stag"


def t(v):
    return "null" if v is None else type(v).__name__


def shape(obj, prefix="", depth=0):
    """path -> type, descending into the FIRST element of lists (representative)."""
    out = {}
    if depth > 6:
        return out
    if isinstance(obj, dict):
        for k, v in obj.items():
            p = f"{prefix}.{k}" if prefix else k
            out[p] = t(v)
            out.update(shape(v, p, depth + 1))
    elif isinstance(obj, list):
        out[(prefix or "<root>") + "[]"] = "list"
        if obj:
            out.update(shape(obj[0], f"{prefix}[0]", depth + 1))
    return out


total = 0
for name in sorted(os.listdir(PROD)):
    pf, sf = os.path.join(PROD, name), os.path.join(STAG, name)
    if not os.path.exists(sf):
        print(f"{name}: MISSING on staging")
        continue
    p = json.load(open(pf))
    s = json.load(open(sf))
    ps, ss = shape(p.get("body")), shape(s.get("body"))
    missing = [k for k in ps if k not in ss]
    types = [(k, ps[k], ss[k]) for k in ps if k in ss and ps[k] != ss[k]]
    nulls = [k for k in ps if k in ss and ss[k] == "null" and ps[k] != "null"]
    if p.get("status") != s.get("status"):
        print(f"\n### {name}: STATUS prod={p.get('status')} staging={s.get('status')}")
        total += 1
    if missing or types:
        print(f"\n### {name}")
        for k in missing:
            print(f"   MISSING on staging: {k:<44} prod_type={ps[k]}")
        for k, a, b in types:
            mark = "  <-- NULL" if b == "null" else ""
            print(f"   TYPE  {k:<48} prod={a:<7} staging={b}{mark}")
        total += len(missing) + len(types)

print(f"\n=== {total} structural difference(s) across {len(os.listdir(PROD))} routes ===")
if total == 0:
    print("Every hub route matches production's shape. The bootstrap failure is not a")
    print("missing/mistyped field in these responses.")
