# pyright: reportArgumentType=none, reportCallIssue=none
"""scene/schema.py の MetricsConfig.radial_min_max フィールド仕様ベーステスト．

仕様出典:
- docs/04_SPEC/SPEC_04_評価仕様.md（動径指標・評価パイプライン）
- docs/04_SPEC/SPEC_02_シーン定義仕様.md（evaluation/metrics セクション）
- src/sm_tias_lightsim/scene/schema.py（MetricsConfig 定義）

テスト方針:
  - Pydantic モデルを直接構築して振る舞いを検証する（YAML パースは別途）
  - 既存フィールド（cov/std/max_min/radial_profile）への非干渉を確認する
  - YAML ロード経由の動作も確認する
"""

from __future__ import annotations

import pytest
import yaml
from pydantic import ValidationError

from sm_tias_lightsim.scene.schema import EvaluationConfig, MetricsConfig

# ---------------------------------------------------------------------------
# A1. 既定値: MetricsConfig() で radial_min_max == False
# ---------------------------------------------------------------------------


def test_metrics_radial_min_max_default_is_false():
    """MetricsConfig() のインスタンスで radial_min_max の既定値が False であること．

    仕様: MetricsConfig.radial_min_max: bool = Field(default=False, ...)
    (schema.py MetricsConfig)
    """
    cfg = MetricsConfig()
    assert cfg.radial_min_max is False


# ---------------------------------------------------------------------------
# A2. 明示 True: MetricsConfig(radial_min_max=True) で True になること
# ---------------------------------------------------------------------------


def test_metrics_radial_min_max_explicit_true():
    """MetricsConfig(radial_min_max=True) で radial_min_max が True になること．

    仕様: MetricsConfig.radial_min_max: bool = Field(default=False, ...)
    True を明示指定すると True が設定される（schema.py MetricsConfig）
    """
    cfg = MetricsConfig(radial_min_max=True)
    assert cfg.radial_min_max is True


def test_metrics_radial_min_max_explicit_false():
    """MetricsConfig(radial_min_max=False) で radial_min_max が False になること．

    仕様: MetricsConfig.radial_min_max: bool = Field(default=False, ...)
    """
    cfg = MetricsConfig(radial_min_max=False)
    assert cfg.radial_min_max is False


# ---------------------------------------------------------------------------
# A3. 既存フィールドへの非干渉
# ---------------------------------------------------------------------------


def test_metrics_radial_min_max_does_not_affect_cov_default():
    """radial_min_max 指定有無で cov の既定値が変わらないこと．

    仕様: MetricsConfig.cov: bool = Field(default=True, ...) — 非干渉
    """
    cfg_default = MetricsConfig()
    cfg_true = MetricsConfig(radial_min_max=True)

    assert cfg_default.cov == cfg_true.cov
    assert cfg_default.cov is True


def test_metrics_radial_min_max_does_not_affect_std_default():
    """radial_min_max 指定有無で std の既定値が変わらないこと．

    仕様: MetricsConfig.std: bool = Field(default=True, ...) — 非干渉
    """
    cfg_default = MetricsConfig()
    cfg_true = MetricsConfig(radial_min_max=True)

    assert cfg_default.std == cfg_true.std
    assert cfg_default.std is True


def test_metrics_radial_min_max_does_not_affect_max_min_default():
    """radial_min_max 指定有無で max_min の既定値が変わらないこと．

    仕様: MetricsConfig.max_min: bool = Field(default=True, ...) — 非干渉
    """
    cfg_default = MetricsConfig()
    cfg_true = MetricsConfig(radial_min_max=True)

    assert cfg_default.max_min == cfg_true.max_min
    assert cfg_default.max_min is True


def test_metrics_radial_min_max_does_not_affect_radial_profile_default():
    """radial_min_max 指定有無で radial_profile の既定値が変わらないこと．

    仕様: MetricsConfig.radial_profile: bool = Field(default=True, ...) — 非干渉
    radial_min_max とは独立したフィールド（schema.py MetricsConfig）
    """
    cfg_default = MetricsConfig()
    cfg_true = MetricsConfig(radial_min_max=True)

    assert cfg_default.radial_profile == cfg_true.radial_profile
    assert cfg_default.radial_profile is True


