"""LED グループ別 sanity check.

下/右/左 の各 LED 基板の LED だけを ON にしたときの輝度マップを生成し，
シミュが 3 つの照明源を正しく独立に扱えているかを目視確認する.

各グループの輝度マップ:
    bottom: led_bottom_0 〜 led_bottom_5 (6 個) のみ ON
    right : led_right_0  〜 led_right_5  (6 個) のみ ON
    left  : led_left_0   〜 led_left_5   (6 個) のみ ON

期待される観察:
    - 方向性: 各単独 ON で評価板上の光が LED 基板側に偏る
    - 対称性: right と left は左右対称パターン
    - 線形性: bottom + right + left ≒ 全 ON ベースライン (Mitsuba linear renderer)
    - 量的バランス: 3 グループの mean がほぼ同じ (各 6 個・同 radiance)

実行方法:
    uv run python scripts/sanity_led_groups.py

前提条件:
    - configs/scene_baseline.yaml が存在し lights に led_bottom_*/right_*/left_* が
      命名規則どおりに揃っていること
    - sm-render が PATH に通っていること
    - output/baseline/luminance.npy が全 ON ベースラインとして存在すること

出力:
    - output/led_group_sanity/{bottom,right,left}/luminance.npy
    - output/led_group_sanity/{bottom,right,left}/render.png
    - configs/_tmp_sanity/scene_{group}.yaml (一時 YAML 残置)
"""

from __future__ import annotations

import subprocess
import sys
import time
from pathlib import Path

import yaml

# ---------------------------------------------------------------------------
# 定数
# ---------------------------------------------------------------------------

ROOT = Path(__file__).resolve().parents[1]

TEMPLATE_YAML = ROOT / "configs" / "scene_baseline.yaml"
TMP_DIR = ROOT / "configs" / "_tmp_sanity"
OUTPUT_BASE = ROOT / "output" / "led_group_sanity"

GROUPS = ["bottom", "right", "left"]


def _generate_tmp_yaml(group: str) -> Path:
    """指定グループの LED だけを残した一時 YAML を生成する.

    Args:
        group: "bottom" / "right" / "left" のいずれか.

    Returns:
        生成した一時 YAML のパス.
    """
    TMP_DIR.mkdir(parents=True, exist_ok=True)

    with TEMPLATE_YAML.open(encoding="utf-8") as f:
        data = yaml.safe_load(f)

    # geometry.meshes の STL 相対パスを絶対化（_tmp_sanity からも解決できるように）
    template_base = TEMPLATE_YAML.parent
    for item in data.get("geometry", {}).get("meshes", []):
        rel_path = item.get("path")
        if rel_path and not Path(rel_path).is_absolute():
            item["path"] = str((template_base / rel_path).resolve())

    # lights を指定グループのみに絞り込む
    prefix = f"led_{group}_"
    data["lights"] = [light for light in data["lights"] if light["id"].startswith(prefix)]

    # 識別用の name を付与
    data["name"] = f"sanity_led_{group}"

    tmp_path = TMP_DIR / f"scene_{group}.yaml"
    with tmp_path.open("w", encoding="utf-8") as f:
        yaml.dump(data, f, allow_unicode=True, default_flow_style=False, sort_keys=False)

    return tmp_path


def _run_render(tmp_yaml: Path, output_dir: Path, group: str) -> int:
    """sm-render を実行して終了コードを返す.

    Args:
        tmp_yaml: 一時 YAML のパス.
        output_dir: 出力ディレクトリ.
        group: ジョブ識別子（ログ用）.

    Returns:
        終了コード（0=成功）.
    """
    cmd = ["sm-render", "--scene", str(tmp_yaml), "--output", str(output_dir)]
    print(f"  [run] {' '.join(cmd)}")
    result = subprocess.run(cmd, check=False)  # noqa: S603
    if result.returncode != 0:
        msg = f"  [ERROR] sm-render ({group}) failed (returncode={result.returncode})"
        print(msg, file=sys.stderr)
    return result.returncode


def main() -> int:
    """sanity check のメイン処理.

    Returns:
        終了コード（全ジョブ成功なら 0，失敗があれば 1）.
    """
    if not TEMPLATE_YAML.exists():
        print(f"エラー: テンプレート YAML が見つかりません: {TEMPLATE_YAML}", file=sys.stderr)
        return 1

    OUTPUT_BASE.mkdir(parents=True, exist_ok=True)

    print(f"=== LED グループ別 sanity check: {len(GROUPS)} jobs ===")
    print(f"  groups: {GROUPS}")
    print(f"  output: {OUTPUT_BASE}")
    print()

    failed: list[str] = []
    total_start = time.time()

    for idx, group in enumerate(GROUPS, start=1):
        print(f"--- Job {idx}/{len(GROUPS)}: {group} ---")
        job_start = time.time()

        tmp_yaml = _generate_tmp_yaml(group)
        print(f"  tmp YAML: {tmp_yaml}")

        output_dir = OUTPUT_BASE / group
        if _run_render(tmp_yaml, output_dir, group) != 0:
            failed.append(group)
            print(f"  -> スキップ: render 失敗\n")
            continue

        elapsed = time.time() - job_start
        print(f"  -> 完了 ({elapsed:.1f}s)\n")

    total_elapsed = time.time() - total_start
    print(f"=== 完了: {len(GROUPS) - len(failed)}/{len(GROUPS)} 成功, 総時間 {total_elapsed:.1f}s ===")

    if failed:
        print(f"失敗ジョブ: {failed}", file=sys.stderr)
        return 1
    return 0


if __name__ == "__main__":
    sys.exit(main())
