"""config.py 单元测试"""

from pathlib import Path

import yaml

from index1.config import Config, load_config, save_config, _load_yaml, _merge_into_config


class TestConfigDefaults:
    def test_default_values(self):
        config = Config()
        assert config.embedding_model == "nomic-embed-text"
        assert config.embedding_dim == 768
        assert config.ollama_url == "http://localhost:11434"
        assert config.top_k == 10
        assert config.rrf_k == 60
        assert config.collection == "default"
        assert config.watch_paths == []

    def test_default_db_path(self):
        config = Config()
        assert "knowledge.db" in config.db_path
        assert ".claude-index1" in config.db_path

    def test_custom_db_path(self):
        config = Config(db_path="/tmp/test.db")
        assert config.db_path == "/tmp/test.db"

    def test_db_path_resolved(self):
        config = Config(db_path="~/test.db")
        resolved = config.db_path_resolved
        assert "~" not in str(resolved)


class TestLoadYaml:
    def test_nonexistent_file(self):
        assert _load_yaml(Path("/nonexistent/config.yaml")) == {}

    def test_valid_yaml(self, tmp_path):
        cfg = tmp_path / "config.yaml"
        cfg.write_text("embedding_model: embeddinggemma\ntop_k: 5\n")
        result = _load_yaml(cfg)
        assert result == {"embedding_model": "embeddinggemma", "top_k": 5}

    def test_invalid_yaml(self, tmp_path):
        cfg = tmp_path / "config.yaml"
        cfg.write_text(": invalid: yaml: [")
        assert _load_yaml(cfg) == {}

    def test_non_dict_yaml(self, tmp_path):
        cfg = tmp_path / "config.yaml"
        cfg.write_text("- item1\n- item2\n")
        assert _load_yaml(cfg) == {}


class TestMerge:
    def test_merge_valid_keys(self):
        config = Config()
        _merge_into_config(config, {"top_k": 20, "collection": "test"})
        assert config.top_k == 20
        assert config.collection == "test"

    def test_ignore_invalid_keys(self):
        config = Config()
        _merge_into_config(config, {"nonexistent_key": "value"})
        # 不报错，静默忽略

    def test_ignore_none_values(self):
        config = Config()
        original_top_k = config.top_k
        _merge_into_config(config, {"top_k": None})
        assert config.top_k == original_top_k


class TestLoadConfig:
    def test_defaults_only(self, tmp_path, monkeypatch):
        monkeypatch.setattr("index1.config.GLOBAL_CONFIG_FILE", tmp_path / "no-global.yaml")
        config = load_config(project_path=tmp_path)
        assert config.embedding_model == "nomic-embed-text"

    def test_project_overrides(self, tmp_path, monkeypatch):
        monkeypatch.setattr("index1.config.GLOBAL_CONFIG_FILE", tmp_path / "no-global.yaml")
        project_cfg = tmp_path / ".index1.yaml"
        project_cfg.write_text("top_k: 20\ncollection: myproject\n")
        config = load_config(project_path=tmp_path)
        assert config.top_k == 20
        assert config.collection == "myproject"
        # 未覆盖的保持默认
        assert config.embedding_model == "nomic-embed-text"

    def test_project_overrides_global(self, tmp_path, monkeypatch):
        # 模拟全局配置
        global_dir = tmp_path / "global"
        global_dir.mkdir()
        global_cfg = global_dir / "config.yaml"
        global_cfg.write_text("top_k: 15\nembedding_model: embeddinggemma\n")

        # 项目配置只覆盖 top_k
        project_dir = tmp_path / "project"
        project_dir.mkdir()
        project_cfg = project_dir / ".index1.yaml"
        project_cfg.write_text("top_k: 25\n")

        monkeypatch.setattr("index1.config.GLOBAL_CONFIG_FILE", global_cfg)
        config = load_config(project_path=project_dir)

        # 项目覆盖全局
        assert config.top_k == 25
        # 全局覆盖默认
        assert config.embedding_model == "embeddinggemma"


class TestSaveConfig:
    def test_save_non_default(self, tmp_path):
        config = Config(top_k=20, collection="test")
        save_path = tmp_path / "saved.yaml"
        save_config(config, path=save_path)

        with open(save_path) as f:
            data = yaml.safe_load(f)

        assert data["top_k"] == 20
        assert data["collection"] == "test"
        # 默认值不保存
        assert "embedding_model" not in data
        assert "rrf_k" not in data

    def test_save_creates_parent_dirs(self, tmp_path):
        config = Config(top_k=30)
        save_path = tmp_path / "sub" / "dir" / "config.yaml"
        save_config(config, path=save_path)
        assert save_path.is_file()
