"""
测试 config.py —— 默认参数、YAML 加载、环境变量覆盖
"""
import os
import sys
import tempfile
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent.parent))

import pytest
import yaml


class TestConfigDefaults:
    """默认参数验证"""

    def test_max_tokens_default(self):
        from aacode.config import ModelConfig
        cfg = ModelConfig()
        assert cfg.max_tokens == 96000, (
            f"Expected max_tokens=96000, got {cfg.max_tokens}"
        )

    def test_compact_trigger_tokens_default(self):
        from aacode.config import ContextConfig
        cfg = ContextConfig()
        assert cfg.compact_trigger_tokens == 256000, (
            f"Expected compact_trigger_tokens=256000, got {cfg.compact_trigger_tokens}"
        )

    def test_tool_execution_removed(self):
        """tool_execution 已从 TimeoutConfig 移除"""
        from aacode.config import TimeoutConfig
        cfg = TimeoutConfig()
        assert not hasattr(cfg, "tool_execution"), (
            "tool_execution should have been removed from TimeoutConfig"
        )

    def test_model_config_has_correct_fields(self):
        from aacode.config import ModelConfig
        cfg = ModelConfig()
        assert cfg.name == "deepseek-chat"
        assert cfg.temperature == 0.1
        assert cfg.gateway == "openai"

    def test_context_config_has_correct_fields(self):
        from aacode.config import ContextConfig
        cfg = ContextConfig()
        assert cfg.max_context_length == 131072
        assert cfg.compact_keep_rounds == 10
        assert cfg.compact_protect_first_rounds == 1, (
            f"Expected compact_protect_first_rounds=1, got {cfg.compact_protect_first_rounds}"
        )
        assert cfg.compact_protect_user_rounds == 2, (
            f"Expected compact_protect_user_rounds=2, got {cfg.compact_protect_user_rounds}"
        )

    def test_timeout_config_remaining_fields_present(self):
        from aacode.config import TimeoutConfig
        cfg = TimeoutConfig()
        assert cfg.shell_command == 30
        assert cfg.model_summary == 30
        assert cfg.file_search == 5
        assert cfg.code_execution == 60

    def test_settings_default_instance(self):
        """测试全新 Settings（无配置文件）获得正确默认值"""
        from aacode.config import Settings
        s = Settings(config_file="/nonexistent/default_test.yaml")
        assert s.model.max_tokens == 96000
        assert s.context.compact_trigger_tokens == 256000
        assert s.model.temperature == 0.1
        assert not hasattr(s.timeouts, "tool_execution")


class TestConfigYamlLoading:
    """YAML 配置加载"""

    def test_yaml_with_max_tokens(self):
        """YAML 配置可以覆盖 max_tokens"""
        from aacode.config import Settings
        yaml_content = """
model:
  max_tokens: 32000
  temperature: 0.5
"""
        with tempfile.TemporaryDirectory() as td:
            cfg_path = Path(td) / "test_config.yaml"
            cfg_path.write_text(yaml_content, encoding="utf-8")
            s = Settings(config_file=str(cfg_path))
            assert s.model.max_tokens == 32000
            assert s.model.temperature == 0.5

    def test_yaml_with_compact_trigger_tokens(self):
        from aacode.config import Settings
        yaml_content = """
context:
  compact_trigger_tokens: 128000
"""
        with tempfile.TemporaryDirectory() as td:
            cfg_path = Path(td) / "test_config.yaml"
            cfg_path.write_text(yaml_content, encoding="utf-8")
            s = Settings(config_file=str(cfg_path))
            assert s.context.compact_trigger_tokens == 128000

    def test_yaml_with_shell_command_timeout(self):
        from aacode.config import Settings
        yaml_content = """
timeouts:
  shell_command: 120
  model_summary: 60
"""
        with tempfile.TemporaryDirectory() as td:
            cfg_path = Path(td) / "test_config.yaml"
            cfg_path.write_text(yaml_content, encoding="utf-8")
            s = Settings(config_file=str(cfg_path))
            assert s.timeouts.shell_command == 120
            assert s.timeouts.model_summary == 60

    def test_yaml_old_tool_execution_ignored(self):
        """YAML 中遗留的 tool_execution 被安全忽略"""
        from aacode.config import Settings
        yaml_content = """
timeouts:
  tool_execution: 999
  shell_command: 60
"""
        with tempfile.TemporaryDirectory() as td:
            cfg_path = Path(td) / "test_config.yaml"
            cfg_path.write_text(yaml_content, encoding="utf-8")
            s = Settings(config_file=str(cfg_path))
            assert s.timeouts.shell_command == 60
            assert not hasattr(s.timeouts, "tool_execution")

    def test_multiple_updates_from_yaml(self):
        from aacode.config import Settings
        yaml_content = """
model:
  max_tokens: 48000
  temperature: 0.3
context:
  compact_trigger_tokens: 192000
timeouts:
  shell_command: 300
"""
        with tempfile.TemporaryDirectory() as td:
            cfg_path = Path(td) / "test_config.yaml"
            cfg_path.write_text(yaml_content, encoding="utf-8")
            s = Settings(config_file=str(cfg_path))
            assert s.model.max_tokens == 48000
            assert s.model.temperature == 0.3
            assert s.context.compact_trigger_tokens == 192000
            assert s.timeouts.shell_command == 300


class TestConfigEnvOverride:
    """环境变量覆盖"""

    def test_env_max_tokens(self):
        from aacode.config import Settings
        with tempfile.TemporaryDirectory() as td:
            cfg_path = Path(td) / "test_env.yaml"
            cfg_path.write_text("model:\n  max_tokens: 16000\n", encoding="utf-8")
            os.environ["LLM_MODEL_NAME"] = "gpt-4o-mini"
            try:
                s = Settings(config_file=str(cfg_path))
                assert s.model.name == "gpt-4o-mini"
            finally:
                del os.environ["LLM_MODEL_NAME"]

    def test_env_overrides_yaml(self):
        from aacode.config import Settings
        with tempfile.TemporaryDirectory() as td:
            cfg_path = Path(td) / "test_override.yaml"
            cfg_path.write_text(
                "model:\n  name: deepseek-chat\n  temperature: 0.7\n",
                encoding="utf-8",
            )
            os.environ["LLM_MODEL_NAME"] = "gpt-4o"
            try:
                s = Settings(config_file=str(cfg_path))
                assert s.model.name == "gpt-4o"
                assert s.model.temperature == 0.7
            finally:
                del os.environ["LLM_MODEL_NAME"]

    def test_config_not_found_uses_defaults(self):
        from aacode.config import Settings
        s = Settings(config_file="/nonexistent/path/config.yaml")
        assert s.model.max_tokens == 96000
        assert s.context.compact_trigger_tokens == 256000
        assert not hasattr(s.timeouts, "tool_execution")

    def test_config_source_tracking(self):
        from aacode.config import Settings
        s = Settings(config_file="/nonexistent/config.yaml")
        assert s.config_source == "none"
