#!/usr/bin/env python3
"""utils/config_loader.py 테스트 스위트"""

import os
import sys
import tempfile
from pathlib import Path

import pytest

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

from utils.config_loader import Config, load_config


class TestConfig:
    """Config 클래스 테스트"""

    def test_get_simple_key(self) -> None:
        """단순 키 접근"""
        cfg = Config({"model": "claude-sonnet-4-6"})
        assert cfg.get("model") == "claude-sonnet-4-6"

    def test_get_nested_dot_notation(self) -> None:
        """점 표기법으로 중첩 키 접근"""
        cfg = Config({"models": {"default": "claude-sonnet-4-6", "fallback": "gpt-4o"}})
        assert cfg.get("models.default") == "claude-sonnet-4-6"
        assert cfg.get("models.fallback") == "gpt-4o"

    def test_get_missing_key_returns_default(self) -> None:
        """없는 키는 default 반환"""
        cfg = Config({})
        assert cfg.get("missing.key") is None
        assert cfg.get("missing.key", "fallback") == "fallback"

    def test_get_deeply_nested(self) -> None:
        """3단계 중첩 키"""
        cfg = Config({"a": {"b": {"c": "deep"}}})
        assert cfg.get("a.b.c") == "deep"

    def test_get_returns_none_for_nonexistent(self) -> None:
        """존재하지 않는 키 default None"""
        cfg = Config({"x": 1})
        assert cfg.get("y") is None

    def test_get_partial_path_missing(self) -> None:
        """중간 경로가 없으면 default 반환"""
        cfg = Config({"models": {"default": "sonnet"}})
        assert cfg.get("models.unknown.deep") is None

    def test_config_empty(self) -> None:
        """빈 Config"""
        cfg = Config({})
        assert cfg.get("anything", "x") == "x"

    def test_config_data_property(self) -> None:
        """data 딕셔너리 접근 가능"""
        data = {"key": "value"}
        cfg = Config(data)
        assert cfg.data == data


class TestLoadConfig:
    """load_config() 함수 테스트"""

    def test_load_valid_yaml(self) -> None:
        """유효한 YAML 파일 로드"""
        yaml_content = "models:\n  default: claude-sonnet-4-6\nagent:\n  max_turns: 60\n"
        with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
            f.write(yaml_content)
            tmp_path = f.name
        try:
            cfg = load_config(tmp_path)
            assert cfg.get("models.default") == "claude-sonnet-4-6"
            assert cfg.get("agent.max_turns") == 60
        finally:
            os.unlink(tmp_path)

    def test_load_nonexistent_path_returns_empty(self) -> None:
        """존재하지 않는 경로는 빈 Config 반환"""
        cfg = load_config("/nonexistent/path/system.yaml")
        assert isinstance(cfg, Config)
        assert cfg.get("anything") is None

    def test_load_path_as_pathlib(self) -> None:
        """Path 객체로도 로드 가능"""
        yaml_content = "key: value\n"
        with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
            f.write(yaml_content)
            tmp_path = Path(f.name)
        try:
            cfg = load_config(tmp_path)
            assert cfg.get("key") == "value"
        finally:
            tmp_path.unlink()

    def test_env_override_simple(self, monkeypatch: pytest.MonkeyPatch) -> None:
        """SYSTEM_ 환경변수 오버라이드"""
        yaml_content = "models:\n  default: claude-sonnet-4-6\n"
        with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
            f.write(yaml_content)
            tmp_path = f.name
        try:
            monkeypatch.setenv("SYSTEM_MODELS_DEFAULT", "claude-opus-4-6")
            cfg = load_config(tmp_path)
            assert cfg.get("models.default") == "claude-opus-4-6"
        finally:
            os.unlink(tmp_path)

    def test_env_override_without_yaml(self, monkeypatch: pytest.MonkeyPatch) -> None:
        """YAML 없어도 환경변수만으로 값 접근 가능"""
        monkeypatch.setenv("SYSTEM_MODELS_DEFAULT", "gpt-4o")
        cfg = load_config("/nonexistent/path.yaml")
        assert cfg.get("models.default") == "gpt-4o"

    def test_env_override_prefix_only(self, monkeypatch: pytest.MonkeyPatch) -> None:
        """SYSTEM_ 접두사 없는 변수는 오버라이드 안 됨"""
        yaml_content = "key: original\n"
        with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
            f.write(yaml_content)
            tmp_path = f.name
        try:
            monkeypatch.setenv("KEY", "should_not_override")
            cfg = load_config(tmp_path)
            assert cfg.get("key") == "original"
        finally:
            os.unlink(tmp_path)

    def test_load_none_path_uses_default(self) -> None:
        """path=None이면 기본 경로 시도 (존재하지 않아도 에러 없음)"""
        # 기본 경로가 없을 수 있으므로 에러 없이 Config 반환해야 함
        cfg = load_config(None)
        assert isinstance(cfg, Config)

    def test_env_lowercase_key_mapping(self, monkeypatch: pytest.MonkeyPatch) -> None:
        """SYSTEM_AGENT_MAX_TURNS → agent.max_turns"""
        monkeypatch.setenv("SYSTEM_AGENT_MAX_TURNS", "100")
        cfg = load_config("/nonexistent/path.yaml")
        assert cfg.get("agent.max_turns") == "100"

    def test_returns_config_instance(self) -> None:
        """반환 타입이 Config"""
        cfg = load_config("/nonexistent/path.yaml")
        assert isinstance(cfg, Config)
