#!/usr/bin/env python3
"""make_images.py — LOG463 の記事に載せる画像を、上カメラの録画 (top.mp4) と横からのスマホ動画から作る (読むだけ).
使い方: python3 make_images.py   (B と SIDE のパスを環境に合わせる)
"""
import cv2, csv, os, subprocess
import numpy as np
from PIL import Image, ImageDraw, ImageFont
FP = "/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc"
F = lambda s: ImageFont.truetype(FP, s, index=0)
B = os.environ.get("RUNS", "/mnt/user-data/uploads/KIOXIA/r2r2r-data/runs/run_pick_place") + "/run_0001_20261109_"
SIDE = os.environ.get("SIDE", "/mnt/user-data/attachments/13cd2fb7-9204-537e-90d7-7ae29d9f967a")
OUT = "LOG463_images"


def times(s):
    st = list(csv.DictReader(open(B + s + "/recording/states.csv")))
    tp = [float(r["ts"]) for r in st if r["event_type"] == "stage" and r["stage"] == "PICK"][0]
    tc = [float(r["ts"]) for r in st if r["event_type"] == "gripper_cmd" and r["gripper_state"] == "1"][0]
    return tp, tc


def frame(s, t):
    fl = [(int(r["frame_idx"]), float(r["capture_ts"])) for r in csv.DictReader(open(B + s + "/recording/top_frame_log.csv"))]
    fi = min(fl, key=lambda x: abs(x[1] - t))[0]
    cap = cv2.VideoCapture(B + s + "/recording/top.mp4"); cap.set(cv2.CAP_PROP_POS_FRAMES, fi)
    ok, im = cap.read(); return im


def pil(im): return Image.fromarray(cv2.cvtColor(im, cv2.COLOR_BGR2RGB))


# 04: 前の教えた記録と作り直した記録. 閉じて 1.0 秒後の上カメラ
def img04():
    pairs = [("093045", "前の教えた記録（2022-10-13 に手で教えた）", "閉じて1秒後のはみ出し 43.4px（浅い）", (200, 30, 30)),
             ("094839", "ゲームパッドで作り直した記録", "閉じて1秒後のはみ出し 16.2px（深い）", (30, 90, 200))]
    W = 2 * 660 + 60; out = Image.new("RGB", (W, 564 + 110), "white"); d = ImageDraw.Draw(out)
    for i, (s, t1, t2, col) in enumerate(pairs):
        tp, tc = times(s); im = frame(s, tc + 1.0)
        c = cv2.resize(im[330:800, 330:880], (660, 564)); x = 20 + i * 680
        out.paste(pil(c), (x, 100)); d.text((x, 12), t1, font=F(28), fill=(30, 30, 30)); d.text((x, 56), t2 + f"　{s}", font=F(22), fill=col)
    out.save(f"{OUT}/LOG463_04_old_vs_new_pick.jpg", quality=88)


# 06: 下ろし始め〜閉じた直後の上カメラ. 普段の本と爪が乗った本
def img06():
    rows = [("101157", "普段の本　下ろし始めから閉じるまで 2.1秒"), ("101434", "爪がブロックに乗った本　8.9秒"),
            ("102109", "位置2 の普段の本　2.1秒"), ("103504", "位置2 で爪が乗った本　8.9秒")]
    crops = {"101157": (330, 780, 380, 860), "101434": (330, 780, 380, 860), "102109": None, "103504": None}
    strips = []
    for s, title in rows:
        tp, tc = times(s); ts = np.linspace(tp - 0.6, tc + 0.3, 8); fr = []
        for t in ts:
            im = frame(s, t)
            if crops[s]: y0, y1, x0, x1 = crops[s]
            else:
                y0, y1, x0, x1 = 380, 830, 400, 880
            fr.append(cv2.resize(im[y0:y1, x0:x1], (240, 225)))
        strips.append((title, np.hstack(fr)))
    W = strips[0][1].shape[1] + 40; out = Image.new("RGB", (W, len(strips) * 290 + 20), "white"); d = ImageDraw.Draw(out)
    for i, (title, st) in enumerate(strips):
        y = 10 + i * 290; d.text((20, y + 4), title, font=F(26), fill=(30, 30, 30) if "普段" in title else (200, 30, 30))
        out.paste(pil(st), (20, y + 50))
    out.save(f"{OUT}/LOG463_06_snag_top.jpg", quality=86)


# 横からのスマホ動画のコマを並べる
def side(src, dst, title, n=12, cols=4):
    v = f"{SIDE}/{src}"
    dur = float(subprocess.check_output(["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "csv=p=0", v]).decode())
    subprocess.run(["ffmpeg", "-loglevel", "error", "-y", "-i", v, "-vf", f"fps={n}/{dur},scale=420:-1,tile={cols}x{n // cols}",
                    "-frames:v", "1", "/tmp/_side.jpg"], check=True)
    im = Image.open("/tmp/_side.jpg"); out = Image.new("RGB", (im.width, im.height + 60), "white")
    ImageDraw.Draw(out).text((10, 12), title, font=F(28), fill=(30, 30, 30)); out.paste(im, (0, 60))
    out.save(f"{OUT}/{dst}", quality=84)


if __name__ == "__main__":
    os.makedirs(OUT, exist_ok=True)
    img04(); img06()
    side("35e64696-IMG_4242-compressed.mp4", "LOG463_03_side_shallow.jpg", "前の教えた記録の再生を横から（左上から右へ時間順）。爪の先でブロックを挟んでいる")
    side("b2d7b71d-IMG_4246-compressed.mp4", "LOG463_07_side_snag.jpg", "位置2 で爪がブロックに乗った回を横から（左上から右へ時間順）。2段目で爪が乗って止まる")
