#!/usr/bin/env python3
"""build_landing — bake landing.json for the dataviz front door (index.html, #63).

The landing ties the corpus dataviz together (narrative + explorable) and opens with
an HONEST style tag-cloud: the genres PLN actually plays, read from his own gig
metadata (catalog_view metas[].style, canonicalised by models.norm_style) — NOT
hallucinated from one-shots ([[feedback_metadata_vs_mastering]]). Counts are tracks,
not samples; a style is counted once per track even across multiple gigs.

    python3 build_landing.py        # → landing.json
"""
import json
from collections import Counter, defaultdict
from datetime import date
from pathlib import Path

import models as M

HERE = Path(__file__).resolve().parent
CV = HERE / "catalog_view.json"
UNW = HERE / "unwrapped.json"
OUT = HERE / "landing.json"


def main():
    cv = json.loads(CV.read_text())
    styles, bpms = Counter(), defaultdict(list)
    gigs = set()
    for t in cv["tracks"]:
        seen = set()
        for m in (t.get("metas") or []):
            if m.get("gig"):
                gigs.add(m["gig"])
            s = m.get("style")
            if not s:
                continue
            ns = M.norm_style(s)
            if ns not in seen:
                styles[ns] += 1
                seen.add(ns)
            if m.get("bpm"):
                bpms[ns].append(m["bpm"])

    def med(xs):
        xs = sorted(xs)
        return xs[len(xs) // 2] if xs else None

    cloud = [{"style": s, "n": n, "bpm": med(bpms[s])}
             for s, n in styles.most_common()]

    unw = json.loads(UNW.read_text()) if UNW.exists() else {}
    n_samples = unw.get("headline", {}).get("n_files")
    n_takes = sum(1 for t in cv["tracks"] for _ in [t] if t.get("n_takes_eda"))

    payload = {
        "schema": "dataviz landing (style cloud + corpus stats) — #63",
        "as_of": date.today().isoformat(),
        "stats": {
            "tracks": len(cv["tracks"]),
            "gigs": len(gigs),
            "samples": n_samples,
            "takes_eda": sum(int(t.get("n_takes_eda") or 0) for t in cv["tracks"]),
            "styles": len(cloud),
        },
        "style_cloud": cloud,
    }
    OUT.write_text(json.dumps(payload, ensure_ascii=False, indent=1))
    print(f"✓ {OUT.name}: {len(cloud)} styles, {payload['stats']['tracks']} tracks, "
          f"{payload['stats']['gigs']} gigs")


if __name__ == "__main__":
    main()
