#!/usr/bin/env python3
"""
AI Creative Rights Contradiction Index (2026) — deterministic scorer.

Reads the frozen data snapshot and evaluates the four pre-registered
contradiction-class predicates EXACTLY as committed in PRE-REGISTRATION.md
(+ Addendum A for Class 3). No human judgement in the counts: pure field
comparisons, so re-running on the deposited data reproduces the index.

Usage: python score.py   (run from this directory; reads ./data-snapshot/)
Outputs: matrix + indices to stdout and to ./RESULT.json
"""
import json, os

HERE = os.path.dirname(os.path.abspath(__file__))
SNAP = os.path.join(HERE, "data-snapshot")

def load(name):
    with open(os.path.join(SNAP, name), encoding="utf-8") as f:
        return json.load(f)

tools = load("tools.json")["tools"]
platforms = load("platforms.json")["platforms"]

def is_ownership(v):
    v = str(v).lower()
    return ("own" in v) or (v == "yes-granted")   # you-own / yes-granted

def yn(v):
    """Return 'yes'/'no' or 'AMBIGUOUS' for anything else."""
    v = str(v).lower()
    return v if v in ("yes", "no") else "AMBIGUOUS"

# ---------- tool-intrinsic classes (1, 2, 4) ----------
tool_rows = []
ambig = {"class1": 0, "class2": 0, "class4": 0}
for t in tools:
    cu = t.get("commercialUse") or {}
    paid = yn(cu.get("paid"))
    free = yn(cu.get("free"))
    indem = yn(t.get("indemnification"))
    copyr = yn(t.get("copyrightable"))
    owns = t.get("ownsOutput")

    # Class 1: ownership granted AND not copyrightable
    if copyr == "AMBIGUOUS":
        c1 = None; ambig["class1"] += 1
    else:
        c1 = bool(is_ownership(owns) and copyr == "no")

    # Class 2: paid commercial AND no indemnification
    if paid == "AMBIGUOUS" or indem == "AMBIGUOUS":
        c2 = None; ambig["class2"] += 1
    else:
        c2 = bool(paid == "yes" and indem == "no")

    # Class 4: paid commercial (marketed commercial) AND free tier can't be sold
    if paid == "AMBIGUOUS" or free == "AMBIGUOUS":
        c4 = None; ambig["class4"] += 1
    else:
        c4 = bool(paid == "yes" and free == "no")

    tool_rows.append({
        "id": t.get("id"), "name": t.get("name"), "modality": t.get("modality"),
        "ownsOutput": owns, "copyrightable": t.get("copyrightable"),
        "indemnification": t.get("indemnification"),
        "commercialFree": cu.get("free"), "commercialPaid": cu.get("paid"),
        "class1_own_vs_copyright": c1,
        "class2_sell_vs_defend": c2,
        "class4_free_tier_trap": c4,
    })

def rate(pred_key):
    fired = sum(1 for r in tool_rows if r[pred_key] is True)
    denom = sum(1 for r in tool_rows if r[pred_key] is not None)
    return fired, denom, (fired / denom if denom else 0.0)

c1 = rate("class1_own_vs_copyright")
c2 = rate("class2_sell_vs_defend")
c4 = rate("class4_free_tier_trap")

# tool-level density: >=1 of classes 1,2,4 fires (True), per tool
tool_flagged = sum(1 for r in tool_rows
                   if any(r[k] is True for k in ("class1_own_vs_copyright","class2_sell_vs_defend","class4_free_tier_trap")))
tool_density = tool_flagged / len(tool_rows)

# ---------- path class (3): tool x platform, matched by modality ----------
def platform_modalities(p):
    return set(p.get("modalities") or ([p.get("modality")] if p.get("modality") else []))

paths = []
for t in tools:
    cu = t.get("commercialUse") or {}
    paid = yn(cu.get("paid"))
    tmod = t.get("modality")
    # tool-intrinsic flags inherited by every path of this tool
    trow = next(r for r in tool_rows if r["id"] == t.get("id"))
    for p in platforms:
        if tmod in platform_modalities(p):
            monet = str(p.get("monetizable")).lower()
            # Class 3 (strict, corrected Addendum A): paid commercial AND platform does not cleanly allow monetization
            if paid == "AMBIGUOUS":
                c3 = None
            else:
                c3 = bool(paid == "yes" and monet != "yes")
            # exploratory friction variant (NOT in headline index)
            strike = str(p.get("strikeRisk")).lower()
            disc = str(p.get("disclosure")).lower()
            c3_expl = bool(paid == "yes" and (monet != "yes" or "medium" in strike or disc.startswith("required")))
            paths.append({
                "tool": t.get("id"), "platform": p.get("id"), "modality": tmod,
                "class1": trow["class1_own_vs_copyright"],
                "class2": trow["class2_sell_vs_defend"],
                "class3_own_vs_monetize": c3,
                "class3_exploratory_friction": c3_expl,
                "platform_monetizable": p.get("monetizable"),
            })

