"""
Module: test_config
Description: Tests for configuration management

Implements:
    - docs/guides/developer-environment.md#configuration
"""

from pathlib import Path

import pytest

from huitzo_cli.config import CLIConfig, ConfigManager, DevConfig


def test_cli_config_defaults() -> None:
    """Test CLIConfig with defaults."""
    config = CLIConfig()
    assert config.api_url == "https://api.huitzo.ai"
    assert config.auth.token_file is None
    assert config.dev.port == 8080
    assert config.dev.verbose is False


def test_dev_config_defaults() -> None:
    """Test DevConfig with defaults."""
    config = DevConfig()
    assert config.port == 8080
    assert config.verbose is False
    assert config.auto_reload is True
    assert config.persist_sandbox is False


def test_config_manager_defaults(temp_dir: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    """Test ConfigManager with no files."""
    # Mock config directory to prevent reading real user config
    config_dir = temp_dir / "config"
    monkeypatch.setattr(ConfigManager, "get_config_dir", staticmethod(lambda: config_dir))

    manager = ConfigManager(project_root=temp_dir)
    assert manager.get("api_url") == "https://api.huitzo.ai"
    assert manager.get("auth.token") is None
    assert manager.get("dev.port") == 8080


def test_config_manager_get_nested(temp_dir: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    """Test getting nested config values."""
    config_dir = temp_dir / "config"
    monkeypatch.setattr(ConfigManager, "get_config_dir", staticmethod(lambda: config_dir))

    manager = ConfigManager(project_root=temp_dir)
    assert manager.get("dev.port") == 8080
    assert manager.get("dev.verbose") is False


def test_config_manager_get_missing(temp_dir: Path) -> None:
    """Test getting missing config values."""
    manager = ConfigManager(project_root=temp_dir)
    assert manager.get("missing.key") is None
    assert manager.get("missing.key", "default") == "default"


def test_config_manager_set_user(temp_dir: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    """Test setting user config (generic ConfigManager.set mechanism)."""
    # Mock config directory to temp dir
    config_dir = temp_dir / "config"
    monkeypatch.setattr(ConfigManager, "get_config_dir", staticmethod(lambda: config_dir))

    manager = ConfigManager(project_root=temp_dir)
    manager.set("dev.verbose", True, scope="user")

    # Verify file was created
    config_file = config_dir / "config.yaml"
    assert config_file.exists()

    # Verify value was set
    assert manager.get("dev.verbose") is True


def test_config_manager_set_project(temp_dir: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    """Test setting project config."""
    config_dir = temp_dir / "config"
    monkeypatch.setattr(ConfigManager, "get_config_dir", staticmethod(lambda: config_dir))

    manager = ConfigManager(project_root=temp_dir)
    manager.set("dev.port", 9000, scope="project")

    # Verify file was created
    config_file = temp_dir / "huitzo.yaml"
    assert config_file.exists()

    # Verify value was set
    assert manager.get("dev.port") == 9000


def test_config_manager_env_override(temp_dir: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    """Test environment variable override.

    Note: Auth tokens use HUITZO_AUTH_TOKEN via AuthClient, not ConfigManager.
    """
    monkeypatch.setenv("HUITZO_API_URL", "https://test.example.com")
    monkeypatch.setenv("HUITZO_DEV_PORT", "3000")

    manager = ConfigManager(project_root=temp_dir)
    assert manager.get("api_url") == "https://test.example.com"
    assert manager.get("dev.port") == 3000


def test_config_manager_to_dict(temp_dir: Path) -> None:
    """Test converting config to dictionary."""
    manager = ConfigManager(project_root=temp_dir)
    config_dict = manager.to_dict()

    assert "api_url" in config_dict
    assert "auth" in config_dict
    assert "dev" in config_dict


def test_config_manager_to_dict_redacts_token_file(
    temp_dir: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    """Test to_dict() redacts auth.token_file."""
    config_dir = temp_dir / "config"
    monkeypatch.setattr(ConfigManager, "get_config_dir", staticmethod(lambda: config_dir))

    manager = ConfigManager(project_root=temp_dir)
    manager.set("auth.token_file", "/secret/path/token", scope="user")

    config_dict = manager.to_dict()
    assert config_dict["auth"]["token_file"] == "***"
    assert "/secret/path/token" not in str(config_dict)


def test_config_manager_get_config_path_user(
    temp_dir: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    """Test getting user config path."""
    config_dir = temp_dir / "config"
    monkeypatch.setattr(ConfigManager, "get_config_dir", staticmethod(lambda: config_dir))

    manager = ConfigManager(project_root=temp_dir)
    path = manager.get_config_path(scope="user")

    assert path == config_dir / "config.yaml"


def test_config_manager_get_config_path_project(temp_dir: Path) -> None:
    """Test getting project config path."""
    manager = ConfigManager(project_root=temp_dir)
    path = manager.get_config_path(scope="project")

    assert path == temp_dir / "huitzo.yaml"


def test_deep_merge_preserves_sibling_keys() -> None:
    """Test that _deep_merge preserves sibling keys in nested dicts."""
    base = {"dev": {"port": 9000, "auto_reload": True}, "api_url": "https://example.com"}
    override = {"dev": {"verbose": True}}

    merged = ConfigManager._deep_merge(base, override)

    assert merged["dev"]["port"] == 9000
    assert merged["dev"]["auto_reload"] is True
    assert merged["dev"]["verbose"] is True
    assert merged["api_url"] == "https://example.com"


def test_deep_merge_override_scalar() -> None:
    """Test that _deep_merge replaces scalars and non-dict values."""
    base = {"dev": {"port": 9000}, "api_url": "https://old.com"}
    override = {"dev": {"port": 3000}, "api_url": "https://new.com"}

    merged = ConfigManager._deep_merge(base, override)

    assert merged["dev"]["port"] == 3000
    assert merged["api_url"] == "https://new.com"


def test_config_manager_nested_merge(temp_dir: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    """Test that user config merges into project config without erasing nested siblings."""
    import yaml

    config_dir = temp_dir / "config"
    monkeypatch.setattr(ConfigManager, "get_config_dir", staticmethod(lambda: config_dir))

    # Project config sets dev.port
    project_yaml = temp_dir / "huitzo.yaml"
    project_yaml.write_text(yaml.dump({"dev": {"port": 9000}}))

    # User config sets dev.verbose — should NOT erase dev.port
    config_dir.mkdir(parents=True, exist_ok=True)
    user_yaml = config_dir / "config.yaml"
    user_yaml.write_text(yaml.dump({"dev": {"verbose": True}}))

    manager = ConfigManager(project_root=temp_dir)
    assert manager.get("dev.port") == 9000
    assert manager.get("dev.verbose") is True


def test_check_namespace_quota_enforced_without_test_mode(
    temp_dir: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    """Test check_namespace_quota enforces limit regardless of env vars (C7)."""
    config_dir = temp_dir / "config"
    monkeypatch.setattr(ConfigManager, "get_config_dir", staticmethod(lambda: config_dir))
    # Ensure HUITZO_TEST_MODE is NOT set
    monkeypatch.delenv("HUITZO_TEST_MODE", raising=False)

    manager = ConfigManager(project_root=temp_dir)

    # Should allow first 5 attempts
    for _ in range(5):
        allowed, error = manager.check_namespace_quota()
        assert allowed is True
        assert error is None

    # 6th attempt should be rate limited
    allowed, error = manager.check_namespace_quota()
    assert allowed is False
    assert "Rate limit exceeded" in (error or "")


def test_check_namespace_quota_ignores_test_mode_env(
    temp_dir: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    """Test HUITZO_TEST_MODE=1 does NOT bypass quota anymore (C7)."""
    config_dir = temp_dir / "config"
    monkeypatch.setattr(ConfigManager, "get_config_dir", staticmethod(lambda: config_dir))
    monkeypatch.setenv("HUITZO_TEST_MODE", "1")

    manager = ConfigManager(project_root=temp_dir)

    # Use up quota
    for _ in range(5):
        manager.check_namespace_quota()

    # Should still be rate limited even with HUITZO_TEST_MODE=1
    allowed, error = manager.check_namespace_quota()
    assert allowed is False
