"""Tests for configuration management."""

from __future__ import annotations

import sys
from pathlib import Path

import pytest
from typer.testing import CliRunner

from ilum.cli.main import app
from ilum.config.manager import ConfigManager
from ilum.config.models import IlumConfig, ProfileConfig
from ilum.config.paths import IlumPaths


class TestIlumPaths:
    def test_default_paths(self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
        monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path / "cfg"))
        monkeypatch.setenv("XDG_DATA_HOME", str(tmp_path / "dat"))
        monkeypatch.setenv("XDG_STATE_HOME", str(tmp_path / "st"))
        monkeypatch.setenv("XDG_CACHE_HOME", str(tmp_path / "ch"))
        if sys.platform == "win32":
            monkeypatch.setenv("APPDATA", str(tmp_path / "cfg"))
            monkeypatch.setenv("LOCALAPPDATA", str(tmp_path / "local"))
        paths = IlumPaths.default()
        if sys.platform == "win32":
            assert paths.config_dir == tmp_path / "cfg" / "ilum"
        else:
            assert paths.config_dir == tmp_path / "cfg" / "ilum"
            assert paths.data_dir == tmp_path / "dat" / "ilum"
            assert paths.state_dir == tmp_path / "st" / "ilum"
            assert paths.cache_dir == tmp_path / "ch" / "ilum"

    def test_ensure_dirs_creates_directories(self, tmp_config_dir: IlumPaths) -> None:
        assert tmp_config_dir.config_dir.is_dir()
        assert tmp_config_dir.data_dir.is_dir()
        assert tmp_config_dir.state_dir.is_dir()
        assert tmp_config_dir.cache_dir.is_dir()

    def test_xdg_env_vars_respected(self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
        if sys.platform == "win32":
            pytest.skip("XDG variables not used on Windows")
        custom = tmp_path / "custom"
        monkeypatch.setenv("XDG_CONFIG_HOME", str(custom))
        # Clear others to use defaults
        monkeypatch.delenv("XDG_DATA_HOME", raising=False)
        monkeypatch.delenv("XDG_STATE_HOME", raising=False)
        monkeypatch.delenv("XDG_CACHE_HOME", raising=False)
        paths = IlumPaths.default()
        assert paths.config_dir == custom / "ilum"

    def test_windows_paths_use_appdata(
        self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
    ) -> None:
        """On Windows, paths use APPDATA and LOCALAPPDATA."""
        monkeypatch.setattr("ilum.config.paths.sys.platform", "win32")
        appdata = tmp_path / "AppData" / "Roaming"
        localappdata = tmp_path / "AppData" / "Local"
        monkeypatch.setenv("APPDATA", str(appdata))
        monkeypatch.setenv("LOCALAPPDATA", str(localappdata))
        paths = IlumPaths.default()
        assert paths.config_dir == appdata / "ilum"
        assert paths.data_dir == appdata / "ilum" / "data"
        assert paths.state_dir == localappdata / "ilum" / "state"
        assert paths.cache_dir == localappdata / "ilum" / "cache"

    def test_unix_paths_use_xdg(self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
        """On non-Windows, paths use XDG directories."""
        monkeypatch.setattr("ilum.config.paths.sys.platform", "linux")
        monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path / "cfg"))
        monkeypatch.setenv("XDG_DATA_HOME", str(tmp_path / "dat"))
        monkeypatch.setenv("XDG_STATE_HOME", str(tmp_path / "st"))
        monkeypatch.setenv("XDG_CACHE_HOME", str(tmp_path / "ch"))
        paths = IlumPaths.default()
        assert paths.config_dir == tmp_path / "cfg" / "ilum"
        assert paths.data_dir == tmp_path / "dat" / "ilum"
        assert paths.state_dir == tmp_path / "st" / "ilum"
        assert paths.cache_dir == tmp_path / "ch" / "ilum"


class TestConfigManager:
    def test_default_created(self, tmp_config_dir: IlumPaths) -> None:
        mgr = ConfigManager(tmp_config_dir)
        config = mgr.ensure_config()
        assert config.active_profile == "default"
        assert "default" in config.profiles
        assert mgr.config_file.exists()

    def test_load_save_roundtrip(self, tmp_config_dir: IlumPaths) -> None:
        mgr = ConfigManager(tmp_config_dir)
        config = IlumConfig(
            active_profile="dev",
            profiles={"dev": ProfileConfig(name="dev")},
        )
        mgr.save(config)
        loaded = mgr.load()
        assert loaded.active_profile == "dev"
        assert "dev" in loaded.profiles

    def test_get_simple_key(self, tmp_config_dir: IlumPaths) -> None:
        mgr = ConfigManager(tmp_config_dir)
        mgr.ensure_config()
        assert mgr.get("active_profile") == "default"

    def test_get_nested_key(self, tmp_config_dir: IlumPaths) -> None:
        mgr = ConfigManager(tmp_config_dir)
        mgr.ensure_config()
        ns = mgr.get("profiles.default.cluster.namespace")
        assert ns == "default"

    def test_set_key(self, tmp_config_dir: IlumPaths) -> None:
        mgr = ConfigManager(tmp_config_dir)
        mgr.ensure_config()
        mgr.set("active_profile", "staging")
        assert mgr.get("active_profile") == "staging"
        # Verify persistence
        loaded = mgr.load()
        assert loaded.active_profile == "staging"


class TestProfileReleaseName:
    def test_profile_release_name_roundtrip(self, tmp_config_dir: IlumPaths) -> None:
        mgr = ConfigManager(tmp_config_dir)
        config = IlumConfig(
            active_profile="prod",
            profiles={
                "prod": ProfileConfig(name="prod", release_name="ilum-prod"),
            },
        )
        mgr.save(config)
        loaded = mgr.load()
        assert loaded.profiles["prod"].release_name == "ilum-prod"

    def test_release_name_backward_compat(self, tmp_config_dir: IlumPaths) -> None:
        """ProfileConfig without release_name should default to empty string."""
        profile = ProfileConfig(name="test")
        assert profile.release_name == ""


class TestConfigCLI:
    def test_config_path(self, tmp_config_dir: IlumPaths, monkeypatch: pytest.MonkeyPatch) -> None:
        runner = CliRunner()
        result = runner.invoke(app, ["config", "path"])
        assert result.exit_code == 0
        assert "config.yaml" in result.stdout

    def test_config_init(self, tmp_config_dir: IlumPaths) -> None:
        runner = CliRunner()
        result = runner.invoke(app, ["config", "init"])
        assert result.exit_code == 0

    def test_config_show(self, tmp_config_dir: IlumPaths) -> None:
        runner = CliRunner()
        runner.invoke(app, ["config", "init"])
        result = runner.invoke(app, ["config", "show"])
        assert result.exit_code == 0

    def test_config_set(self, tmp_config_dir: IlumPaths) -> None:
        runner = CliRunner()
        runner.invoke(app, ["config", "init"])
        result = runner.invoke(app, ["config", "set", "active_profile", "dev"])
        assert result.exit_code == 0
