"""Tests for configuration management."""

import os
from pathlib import Path
from unittest.mock import patch

import pytest

from scry_run.config import (
    Config,
    load_config,
    get_env_vars,
    DEFAULT_CONFIG,
)


class TestConfig:
    """Tests for Config dataclass."""

    def test_default_values(self):
        """Test Config has sensible defaults."""
        config = Config()
        assert config.backend == "auto"
        assert config.quiet is False
        assert config.full_context is True
        assert config.log_level == "info"

    def test_backend_config(self):
        """Test backend-specific config."""
        config = Config(
            claude_model="opus",
        )
        assert config.claude_model == "opus"


class TestLoadConfig:
    """Tests for load_config()."""

    def test_load_missing_config_returns_defaults(self, tmp_path):
        """Test missing config file returns defaults."""
        with patch.dict(os.environ, {"SCRY_HOME": str(tmp_path)}, clear=True):
            config = load_config()
            assert config.backend == "auto"

    def test_load_existing_config(self, tmp_path):
        """Test loading existing config file."""
        config_path = tmp_path / "config.toml"
        config_path.write_text("""
[defaults]
backend = "claude"
quiet = true

[backend.claude]
model = "opus"
""")
        with patch.dict(os.environ, {"SCRY_HOME": str(tmp_path)}, clear=True):
            config = load_config()
            assert config.backend == "claude"
            assert config.quiet is True
            assert config.claude_model == "opus"

    def test_env_vars_override_config(self, tmp_path):
        """Test environment variables override config file."""
        config_path = tmp_path / "config.toml"
        config_path.write_text("""
[defaults]
backend = "frozen"
""")
        with patch.dict(os.environ, {
            "SCRY_HOME": str(tmp_path),
            "SCRY_BACKEND": "claude",
        }):
            config = load_config()
            assert config.backend == "claude"


class TestGetEnvVars:
    """Tests for get_env_vars()."""

    def test_converts_config_to_env_vars(self):
        """Test config is converted to env vars dict."""
        config = Config(
            backend="claude",
            quiet=True,
            claude_model="opus",
        )
        with patch.dict(os.environ, {}, clear=True):
            env_vars = get_env_vars(config)

            assert env_vars["SCRY_BACKEND"] == "claude"
            assert env_vars["SCRY_QUIET"] == "true"
            assert env_vars["SCRY_MODEL"] == "opus"

    def test_existing_env_vars_preserved(self):
        """Test existing env vars are not overwritten."""
        config = Config(claude_model="sonnet")

        with patch.dict(os.environ, {"SCRY_MODEL": "opus"}):
            env_vars = get_env_vars(config)
            # Existing env var takes precedence
            assert env_vars["SCRY_MODEL"] == "opus"


class TestDefaultConfig:
    """Tests for DEFAULT_CONFIG constant."""

    def test_default_config_is_valid_toml(self):
        """Test DEFAULT_CONFIG is valid TOML."""
        import tomllib
        parsed = tomllib.loads(DEFAULT_CONFIG)
        assert "defaults" in parsed
        assert "backend" in parsed["defaults"]


class TestLoadConfigAllBackends:
    """Test load_config with all backend configurations."""

    def test_load_claude_model(self, tmp_path):
        """Test loading claude backend model from config."""
        config_path = tmp_path / "config.toml"
        config_path.write_text("""
[defaults]
backend = "claude"

[backend.claude]
model = "opus"
""")
        with patch.dict(os.environ, {"SCRY_HOME": str(tmp_path)}, clear=True):
            config = load_config()
            assert config.backend == "claude"
            assert config.claude_model == "opus"


