"""座標変換ユーティリティモジュール．

単位変換（mm ↔ m）および LoadedMesh への適用を提供する．
座標系の回転・並進は Step 4（シーン構築）で実装する．
"""

from __future__ import annotations

import dataclasses
from typing import Literal

import numpy

from sm_tias_lightsim.geometry.loader import LoadedMesh

_MM_PER_M = 1000.0
_M_PER_MM = 0.001


def mm_to_m(value: numpy.ndarray | float) -> numpy.ndarray | float:
    """ミリメートル単位の数値配列をメートル単位に変換する．

    Args:
        value: スカラまたは ndarray（任意 shape）．

    Returns:
        入力と同じ shape の値．スカラなら float 1 つ，ndarray なら新しい配列．
    """
    return value * _M_PER_MM


def scale_vertices(mesh: LoadedMesh, target_unit: Literal["mm", "m"]) -> LoadedMesh:
    """LoadedMesh の頂点座標を指定単位にスケール変換した新インスタンスを返す．

    frozen dataclass の不変性を維持するため，常に新規インスタンスを返す．
    元と同じ単位が指定された場合も頂点配列はコピーされる（関数の純粋性のため）．

    Args:
        mesh: 元のメッシュ．
        target_unit: 変換先の単位．

    Returns:
        頂点が target_unit にスケールされた新 LoadedMesh．
        unit フィールドは target_unit に更新される．

    Raises:
        ValueError: 未対応の unit の組み合わせが指定された場合．
    """
    if mesh.unit == target_unit:
        new_vertices = mesh.vertices.copy()
    elif mesh.unit == "mm" and target_unit == "m":
        new_vertices = mesh.vertices * _M_PER_MM
    elif mesh.unit == "m" and target_unit == "mm":
        new_vertices = mesh.vertices * _MM_PER_M
    else:
        msg = f"Unsupported unit conversion: '{mesh.unit}' -> '{target_unit}'"
        raise ValueError(msg)

    return dataclasses.replace(mesh, vertices=new_vertices, unit=target_unit)
