# pyright: reportCallIssue=none
# Mitsuba 3 は variant ベースの動的属性解決を行うため Pylance/Pyright が
# mi.* を object 型と推論し reportCallIssue を誤検知する（coding-style.md の方針）．
"""YAML センサ定義 → Mitsuba sensor dict 変換モジュール．"""

from __future__ import annotations

from sm_tias_lightsim.runtime.llvm_init import ensure_drjit_libllvm_path
from sm_tias_lightsim.scene.schema import SensorConfig

# mitsuba を import した時点で Dr.Jit が LLVM の初期化を試みる．そのため
# DRJIT_LIBLLVM_PATH の自動探索は import より前に済ませておく必要がある．
# 本モジュールはモジュールレベルで mitsuba を import するので，
# render/runner.py の探索呼び出しでは手遅れになる（環境変数未設定の環境では
# レンダリングが ImportError で失敗し，slow マークのレンダテストが全滅していた）．
ensure_drjit_libllvm_path()

import mitsuba as mi  # noqa: E402


def build_sensor_dict(sensor: SensorConfig, position_scale: float) -> dict:
    """SensorConfig を Mitsuba sensor dict に変換する．

    Args:
        sensor: SceneConfig.sensor．
        position_scale: 座標スケール係数（mm→m なら 0.001）．position/target にも適用．

    Returns:
        Mitsuba sensor dict（perspective または orthographic）．
    """
    pos = [c * position_scale for c in sensor.position]
    target = [c * position_scale for c in sensor.target]
    up = list(sensor.up)

    film = {
        "type": "hdrfilm",
        "width": sensor.film.width,
        "height": sensor.film.height,
        "rfilter": {"type": sensor.film.rfilter},
    }
    sampler = {"type": "independent", "sample_count": 1}

    if sensor.type == "perspective":
        to_world = mi.ScalarTransform4f().look_at(origin=pos, target=target, up=up)
        return {
            "type": "perspective",
            "fov": sensor.fov_deg,
            "to_world": to_world,
            "film": film,
            "sampler": sampler,
        }

    # orthographic: ortho_scale (mm) を画像幅・高さの半幅として使う．
    # Mitsuba の orthographic は clip-space X,Y が ±1 → look_at × scale で実空間範囲を決める．
    if sensor.ortho_scale is None:
        msg = "orthographic sensor requires ortho_scale (validated in schema)"
        raise RuntimeError(msg)
    sx_m = sensor.ortho_scale[0] * position_scale
    sy_m = sensor.ortho_scale[1] * position_scale
    to_world = (
        mi.ScalarTransform4f().look_at(origin=pos, target=target, up=up)
        # Z 方向はスケールしない（奥行き軸はそのまま look_at の視錐台に従う）
        @ mi.ScalarTransform4f().scale([sx_m, sy_m, 1.0])
    )
    return {
        "type": "orthographic",
        "to_world": to_world,
        "film": film,
        "sampler": sampler,
    }
