#!/usr/bin/env python3
"""LOG484 / 研究室 Log28: deep1 の実機推論で、アームがどこをつかみに行ったかを、お手本の位置ごとのつかむ姿勢と比べる.

- お手本: mecharm_redblock_box_deep_even10_v1 の 50 本. 位置は pi05/count_by_position.py の出力 (2026-11-10) のとおり.
  つかむ姿勢 = state の爪 (7 列目) が初めて 1 になったコマの j0〜j5.
- 実機推論: runs/pi05_policy/pi05_20261110_*/.
  爪を閉じた姿勢 = recording/states.csv で, 初めて gripper_cmd が 1 (閉じる) になった直前の actual の j0〜j5.
  AI が行った所 = 閉じる前にゲームパッドの補正があれば, その補正の最初の measured_before (人が直す前の姿勢).
  なければ, 爪を閉じた姿勢と同じ.
- 近い位置 = AI が行った所と, 位置ごとのつかむ姿勢の平均との距離 (j0〜j5 の差の二乗和の平方根) がいちばん小さい位置.
使い方: python3 grasp_pose_compare.py [--data-root /Volumes/KIOXIA/r2r2r-data]
"""
import argparse, csv, json, math
from pathlib import Path
import numpy as np

POS = {
 1: "094839 095308 095810 095948 100126 100307 100444 100716 101157 103049",
 2: "191257 191541 191635 102109 102248 102431 103804 103943 104110 104517",
 3: "192438 192539 123848 124032 124117 124207 124256 124438 124817 124920",
 4: "193404 193459 193617 193825 193932 130542 130723 130824 130929 131103",
 5: "pi05_20261031_175527 pi05_20261031_180435 pi05_20261031_184016 pi05_20261101_190347 pi05_20261106_183926 pi05_20261106_184650 194818 194913 195023 195120",
}
DAY = {"1910": "20261019", "1930": "20261019", "1940": "20261019", "1950": "20261019"}
# 2026-11-10 の実機推論. 位置はエイイチの答え (チャット) とスクリプトの出力から. 111034 は位置合わせの前の 1 回目
RUNS = [("111034", "1回目(位置なし)"), ("112346", "位置1"), ("112639", "位置1"), ("112924", "位置1"),
        ("113433", "位置2"), ("113600", "位置2"), ("113741", "位置2"), ("114106", "位置2")]


def ep_name(s):
    if s.startswith("pi05_"):
        return s
    day = "20261019" if s[:2] == "19" else "20261109"
    return f"run_0001_{day}_{s}"


def demo_grasp(root):
    out = {}
    for p, names in POS.items():
        poses = []
        for s in names.split():
            z = np.load(root / "datasets/mecharm_redblock_box_deep_even10_v1/raw_episodes" / ep_name(s) / "episode.npz")
            st = z["state"]
            i = int(np.argmax(st[:, 6] > 0.5))
            poses.append(st[i, :6])
        out[p] = np.array(poses)
    return out


def run_poses(rd):
    rows = list(csv.DictReader(open(rd / "recording/states.csv")))
    last = None
    close = None
    close_t = None
    for r in rows:
        if r["event_type"] == "actual" and r["j0"]:
            last = [float(r[f"j{k}"]) for k in range(6)]
        if r["event_type"] == "gripper_cmd" and r["gripper_state"] == "1" and close is None:
            close, close_t = last, float(r["ts"])
    pad = None
    for line in open(rd / "log.jsonl"):
        d = json.loads(line)
        if d.get("type") == "pad" and d.get("measured_before"):
            if close_t is None or d["t_unix"] < close_t:
                pad = d["measured_before"]
            break
    meta = json.load(open(rd / f"{rd.name}.json"))
    return close, pad, meta


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--data-root", default="/Volumes/KIOXIA/r2r2r-data")
    a = ap.parse_args()
    root = Path(a.data_root)
    g = demo_grasp(root)
    mean = {p: v.mean(0) for p, v in g.items()}
    print("お手本 50 本の, 位置ごとのつかむ姿勢 (平均 / 最小〜最大)")
    print("位置 | " + " | ".join(f"j{k}" for k in range(6)))
    for p, v in g.items():
        print(f"{p} | " + " | ".join(f"{v[:, k].mean():+.1f} ({v[:, k].min():+.1f}〜{v[:, k].max():+.1f})" for k in range(6)))
    print()
    print("位置どうしの, つかむ姿勢の平均の距離 (度)")
    for p in mean:
        print(f"{p} | " + " | ".join(f"{np.linalg.norm(mean[p] - mean[q]):.1f}" for q in mean))
    print()
    print("2026-11-10 の実機推論 (deep1)")
    print("run | 置いた所 | 結果 | 補正 | AI が行った所 j0〜j5 | 近い位置 (距離) | 位置ごとの距離 1〜5 | 爪を閉じた姿勢 j0〜j5")
    for stem, label in RUNS:
        rd = root / "runs/pi05_policy" / f"pi05_20261110_{stem}"
        close, pad, meta = run_poses(rd)
        went = pad if pad is not None else close
        corr = meta.get("corrections", 0)
        res = meta.get("outcome") or meta.get("result")
        if went is None:
            print(f"{stem} | {label} | {res} | {corr} | 爪を閉じる前に終えた | - | - | -")
            continue
        dist = {p: float(np.linalg.norm(np.array(went) - mean[p])) for p in mean}
        near = min(dist, key=dist.get)
        cl = " ".join(f"{x:+.1f}" for x in close) if close else "閉じていない"
        print(f"{stem} | {label} | {res} | {corr} | " + " ".join(f"{x:+.1f}" for x in went)
              + f" | {near} ({dist[near]:.1f}) | " + " ".join(f"{dist[p]:.1f}" for p in mean) + f" | {cl}"
              + (" | 補正の前" if pad is not None else ""))


if __name__ == "__main__":
    main()