def path_class_rate(key):
    fired = sum(1 for p in paths if p[key] is True)
    denom = sum(1 for p in paths if p[key] is not None)
    return fired, denom, (fired / denom if denom else 0.0)

p_c1 = path_class_rate("class1")
p_c2 = path_class_rate("class2")
p_c3 = path_class_rate("class3_own_vs_monetize")
p_c3e = path_class_rate("class3_exploratory_friction")

# headline: path-level density = >=1 of {class1, class2, class3} fires (True)
path_flagged = sum(1 for p in paths if any(p[k] is True for k in ("class1","class2","class3_own_vs_monetize")))
path_density = path_flagged / len(paths)

# per-modality path density
from collections import defaultdict
mod_tot = defaultdict(int); mod_flag = defaultdict(int)
for p in paths:
    mod_tot[p["modality"]] += 1
    if any(p[k] is True for k in ("class1","class2","class3_own_vs_monetize")):
        mod_flag[p["modality"]] += 1
per_modality = {m: {"paths": mod_tot[m], "flagged": mod_flag[m], "density": round(mod_flag[m]/mod_tot[m],4)} for m in sorted(mod_tot)}

result = {
    "meta": {
        "title": "AI Creative Rights Contradiction Index (2026)",
        "snapshot_date": "2026-06-08",
        "n_tools": len(tools), "n_platforms": len(platforms), "n_paths": len(paths),
        "note": "Deterministic. Predicates frozen in PRE-REGISTRATION.md + Addendum A. AMBIGUOUS = value not exactly yes/no, excluded from that class."
    },
    "tool_level": {
        "class1_own_vs_copyright": {"fired": c1[0], "denom": c1[1], "rate": round(c1[2],4)},
        "class2_sell_vs_defend":   {"fired": c2[0], "denom": c2[1], "rate": round(c2[2],4)},
        "class4_free_tier_trap":   {"fired": c4[0], "denom": c4[1], "rate": round(c4[2],4)},
        "tool_level_density": round(tool_density,4),
        "tools_flagged": tool_flagged, "n_tools": len(tool_rows),
        "ambiguous_exclusions": ambig,
    },
    "path_level_HEADLINE": {
        "path_density": round(path_density,4),
        "paths_flagged": path_flagged, "n_paths": len(paths),
        "class1_rate": round(p_c1[2],4),
        "class2_rate": round(p_c2[2],4),
        "class3_own_vs_monetize_rate": round(p_c3[2],4),
        "class3_own_vs_monetize_fired": p_c3[0],
        "per_modality": per_modality,
    },
    "exploratory_not_preregistered": {
        "class3_friction_rate": round(p_c3e[2],4),
        "class3_friction_fired": p_c3e[0],
        "note": "Broader 'platform friction' variant (conditional monetize + medium strike + mandatory disclosure). NOT part of the headline index; shown for sensitivity only."
    },
    "tool_matrix": tool_rows,
}

with open(os.path.join(HERE, "RESULT.json"), "w", encoding="utf-8") as f:
    json.dump(result, f, indent=2)

# also deposit the full path matrix
with open(os.path.join(HERE, "path-matrix.json"), "w", encoding="utf-8") as f:
    json.dump(paths, f, indent=2)

# ---- human-readable summary ----
print("=== AI CREATIVE RIGHTS CONTRADICTION INDEX (2026) ===")
print(f"tools={len(tools)} platforms={len(platforms)} paths={len(paths)} snapshot=2026-06-08\n")
print("TOOL-LEVEL (classes 1,2,4):")
print(f"  Class 1 OWN-vs-COPYRIGHT : {c1[0]}/{c1[1]} = {c1[2]:.0%}")
print(f"  Class 2 SELL-vs-DEFEND   : {c2[0]}/{c2[1]} = {c2[2]:.0%}")
print(f"  Class 4 FREE-TIER trap   : {c4[0]}/{c4[1]} = {c4[2]:.0%}")
print(f"  >> tool-level density (>=1 of 1,2,4): {tool_flagged}/{len(tool_rows)} = {tool_density:.0%}")
print(f"  ambiguous exclusions: {ambig}\n")
print("PATH-LEVEL (headline; classes 1,2,3 over tool x platform paths):")
print(f"  Class 1 rate: {p_c1[2]:.0%}   Class 2 rate: {p_c2[2]:.0%}   Class 3 rate: {p_c3[2]:.0%} ({p_c3[0]} fired)")
print(f"  >> HEADLINE path density (>=1 contradiction): {path_flagged}/{len(paths)} = {path_density:.0%}")
print(f"  per-modality: {json.dumps(per_modality)}")
print(f"\nEXPLORATORY (not pre-registered) class-3 friction rate: {p_c3e[2]:.0%} ({p_c3e[0]} fired)")
print("\nWrote RESULT.json + path-matrix.json")