class TestLoadConfigEnvOverride:
    """Test that environment variables override config file."""

    def test_env_overrides_backend(self, tmp_path):
        """Env var overrides backend from config."""
        config_path = tmp_path / "config.toml"
        config_path.write_text('[defaults]\nbackend = "frozen"')
        with patch.dict(os.environ, {
            "SCRY_HOME": str(tmp_path),
            "SCRY_BACKEND": "claude"
        }, clear=True):
            config = load_config()
            assert config.backend == "claude"

    def test_env_overrides_quiet(self, tmp_path):
        """Env var overrides quiet from config."""
        config_path = tmp_path / "config.toml"
        config_path.write_text('[defaults]\nquiet = false')
        with patch.dict(os.environ, {
            "SCRY_HOME": str(tmp_path),
            "SCRY_QUIET": "true"
        }, clear=True):
            config = load_config()
            assert config.quiet is True

    def test_boolean_parsing_variants(self, tmp_path):
        """Test various boolean string formats."""
        config_path = tmp_path / "config.toml"
        config_path.write_text('[defaults]\nquiet = false')

        for true_val in ["true", "TRUE", "True", "1", "yes", "YES"]:
            with patch.dict(os.environ, {
                "SCRY_HOME": str(tmp_path),
                "SCRY_QUIET": true_val
            }, clear=True):
                config = load_config()
                assert config.quiet is True, f"Failed for value: {true_val}"

        for false_val in ["false", "FALSE", "0", "no", "NO", "anything"]:
            with patch.dict(os.environ, {
                "SCRY_HOME": str(tmp_path),
                "SCRY_QUIET": false_val
            }, clear=True):
                config = load_config()
                assert config.quiet is False, f"Failed for value: {false_val}"


class TestGetEnvVarsPerBackend:
    """Test get_env_vars exports correct env vars per backend."""

    def test_claude_backend_exports_scry_run_model(self):
        """Claude backend exports SCRY_MODEL."""
        config = Config(backend="claude", claude_model="opus")
        with patch.dict(os.environ, {}, clear=True):
            env_vars = get_env_vars(config)
            assert env_vars.get("SCRY_MODEL") == "opus"

    def test_auto_backend_exports_no_model(self):
        """Auto backend exports no model env var."""
        config = Config(backend="auto", claude_model="opus")
        with patch.dict(os.environ, {}, clear=True):
            env_vars = get_env_vars(config)
            assert "SCRY_MODEL" not in env_vars

    def test_none_model_not_exported(self):
        """None model values are not exported."""
        config = Config(backend="claude", claude_model=None)
        with patch.dict(os.environ, {}, clear=True):
            env_vars = get_env_vars(config)
            assert "SCRY_MODEL" not in env_vars


class TestConfigRoundTrip:
    """Test full round-trip: file -> load_config -> get_env_vars."""

    def test_claude_config_round_trip(self, tmp_path):
        """Claude config round-trips correctly."""
        config_path = tmp_path / "config.toml"
        config_path.write_text("""
[defaults]
backend = "claude"
quiet = true

[backend.claude]
model = "opus"
""")
        with patch.dict(os.environ, {"SCRY_HOME": str(tmp_path)}, clear=True):
            config = load_config()
            env_vars = get_env_vars(config)

            assert env_vars["SCRY_BACKEND"] == "claude"
            assert env_vars["SCRY_QUIET"] == "true"
            assert env_vars["SCRY_MODEL"] == "opus"

    def test_auto_backend_no_model_leak(self, tmp_path):
        """Auto backend doesn't leak model from other backend configs."""
        config_path = tmp_path / "config.toml"
        config_path.write_text("""
[defaults]
backend = "auto"

[backend.claude]
model = "opus"
""")
        with patch.dict(os.environ, {"SCRY_HOME": str(tmp_path)}, clear=True):
            config = load_config()
            env_vars = get_env_vars(config)

            assert env_vars["SCRY_BACKEND"] == "auto"
            # No model should be exported for auto from config
            assert "SCRY_MODEL" not in env_vars


class TestEnvVarPreservation:
    """Test that existing env vars are always preserved."""

    def test_scry_run_model_preserved_with_auto_backend(self):
        """SCRY_MODEL env var preserved even with auto backend."""
        config = Config(backend="auto")
        with patch.dict(os.environ, {"SCRY_MODEL": "opus"}, clear=True):
            env_vars = get_env_vars(config)
            assert env_vars["SCRY_MODEL"] == "opus"

    def test_env_var_overrides_config_model(self):
        """Env var takes precedence over config for same key."""
        config = Config(backend="claude", claude_model="sonnet")
        with patch.dict(os.environ, {"SCRY_MODEL": "opus"}, clear=True):
            env_vars = get_env_vars(config)
            # Env var wins
            assert env_vars["SCRY_MODEL"] == "opus"
