"""
测试 aacode init (pip 模式) 配置持久化：
- API key / model 写入 com.aacode/aacode_config.yaml (models[default_model].api_key)
- 同时写入 com.aacode/.env（去重）
- 启动时 CWD .env 缺失可 fallback 到 com.aacode/.env
"""
import os
import sys
import tempfile
from pathlib import Path

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

import yaml
import platformdirs as pd

from aacode import cli


class TestInitPipPersistence:
    def test_update_yaml_preset(self):
        with tempfile.TemporaryDirectory() as td:
            cfg = Path(td) / "aacode_config.yaml"
            model = dict(cli.PRESET_MODELS["1"])
            cli._update_yaml_model(cfg, model, "sk-abc123")
            data = yaml.safe_load(cfg.read_text(encoding="utf-8"))
            assert data["model"]["default_model"] == "deepseek"
            entry = data["model"]["models"]["deepseek"]
            assert entry["api_key"] == "sk-abc123"
            assert entry["name"] == "deepseek-chat"
            assert entry["gateway"] == "openai"
            assert entry["base_url"] == "https://api.deepseek.com/v1"

    def test_update_yaml_preserves_other_sections(self):
        with tempfile.TemporaryDirectory() as td:
            cfg = Path(td) / "aacode_config.yaml"
            cfg.write_text(
                yaml.dump({"language": "zh", "model": {"temperature": 0.3, "models": {"deepseek": {"api_key": ""}}}}),
                encoding="utf-8",
            )
            cli._update_yaml_model(cfg, dict(cli.PRESET_MODELS["2"]), "sk-kimi")
            data = yaml.safe_load(cfg.read_text(encoding="utf-8"))
            assert data["language"] == "zh"
            assert data["model"]["temperature"] == 0.3
            assert data["model"]["default_model"] == "moonshot_kimi_k2.5"
            assert data["model"]["models"]["moonshot_kimi_k2.5"]["api_key"] == "sk-kimi"
            assert "deepseek" in data["model"]["models"]

    def test_update_yaml_custom_model(self):
        with tempfile.TemporaryDirectory() as td:
            cfg = Path(td) / "aacode_config.yaml"
            model = {"key": "custom", "name": "my-model", "gateway": "anthropic", "base_url": "https://x/v1"}
            cli._update_yaml_model(cfg, model, "sk-custom")
            data = yaml.safe_load(cfg.read_text(encoding="utf-8"))
            assert data["model"]["default_model"] == "custom"
            assert data["model"]["models"]["custom"]["name"] == "my-model"
            assert data["model"]["models"]["custom"]["api_key"] == "sk-custom"

    def test_write_env_dedup(self):
        with tempfile.TemporaryDirectory() as td:
            env = Path(td) / ".env"
            cli._write_env(env, {"LLM_API_KEY": "sk-1", "LLM_MODEL_NAME": "m1"})
            cli._write_env(env, {"LLM_API_KEY": "sk-2", "LLM_API_URL": "https://u/v1"})
            lines = [l for l in env.read_text(encoding="utf-8").splitlines() if l.strip()]
            keys = [l.split("=", 1)[0] for l in lines]
            assert keys.count("LLM_API_KEY") == 1
            kv = dict(l.split("=", 1) for l in lines)
            assert kv["LLM_API_KEY"] == "sk-2"
            assert kv["LLM_MODEL_NAME"] == "m1"
            assert kv["LLM_API_URL"] == "https://u/v1"

    def test_write_env_preserves_unrelated_keys(self):
        with tempfile.TemporaryDirectory() as td:
            env = Path(td) / ".env"
            env.write_text("# comment\nOTHER=keepme\nLLM_API_KEY=old\n", encoding="utf-8")
            cli._write_env(env, {"LLM_API_KEY": "new"})
            kv = dict(
                l.split("=", 1)
                for l in env.read_text(encoding="utf-8").splitlines()
                if l.strip() and not l.startswith("#") and "=" in l
            )
            assert kv["OTHER"] == "keepme"
            assert kv["LLM_API_KEY"] == "new"

    def test_run_init_pip_writes_both(self, monkeypatch):
        with tempfile.TemporaryDirectory() as td:
            monkeypatch.setattr(pd, "user_config_dir", lambda *a, **kw: str(td))
            answers = iter(["1", "sk-init-key"])
            monkeypatch.setattr("builtins.input", lambda *a, **kw: next(answers))
            cli.run_init_pip()
            cfg = Path(td) / "aacode_config.yaml"
            env = Path(td) / ".env"
            assert cfg.exists() and env.exists()
            data = yaml.safe_load(cfg.read_text(encoding="utf-8"))
            assert data["model"]["default_model"] == "deepseek"
            assert data["model"]["models"]["deepseek"]["api_key"] == "sk-init-key"
            kv = dict(
                l.split("=", 1) for l in env.read_text(encoding="utf-8").splitlines() if l.strip()
            )
            assert kv["LLM_API_KEY"] == "sk-init-key"
            assert kv["LLM_MODEL_NAME"] == "deepseek-chat"

    def test_settings_loads_key_from_platformdirs_yaml(self, monkeypatch):
        """init 写入后，无环境变量/CWD .env 时 Settings 能从 com.aacode yaml 读到 key"""
        with tempfile.TemporaryDirectory() as td:
            monkeypatch.setattr(pd, "user_config_dir", lambda *a, **kw: str(td))
            answers = iter(["1", "sk-persist"])
            monkeypatch.setattr("builtins.input", lambda *a, **kw: next(answers))
            cli.run_init_pip()
            for var in ("LLM_API_KEY", "LLM_MODEL_NAME", "LLM_API_URL", "LLM_GATEWAY"):
                monkeypatch.delenv(var, raising=False)
            with tempfile.TemporaryDirectory() as cwd_td:
                orig = os.getcwd()
                try:
                    os.chdir(cwd_td)
                    from aacode.config import Settings
                    s = Settings()
                    assert s.model.api_key == "sk-persist"
                    assert s.model.name == "deepseek-chat"
                finally:
                    os.chdir(orig)

    def test_perms_restricted(self, monkeypatch):
        if os.name == "nt":
            return
        with tempfile.TemporaryDirectory() as td:
            monkeypatch.setattr(pd, "user_config_dir", lambda *a, **kw: str(td))
            answers = iter(["1", "sk-perm"])
            monkeypatch.setattr("builtins.input", lambda *a, **kw: next(answers))
            cli.run_init_pip()
            for name in ("aacode_config.yaml", ".env"):
                mode = (Path(td) / name).stat().st_mode & 0o777
                assert mode == 0o600
