from __future__ import annotations

import json
import os
import sys
import tempfile
import unittest
from contextlib import redirect_stdout
from io import StringIO
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
SRC = ROOT / "src"
if str(SRC) not in sys.path:
    sys.path.insert(0, str(SRC))

from agentkeyswitch.cli import main


class CliTestCase(unittest.TestCase):
    def setUp(self) -> None:
        self.temp_dir = tempfile.TemporaryDirectory()
        self.home = Path(self.temp_dir.name) / "home"
        self.home.mkdir(parents=True)
        self.config_home = Path(self.temp_dir.name) / "xdg"
        self.original_env = {
            key: os.environ.get(key)
            for key in ("AGSWITCH_HOME", "AGSWITCH_STORE", "XDG_CONFIG_HOME")
        }
        os.environ["AGSWITCH_HOME"] = str(self.home)
        os.environ["XDG_CONFIG_HOME"] = str(self.config_home)
        os.environ.pop("AGSWITCH_STORE", None)

        (self.home / ".claude").mkdir(parents=True)
        (self.home / ".codex").mkdir(parents=True)

        (self.home / ".claude" / "settings.json").write_text(
            json.dumps(
                {
                    "env": {
                        "ANTHROPIC_AUTH_TOKEN": "old-claude-token",
                        "ANTHROPIC_BASE_URL": "https://old.example/api",
                        "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
                    },
                    "model": "opus",
                    "skipDangerousModePermissionPrompt": True,
                },
                indent=2,
            )
            + "\n",
            encoding="utf-8",
        )

        (self.home / ".codex" / "auth.json").write_text(
            json.dumps(
                {
                    "auth_mode": "apikey",
                    "OPENAI_API_KEY": "old-codex-key",
                },
                indent=2,
            )
            + "\n",
            encoding="utf-8",
        )
        (self.home / ".codex" / "config.toml").write_text(
            "\n".join(
                [
                    'model = "gpt-5.4"',
                    'model_provider = "oldprovider"',
                    "",
                    "[model_providers.oldprovider]",
                    'name = "oldprovider"',
                    'base_url = "https://old.example/openai/v1"',
                    'wire_api = "responses"',
                    "requires_openai_auth = true",
                    "",
                ]
            ),
            encoding="utf-8",
        )

    def tearDown(self) -> None:
        for key, value in self.original_env.items():
            if value is None:
                os.environ.pop(key, None)
            else:
                os.environ[key] = value
        self.temp_dir.cleanup()

    def test_add_and_use_all_profile(self) -> None:
        rc = main(
            [
                "add",
                "taiji",
                "--agent",
                "all",
                "--claude-token",
                "claude-taiji-token",
                "--claude-base-url",
                "https://taijiai.online/v1",
                "--claude-model",
                "opus",
                "--codex-key",
                "codex-taiji-key",
                "--codex-base-url",
                "https://taijiai.online/v1",
                "--codex-provider",
                "taiji",
            ]
        )
        self.assertEqual(rc, 0)

        buf = StringIO()
        with redirect_stdout(buf):
            rc = main(["use", "all", "taiji"])
        self.assertEqual(rc, 0)
        output = buf.getvalue()
        self.assertIn("Applied Profile", output)
        self.assertIn("profile      taiji", output)
        self.assertIn("agent        all", output)
        self.assertIn("- claude", output)
        self.assertIn("- codex", output)

        claude_data = json.loads(
            (self.home / ".claude" / "settings.json").read_text(encoding="utf-8")
        )
        self.assertEqual(
            claude_data["env"]["ANTHROPIC_AUTH_TOKEN"], "claude-taiji-token"
        )
        self.assertEqual(
            claude_data["env"]["ANTHROPIC_BASE_URL"], "https://taijiai.online/v1"
        )
        self.assertTrue(claude_data["skipDangerousModePermissionPrompt"])

        codex_auth = json.loads(
            (self.home / ".codex" / "auth.json").read_text(encoding="utf-8")
        )
        self.assertEqual(codex_auth["OPENAI_API_KEY"], "codex-taiji-key")

        codex_config = (self.home / ".codex" / "config.toml").read_text(encoding="utf-8")
        self.assertIn('model_provider = "taiji"', codex_config)
        self.assertIn('[model_providers.taiji]', codex_config)
        self.assertIn('base_url = "https://taijiai.online/v1"', codex_config)

    def test_import_live_profile(self) -> None:
        rc = main(["import", "current", "--agent", "all"])
        self.assertEqual(rc, 0)

        store_path = self.config_home / "agentkeyswitch" / "profiles.json"
        store = json.loads(store_path.read_text(encoding="utf-8"))
        self.assertIn("current", store["profiles"])
        self.assertEqual(
            store["profiles"]["current"]["claude"]["auth_token"], "old-claude-token"
        )
        self.assertEqual(
            store["profiles"]["current"]["codex"]["api_key"], "old-codex-key"
        )

    def test_import_existing_named_profiles(self) -> None:
        (self.home / ".claude" / "settings - max.json").write_text(
            json.dumps(
                {
                    "env": {
                        "ANTHROPIC_AUTH_TOKEN": "max-claude-token",
                        "ANTHROPIC_BASE_URL": "https://www.88code.org/api",
                        "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
                    },
                    "model": "opus",
                },
                indent=2,
            )
            + "\n",
            encoding="utf-8",
        )
        (self.home / ".claude" / "settings - taiji.json").write_text(
            json.dumps(
                {
                    "env": {
                        "ANTHROPIC_AUTH_TOKEN": "taiji-claude-token",
                        "ANTHROPIC_BASE_URL": "https://taijiai.online/v1",
                        "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
                    },
                    "model": "opus",
                },
                indent=2,
            )
            + "\n",
            encoding="utf-8",
        )
        (self.home / ".codex" / "auth - packy.json").write_text(
            json.dumps(
                {
                    "base_url": "https://www.packyapi.com/v1",
                    "OPENAI_API_KEY": "packy-codex-key",
                },
                indent=2,
            )
            + "\n",
            encoding="utf-8",
        )
        (self.home / ".codex" / "auth - taiji.json").write_text(
            json.dumps(
                {
                    "base_url": "https://taijiai.online/v1",
                    "OPENAI_API_KEY": "taiji-codex-key",
                },
                indent=2,
            )
            + "\n",
            encoding="utf-8",
        )
        (self.home / ".codex" / "config.toml").write_text(
            "\n".join(
                [
                    'model = "gpt-5.4"',
                    'model_provider = "oldprovider"',
                    "",
                    "[model_providers.oldprovider]",
                    'name = "oldprovider"',
                    'base_url = "https://old.example/openai/v1"',
                    'wire_api = "responses"',
                    "requires_openai_auth = true",
                    "",
                    "[model_providers.packycode]",
                    'name = "packycode"',
                    'base_url = "https://www.packyapi.com/v1"',
                    'wire_api = "responses"',
                    "requires_openai_auth = true",
                    "",
                ]
            ),
            encoding="utf-8",
        )

        buf = StringIO()
        with redirect_stdout(buf):
            rc = main(["import-existing"])
        self.assertEqual(rc, 0)
        output = buf.getvalue()
        self.assertIn("Imported Profiles (3)", output)
        self.assertIn("- max", output)
        self.assertIn("agents       claude", output)
        self.assertIn("agents       codex", output)
        self.assertIn("agents       claude, codex", output)

        store_path = self.config_home / "agentkeyswitch" / "profiles.json"
        store = json.loads(store_path.read_text(encoding="utf-8"))
        self.assertIn("max", store["profiles"])
        self.assertIn("packy", store["profiles"])
        self.assertIn("taiji", store["profiles"])
        self.assertIn("claude", store["profiles"]["max"])
        self.assertNotIn("codex", store["profiles"]["max"])
        self.assertIn("codex", store["profiles"]["packy"])
        self.assertEqual(
            store["profiles"]["packy"]["codex"]["provider_name"], "packycode"
        )
        self.assertEqual(
            store["profiles"]["taiji"]["codex"]["provider_name"], "taiji"
        )
        self.assertEqual(
            store["profiles"]["taiji"]["claude"]["auth_token"], "taiji-claude-token"
        )

    def test_import_existing_with_custom_separator(self) -> None:
        (self.home / ".claude" / "settings_max.json").write_text(
            json.dumps(
                {
                    "env": {
                        "ANTHROPIC_AUTH_TOKEN": "max-claude-token",
                        "ANTHROPIC_BASE_URL": "https://www.88code.org/api",
                        "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
                    },
                    "model": "opus",
                },
                indent=2,
            )
            + "\n",
            encoding="utf-8",
        )
        (self.home / ".codex" / "auth_max.json").write_text(
            json.dumps(
                {
                    "base_url": "https://www.88code.org/openai/v1",
                    "OPENAI_API_KEY": "max-codex-key",
                },
                indent=2,
            )
            + "\n",
            encoding="utf-8",
        )

        buf = StringIO()
        with redirect_stdout(buf):
            rc = main(["import-existing", "--separator", "_"])
        self.assertEqual(rc, 0)
        output = buf.getvalue()
        self.assertIn("Imported Profiles (1)", output)
        self.assertIn("- max", output)

        store_path = self.config_home / "agentkeyswitch" / "profiles.json"
        store = json.loads(store_path.read_text(encoding="utf-8"))
        self.assertIn("max", store["profiles"])
        self.assertEqual(
            store["profiles"]["max"]["claude"]["auth_token"], "max-claude-token"
        )
        self.assertEqual(
            store["profiles"]["max"]["codex"]["api_key"], "max-codex-key"
        )

    def test_help_outputs_global_details(self) -> None:
        buf = StringIO()
        with redirect_stdout(buf):
            rc = main(["help"])
        self.assertEqual(rc, 0)
        output = buf.getvalue()
        self.assertIn("Switch Claude and Codex API profiles on Linux.", output)
        self.assertIn("Quick start:", output)
        self.assertIn("agswitch import-existing", output)

    def test_help_outputs_use_details(self) -> None:
        buf = StringIO()
        with redirect_stdout(buf):
            rc = main(["help", "use"])
        self.assertEqual(rc, 0)
        output = buf.getvalue()
        self.assertIn("Apply a stored profile to live config files.", output)
        self.assertIn("agswitch use all taiji", output)
        self.assertIn("~/.codex/config.toml", output)

    def test_list_and_status_outputs_are_block_formatted(self) -> None:
        rc = main(
            [
                "add",
                "max",
                "--agent",
                "all",
                "--claude-token",
                "max-claude-token",
                "--claude-base-url",
                "https://www.88code.org/api",
                "--claude-model",
                "opus",
                "--codex-key",
                "max-codex-key",
                "--codex-base-url",
                "https://www.88code.org/openai/v1",
                "--codex-provider",
                "88code",
            ]
        )
        self.assertEqual(rc, 0)

        buf = StringIO()
        with redirect_stdout(buf):
            rc = main(["list"])
        self.assertEqual(rc, 0)
        output = buf.getvalue()
        self.assertIn("Stored Profiles (1)", output)
        self.assertIn("- max", output)
        self.assertIn("claude       yes (token:", output)
        self.assertIn("codex        yes (key:", output)

        rc = main(["use", "all", "max"])
        self.assertEqual(rc, 0)

        buf = StringIO()
        with redirect_stdout(buf):
            rc = main(["status"])
        self.assertEqual(rc, 0)
        output = buf.getvalue()
        self.assertIn("Live Status", output)
        self.assertIn("- claude", output)
        self.assertIn("- codex", output)
        self.assertIn("profile      max", output)
        self.assertIn("paths        1", output)


if __name__ == "__main__":
    unittest.main()
