# -*- coding: utf-8 -*-
"""
YamlConfigManager、read_yaml/update_yaml、read_order_manifest/update_order_manifest、rescan/get_cached/get 测试。
无缓存、每次从磁盘读取。
"""

import tempfile
from pathlib import Path

import pytest

from pb_calibration import (
    parse,
    build,
    YamlConfigManager,
    read_yaml,
    update_yaml,
    read_order_manifest,
    update_order_manifest,
)


def _valid_pb_path():
    p = Path(__file__).resolve().parent / "vehicle_config.pb.txt"
    if not p.exists():
        pytest.skip(f"测试输入不存在: {p}")
    return str(p)


def test_yaml_manager_default_path_read_write():
    """YamlConfigManager：构造传入 default_yaml_dir，读/写使用默认路径，读写路径一致。"""
    pb_path = _valid_pb_path()
    with tempfile.TemporaryDirectory(prefix="pb_cal_mgr_") as tmpdir:
        parse(pb_path, tmpdir)
        mgr = YamlConfigManager(tmpdir)
        # 读使用默认路径
        om = mgr.read_order_manifest()
        assert "vehicle_info_file" in om and "extrinsics" in om
        vi = mgr.read_yaml("vehicle_info.yaml")
        assert isinstance(vi, dict)
        # 写回默认路径，再读到的应一致
        mgr.update_yaml("vehicle_info.yaml", {"model": "test_model_updated"})
        vi2 = mgr.read_yaml("vehicle_info.yaml")
        assert vi2.get("model") == "test_model_updated"


def test_read_yaml_returns_dict():
    """read_yaml：读 order_manifest.yaml、vehicle_info.yaml 等，返回 dict 且含预期 key。"""
    pb_path = _valid_pb_path()
    with tempfile.TemporaryDirectory(prefix="pb_cal_read_") as tmpdir:
        parse(pb_path, tmpdir)
        root = Path(tmpdir)
        om = read_yaml(str(root / "order_manifest.yaml"))
        assert isinstance(om, dict)
        assert "vehicle_info_file" in om
        vi = read_yaml(str(root / "vehicle_info.yaml"))
        assert isinstance(vi, dict)


def test_update_yaml_in_place_and_new_file():
    """update_yaml：原地修改与写出到新相对路径，再 read_yaml 从磁盘读取断言修改已落盘。"""
    pb_path = _valid_pb_path()
    with tempfile.TemporaryDirectory(prefix="pb_cal_upd_") as tmpdir:
        parse(pb_path, tmpdir)
        mgr = YamlConfigManager(tmpdir)
        mgr.update_yaml("vehicle_info.yaml", {"plate": "京A00001"})
        vi = mgr.read_yaml("vehicle_info.yaml")
        assert vi.get("plate") == "京A00001"
        mgr.update_yaml("vehicle_info.yaml", {"vin": "VIN999"}, output_relative_path="vehicle_info_copy.yaml")
        vi_copy = mgr.read_yaml("vehicle_info_copy.yaml")
        assert vi_copy.get("vin") == "VIN999"


def test_read_order_manifest_structure():
    """read_order_manifest：对 parse 得到的目录调用，结构与 generate_order_manifest 一致。"""
    pb_path = _valid_pb_path()
    with tempfile.TemporaryDirectory(prefix="pb_cal_om_") as tmpdir:
        parse(pb_path, tmpdir)
        om = read_order_manifest(tmpdir)
        for key in ("vehicle_info_file", "vehicle_param_file", "extrinsics", "intrinsics"):
            assert key in om, f"order_manifest 缺少 key: {key}"


def test_update_order_manifest_then_build():
    """update_order_manifest：更新后 build 能正确组装。"""
    pb_path = _valid_pb_path()
    with tempfile.TemporaryDirectory(prefix="pb_cal_om_build_") as tmpdir:
        parse(pb_path, tmpdir)
        update_order_manifest(tmpdir, {"vehicle_info_file": "vehicle_info.yaml"})
        out_pb = Path(tmpdir) / "out.pb.txt"
        build(tmpdir, str(out_pb))
        assert out_pb.exists()


def test_rescan_get_cached_from_disk():
    """rescan / get_cached：从磁盘组装并返回；修改磁盘文件后再次 rescan 返回磁盘最新内容。"""
    pb_path = _valid_pb_path()
    with tempfile.TemporaryDirectory(prefix="pb_cal_rescan_") as tmpdir:
        parse(pb_path, tmpdir)
        mgr = YamlConfigManager(tmpdir)
        data1 = mgr.rescan()
        assert "order_manifest" in data1 and "vehicle_info" in data1
        data2 = mgr.get_cached()
        assert "vehicle_param" in data2
        # 直接写文件模拟其他程序修改
        vi_path = Path(tmpdir) / "vehicle_info.yaml"
        with open(vi_path, "r", encoding="utf-8") as f:
            import yaml
            vi = yaml.safe_load(f) or {}
        vi["model"] = "external_edit"
        with open(vi_path, "w", encoding="utf-8") as f:
            yaml.dump(vi, f, allow_unicode=True, default_flow_style=False, sort_keys=False)
        data3 = mgr.rescan()
        assert data3["vehicle_info"].get("model") == "external_edit"


def test_get_key_from_disk():
    """get(key)：get('order_manifest')、get('vehicle_info') 等每次从磁盘读对应文件并返回。"""
    pb_path = _valid_pb_path()
    with tempfile.TemporaryDirectory(prefix="pb_cal_get_") as tmpdir:
        parse(pb_path, tmpdir)
        mgr = YamlConfigManager(tmpdir)
        om = mgr.get("order_manifest")
        assert om is not None and "vehicle_info_file" in om
        vi = mgr.get("vehicle_info")
        assert vi is not None and isinstance(vi, dict)
        none_result = mgr.get("nonexistent.yaml")
        assert none_result is None or (isinstance(none_result, dict) and not none_result)


def test_functional_update_order_manifest_output_dir():
    """update_order_manifest(yaml_dir, updates, output_dir)：写出到 output_dir。"""
    pb_path = _valid_pb_path()
    with tempfile.TemporaryDirectory(prefix="pb_cal_fom_") as tmpdir:
        parse(pb_path, tmpdir)
        other_dir = Path(tmpdir) / "other"
        other_dir.mkdir()
        update_order_manifest(tmpdir, {"vehicle_info_file": "vehicle_info.yaml"}, output_dir=str(other_dir))
        assert (other_dir / "order_manifest.yaml").exists()
