"""auto_params / param_store モジュールのテスト"""

from pathlib import Path
from unittest.mock import patch

import pytest

from pc.steering.pd_control import PdParams
from pc.vision.line_detector import ImageParams


class TestAutoParams:
    """auto_params の保存・読み込みテスト"""

    @pytest.fixture(autouse=True)
    def _use_tmp_dir(self, tmp_path: Path) -> None:
        """PARAMS_DIR を一時ディレクトリに差し替える"""
        with patch(
            "pc.steering.auto_params.PARAMS_DIR",
            tmp_path,
        ):
            with patch(
                "pc.steering.auto_params._CONTROL_FILE",
                tmp_path / "control.json",
            ):
                yield

    def test_save_load_control_roundtrip(self) -> None:
        """PD パラメータと手法を保存→読込で復元できる"""
        from pc.steering.auto_params import (
            load_control,
            save_control,
        )
        params = PdParams(
            kp=1.0, kh=0.5, kd=0.2,
            max_steer_rate=0.05,
            max_throttle=0.6, speed_k=0.4,
        )
        save_control(params, "blackhat")
        loaded, method = load_control()
        assert method == "blackhat"
        assert loaded.kp == pytest.approx(1.0)
        assert loaded.kh == pytest.approx(0.5)
        assert loaded.max_throttle == pytest.approx(0.6)

    def test_load_control_missing_file(self) -> None:
        """ファイルがない場合はデフォルト値を返す"""
        from pc.steering.auto_params import load_control
        params, method = load_control()
        assert method == "current"
        assert params.kp == PdParams().kp

    def test_save_load_detect_params(
        self, tmp_path: Path,
    ) -> None:
        """検出パラメータを手法別に保存→復元できる"""
        from pc.steering.auto_params import (
            load_detect_params,
            save_detect_params,
        )
        ip = ImageParams(
            method="dual_norm",
            adaptive_block=31,
            adaptive_c=15,
        )
        save_detect_params("dual_norm", ip)
        loaded = load_detect_params("dual_norm")
        assert loaded.method == "dual_norm"
        assert loaded.adaptive_block == 31
        assert loaded.adaptive_c == 15

    def test_load_detect_unknown_method(self) -> None:
        """未知の手法は指定手法のデフォルト値を返す"""
        from pc.steering.auto_params import (
            load_detect_params,
        )
        loaded = load_detect_params("unknown")
        assert loaded.method == "unknown"


class TestParamStore:
    """param_store の保存・読み込みテスト"""

    @pytest.fixture(autouse=True)
    def _use_tmp_dir(self, tmp_path: Path) -> None:
        """プリセットファイルを一時ディレクトリに差し替える"""
        with patch(
            "pc.steering.param_store._PD_FILE",
            tmp_path / "presets_pd.json",
        ):
            with patch(
                "pc.steering.param_store._IMAGE_FILE",
                tmp_path / "presets_image.json",
            ):
                yield

    def test_pd_preset_add_load_delete(self) -> None:
        """PD プリセットの追加・読込・削除"""
        from pc.steering.param_store import (
            PdPreset,
            add_pd_preset,
            delete_pd_preset,
            load_pd_presets,
        )
        # 追加
        preset = PdPreset(
            title="テスト",
            memo="メモ",
            params=PdParams(kp=2.0),
        )
        add_pd_preset(preset)
        presets = load_pd_presets()
        assert len(presets) == 1
        assert presets[0].title == "テスト"
        assert presets[0].params.kp == pytest.approx(2.0)

        # 削除
        delete_pd_preset(0)
        assert len(load_pd_presets()) == 0

    def test_image_preset_add_load(self) -> None:
        """画像処理プリセットの追加・読込"""
        from pc.steering.param_store import (
            ImagePreset,
            add_image_preset,
            load_image_presets,
        )
        ip = ImageParams(
            method="blackhat", blackhat_ksize=51,
        )
        add_image_preset(ImagePreset(
            title="BH51", memo="テスト", image_params=ip,
        ))
        presets = load_image_presets()
        assert len(presets) == 1
        assert presets[0].image_params.blackhat_ksize == 51

    def test_load_empty(self) -> None:
        """ファイルがない場合は空リストを返す"""
        from pc.steering.param_store import (
            load_image_presets,
            load_pd_presets,
        )
        assert load_pd_presets() == []
        assert load_image_presets() == []
