#!/usr/bin/env python3
"""事后描述性分析 —— **非预注册**，不参与任何判据，只用来解释主结果的机制。

主结论（H1 被推翻）完全由 05_analyze.py 的预注册检验决定，与本文件无关。
本文件的数字在报告里一律标注为「事后探索」。
"""
import json
from pathlib import Path

PKG = Path(__file__).resolve().parents[2]
RAW = json.loads((PKG / "work/results/eval_raw.json").read_text(encoding="utf-8"))
SEEDS = [str(s) for s in RAW["eval_seeds"]]
R = RAW["real"]


def med(v):
    w = sorted(v); n = len(w)
    return w[n // 2] if n % 2 else (w[n // 2 - 1] + w[n // 2]) / 2.0


def phase(arm, lo, hi):
    return [sum(R[arm][s]["trajectory"][lo:hi]) / (hi - lo) for s in SEEDS]


out = {"label": "事后探索性描述，非预注册，不参与任何判据",
       "spending_phase_windows_1_8": {}, "post_spending_phase_windows_9_16": {}}
for arm in ("null_no_intervention", "extremity_top_b", "offline_rl_fqi"):
    out["spending_phase_windows_1_8"][arm] = med(phase(arm, 0, 8))
    out["post_spending_phase_windows_9_16"][arm] = med(phase(arm, 8, 16))
d1 = [a - b for a, b in zip(phase("extremity_top_b", 0, 8), phase("offline_rl_fqi", 0, 8))]
d2 = [a - b for a, b in zip(phase("extremity_top_b", 8, 16), phase("offline_rl_fqi", 8, 16))]
out["extremity_minus_rl_median_phase1_windows_1_8"] = med(d1)
out["extremity_minus_rl_median_phase2_windows_9_16"] = med(d2)
out["n_seeds_rl_better_phase1_of_12"] = sum(1 for v in d1 if v > 0)
out["n_seeds_rl_better_phase2_of_12"] = sum(1 for v in d2 if v > 0)
out["rl_windows_with_any_action_median"] = med(
    [sum(1 for c in R["offline_rl_fqi"][s]["picks_per_window"] if c > 0) for s in SEEDS])
out["extremity_windows_with_any_action_median"] = med(
    [sum(1 for c in R["extremity_top_b"][s]["picks_per_window"] if c > 0) for s in SEEDS])
out["reading"] = ("离线 RL 把 96 次预算全部压在留出期前 8 个月连续出手，后 8 个月无预算可用；"
                  "极端度贪心每隔一个月出手、把预算摊满 16 个月。前半段 RL 确实压得更低，"
                  "后半段扰动随 FJ 锚定衰减、方差反弹，终点与全程 AUC 两个口径上都输。")
(PKG / "work/results/exploratory_post_hoc.json").write_text(
    json.dumps(out, ensure_ascii=False, indent=1), encoding="utf-8")
print(json.dumps(out, ensure_ascii=False, indent=1))
