"""render.seed（レンダの乱数シード）の仕様ベーステスト．

仕様出典:
- docs/04_SPEC/SPEC_02_シーン定義仕様.md「render」セクション（レンダ設定の YAML スキーマ．
  seed は本実装で追加された新フィールドで，仕様書側は Phase 4 の更新対象）
- docs/02_ENV/ENV_04_開発コマンド.md「研究室サーバでの実行」
  （同じ YAML・同じ seed でも読み込み直すと画素は変わるが，指標はほぼ一致する．
  ノイズの実現を意図的に変えたいときに seed を振る）

検証する仕様:
- seed は省略可能（既定 0）＝既存 YAML が書き換え無しで読める（後方互換）
- seed は 0 以上の整数のみ（負値は ValidationError）
- YAML に書いた値がそのまま SceneConfig に載る
"""

from __future__ import annotations

from pathlib import Path

import pytest
import yaml
from pydantic import ValidationError

from sm_tias_lightsim.scene.schema import RenderConfig, SceneConfig, load_scene_yaml

MINIMAL_YAML = Path(__file__).parent.parent / "fixtures" / "minimal.yaml"


# ---------------------------------------------------------------------------
# 既定値・後方互換
# ---------------------------------------------------------------------------


def test_seed_defaults_to_zero():
    """seed を省略すると 0 になること（既定値）．"""
    assert RenderConfig().seed == 0


def test_existing_yaml_without_seed_is_still_valid():
    """seed を書いていない既存 YAML がそのまま読め，seed=0 になること（後方互換）．"""
    config = load_scene_yaml(MINIMAL_YAML)
    assert config.render.seed == 0


def test_seed_omission_does_not_change_other_render_fields():
    """seed の追加で他の render 設定の既定値が変わっていないこと．"""
    render = RenderConfig()
    assert render.variant == "llvm_ad_rgb"
    assert render.integrator == "path"
    assert render.max_depth == 8
    assert render.spp == 256


# ---------------------------------------------------------------------------
# 正常系: 値の指定
# ---------------------------------------------------------------------------


@pytest.mark.parametrize("seed", [0, 1, 2, 42, 12345])
def test_seed_accepts_non_negative_integers(seed):
    """0 以上の整数はそのまま保持されること．"""
    assert RenderConfig(seed=seed).seed == seed


def test_seed_from_yaml_is_loaded(tmp_path: Path):
    """YAML の render.seed が SceneConfig に反映されること．"""
    data = yaml.safe_load(MINIMAL_YAML.read_text(encoding="utf-8"))
    data["render"]["seed"] = 7
    # メッシュの相対パスを保つため，YAML はフィクスチャと同じディレクトリ基準で解決する
    yaml_path = tmp_path / "scene_with_seed.yaml"
    yaml_path.write_text(yaml.safe_dump(data, allow_unicode=True), encoding="utf-8")
    config = SceneConfig.model_validate(yaml.safe_load(yaml_path.read_text(encoding="utf-8")))
    assert config.render.seed == 7


# ---------------------------------------------------------------------------
# 異常系
# ---------------------------------------------------------------------------


@pytest.mark.parametrize("seed", [-1, -42])
def test_negative_seed_raises_validation_error(seed):
    """負の seed は ValidationError になること（ge=0）．"""
    with pytest.raises(ValidationError):
        RenderConfig(seed=seed)


def test_non_integer_seed_raises_validation_error():
    """整数に解釈できない seed は ValidationError になること．"""
    with pytest.raises(ValidationError):
        RenderConfig(seed="abc")


def test_float_seed_with_fraction_raises_validation_error():
    """小数の seed は ValidationError になること（整数フィールド）．"""
    with pytest.raises(ValidationError):
        RenderConfig(seed=1.5)