def test_metrics_config_all_fields_together():
    """radial_min_max=True を含む全フィールド指定で正常にパースされること．

    仕様: MetricsConfig の全フィールドが独立して指定可能（schema.py MetricsConfig）
    """
    cfg = MetricsConfig(
        cov=True, std=False, max_min=True, radial_profile=False, radial_min_max=True
    )
    assert cfg.cov is True
    assert cfg.std is False
    assert cfg.max_min is True
    assert cfg.radial_profile is False
    assert cfg.radial_min_max is True


def test_metrics_config_is_frozen_for_radial_min_max():
    """MetricsConfig が frozen（イミュータブル）で radial_min_max も変更不可であること．

    仕様: _FrozenBase → frozen=True（schema.py ConfigDict）
    """
    cfg = MetricsConfig()
    with pytest.raises(ValidationError):
        cfg.radial_min_max = True  # type: ignore[misc]


# ---------------------------------------------------------------------------
# A4. YAML ロード: YAML で metrics.radial_min_max: true を指定すると True
# ---------------------------------------------------------------------------


def test_yaml_load_metrics_radial_min_max_true():
    """YAML で metrics.radial_min_max: true を指定したとき True が反映されること．

    仕様: EvaluationConfig.metrics.radial_min_max が YAML 経由で設定される
    (schema.py MetricsConfig / EvaluationConfig)
    """
    yaml_content = """\
roi:
  type: image_pixel
  x: 0
  y: 0
  width: 100
  height: 100
metrics:
  cov: true
  std: true
  max_min: true
  radial_profile: true
  radial_min_max: true
"""
    data = yaml.safe_load(yaml_content)
    cfg = EvaluationConfig.model_validate(data)
    assert cfg.metrics is not None
    assert cfg.metrics.radial_min_max is True


def test_yaml_load_metrics_radial_min_max_false():
    """YAML で metrics.radial_min_max: false を指定したとき False が反映されること．

    仕様: MetricsConfig.radial_min_max: bool = Field(default=False, ...)
    """
    yaml_content = """\
roi:
  type: image_pixel
  x: 0
  y: 0
  width: 100
  height: 100
metrics:
  cov: true
  radial_min_max: false
"""
    data = yaml.safe_load(yaml_content)
    cfg = EvaluationConfig.model_validate(data)
    assert cfg.metrics is not None
    assert cfg.metrics.radial_min_max is False


def test_yaml_load_metrics_radial_min_max_omitted_defaults_false():
    """YAML で metrics.radial_min_max を省略したとき既定値 False が設定されること．

    仕様: MetricsConfig.radial_min_max: bool = Field(default=False, ...)
    既存 YAML（eval_baseline.yaml / eval_baseline_linear.yaml / eval_real.yaml 相当）は
    radial_min_max を含まないため後方互換として False になる必要がある
    """
    yaml_content = """\
roi:
  type: image_pixel
  x: 0
  y: 0
  width: 100
  height: 100
metrics:
  cov: true
  std: true
  max_min: true
  radial_profile: true
"""
    data = yaml.safe_load(yaml_content)
    cfg = EvaluationConfig.model_validate(data)
    assert cfg.metrics is not None
    assert cfg.metrics.radial_min_max is False


def test_yaml_load_eval_baseline_linear_equivalent_has_radial_min_max_false():
    """eval_baseline_linear.yaml 相当の YAML では radial_min_max が False であること．

    仕様: 既存 configs（eval_baseline.yaml / eval_baseline_linear.yaml）は
    radial_min_max を含まず，未指定時は False（後方互換）
    """
    yaml_content = """\
roi:
  type: image_pixel
  x: 24
  y: 37
  width: 464
  height: 450
zones:
  enabled: true
  boundaries:
  - 0.33
  - 0.66
metrics:
  cov: true
  std: true
  max_min: true
  radial_profile: true
normalization:
  enabled: true
  type: mean_anchor
  target_mean: 146.7146
"""
    data = yaml.safe_load(yaml_content)
    cfg = EvaluationConfig.model_validate(data)
    assert cfg.metrics is not None
    assert cfg.metrics.radial_min_max is False
