# -*- coding: utf-8 -*-
"""本番入力の拡張検証: 濃度＋動画＋時間(slot)。
打ち手1ゲート(assessable=1)上で、時間(slot)特徴量を加えた効果を5-fold OOFで測定。
LLM再実行なし・追加課金ゼロ。線形回帰。
"""
from __future__ import annotations
import importlib.util, sys
from pathlib import Path
import numpy as np, pandas as pd
from sklearn.model_selection import KFold
from sklearn.pipeline import Pipeline
from sklearn.base import clone

ROOT = Path(__file__).resolve().parents[2]
LEGACY = ROOT / "検証" / "scripts" / "run_downstream_model_comparison.py"
INPUT = ROOT / "local_batch_api" / "output_full" / "training_dataset.csv"
OUTDIR = ROOT / "精度改善_20260619" / "08_gate_comparison"
SEED, N = 42, 5


def load_legacy():
    spec = importlib.util.spec_from_file_location("legacy_cmp", LEGACY)
    m = importlib.util.module_from_spec(spec); sys.modules["legacy_cmp"] = m
    spec.loader.exec_module(m); return m


def oof(data, fs, target, mod, kf):
    X = data[list(fs.numeric) + list(fs.categorical)]; y = data[target].to_numpy(); pred = np.zeros(len(y))
    for tr, te in kf.split(X):
        p = Pipeline([("prep", mod.preprocessor(list(fs.numeric), list(fs.categorical))),
                      ("model", clone(mod.model_specs(SEED)[1][1]))])
        p.fit(X.iloc[tr], y[tr]); pred[te] = np.clip(p.predict(X.iloc[te]), 0, 100)
    return y, pred


def stat(y, pred, grade):
    return {"MAE": round(float(np.abs(y-pred).mean()), 2),
            "グレード一致%": round(float((grade(y)==grade(pred)).mean())*100, 1),
            "±15点%": round(float((np.abs(y-pred)<=15).mean())*100, 1)}


def main():
    OUTDIR.mkdir(parents=True, exist_ok=True)
    mod = load_legacy()
    f = mod.build_features(INPUT)
    f = f[f["target_out_of_range"] == 0].reset_index(drop=True)
    g = f[f["assessable"] == 1].reset_index(drop=True)  # 打ち手1ゲート
    fsets = {x.name: x for x in mod.feature_sets()}
    kf = KFold(N, shuffle=True, random_state=SEED)

    # slotの分布
    print("slot分布(assessable=1):")
    print("  slot_is_opening=1:", int(g["slot_is_opening"].sum()), " slot_is_evening=1:", int(g["slot_is_evening"].sum()), " /", len(g))
    print()

    combos = {
        "human_total_score": ["visual_plus_brix", "visual_plus_brix_slot"],
        "human_soup_score": ["visual_only", "visual_plus_brix", "visual_plus_brix_slot"],
    }
    rows = []
    for target, fsnames in combos.items():
        for fsn in fsnames:
            y, pred = oof(g, fsets[fsn], target, mod, kf)
            s = stat(y, pred, mod.grade)
            s.update({"target": "total" if "total" in target else "soup", "feature_set": fsn, "n": len(g)})
            rows.append(s)
    res = pd.DataFrame(rows)[["target", "feature_set", "n", "MAE", "グレード一致%", "±15点%"]]
    res.to_csv(OUTDIR / "input_expansion.csv", index=False, encoding="utf-8-sig")
    for t in ["total", "soup"]:
        print(f"[{t}]"); print(res[res.target == t].to_string(index=False)); print()


if __name__ == "__main__":
    main()
