"""Tests for cli.py Codex agent registration and setup."""
from __future__ import annotations

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

import pytest

from staso.cli import (
    CODEX,
    _build_hooks_config,
    _ensure_codex_hooks_enabled,
    _merge_settings,
    cmd_setup,
    get_agent,
)


class TestCodexAgentRegistry:
    def test_codex_registered(self):
        agent = get_agent("codex")
        assert agent is not None
        assert agent.module == "codex"
        assert agent.display_name == "Codex"

    def test_codex_hook_events(self):
        agent = get_agent("codex")
        assert set(agent.hook_events) == {
            "SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "Stop",
        }

    def test_codex_has_no_session_end(self):
        agent = get_agent("codex")
        assert "SessionEnd" not in agent.hook_events

    def test_codex_embed_env_flag(self):
        agent = get_agent("codex")
        assert agent.embed_env_in_command is True

    def test_claude_code_no_embed_env(self):
        agent = get_agent("claude-code")
        assert agent.embed_env_in_command is False


class TestBuildHooksConfigCodex:
    def test_all_events_present(self):
        hooks = _build_hooks_config("python3 -m staso.codex", agent=CODEX)
        assert set(hooks.keys()) == set(CODEX.hook_events)

    def test_tool_events_have_matcher(self):
        hooks = _build_hooks_config("python3 -m staso.codex", agent=CODEX)
        for event in ("PreToolUse", "PostToolUse"):
            entry = hooks[event][0]
            assert "matcher" in entry

    def test_non_tool_events_no_matcher(self):
        hooks = _build_hooks_config("python3 -m staso.codex", agent=CODEX)
        for event in ("SessionStart", "UserPromptSubmit", "Stop"):
            entry = hooks[event][0]
            assert "matcher" not in entry

    def test_command_embedded(self):
        hooks = _build_hooks_config("STASO_API_KEY=ak_test python3 -m staso.codex", agent=CODEX)
        entry = hooks["Stop"][0]
        cmd = entry["hooks"][0]["command"]
        assert "staso.codex" in cmd
        assert "STASO_API_KEY=ak_test" in cmd


class TestSetupCodex:
    def test_writes_hooks_json_with_env_in_command(self, tmp_path, monkeypatch):
        monkeypatch.setattr("staso.cli.Path.home", lambda: tmp_path)

        import argparse
        args = argparse.Namespace(
            target="codex",
            api_key="ak_testkey123",
            base_url="https://api.staso.dev",
            workspace="my-workspace",
            environment="production",
            agent_id="my-agent",
            scope="global",
        )

        with patch("staso.cli.sys.executable", "/usr/bin/python3"):
            result = cmd_setup(args)

        assert result == 0
        hooks_path = tmp_path / ".codex" / "hooks.json"
        written = json.loads(hooks_path.read_text())
        assert "hooks" in written
        assert "Stop" in written["hooks"]

        # Env vars should be in command, not in env section
        assert "env" not in written or written.get("env", {}) == {}

        # Check env vars are embedded in the command
        stop_entry = written["hooks"]["Stop"][0]
        cmd = stop_entry["hooks"][0]["command"]
        assert "STASO_API_KEY=ak_testkey123" in cmd
        assert "STASO_BASE_URL=https://api.staso.dev" in cmd
        assert "STASO_WORKSPACE_SLUG=my-workspace" in cmd
        assert "staso.codex" in cmd

    def test_enables_feature_flag(self, tmp_path, monkeypatch):
        monkeypatch.setattr("staso.cli.Path.home", lambda: tmp_path)

        import argparse
        args = argparse.Namespace(
            target="codex",
            api_key="ak_testkey123",
            base_url=None,
            workspace=None,
            environment="production",
            agent_id=None,
            scope="global",
        )

        with patch("staso.cli.sys.executable", "/usr/bin/python3"):
            cmd_setup(args)

        config_path = tmp_path / ".codex" / "config.toml"
        assert config_path.exists()
        content = config_path.read_text()
        assert "codex_hooks = true" in content
        assert "[features]" in content

    def test_preserves_existing_config_toml(self, tmp_path, monkeypatch):
        monkeypatch.setattr("staso.cli.Path.home", lambda: tmp_path)

        # Pre-create config.toml with existing settings
        codex_dir = tmp_path / ".codex"
        codex_dir.mkdir(parents=True)
        (codex_dir / "config.toml").write_text('model = "gpt-5.4"\n')

        import argparse
        args = argparse.Namespace(
            target="codex",
            api_key="ak_testkey123",
            base_url=None,
            workspace=None,
            environment="production",
            agent_id=None,
            scope="global",
        )

        with patch("staso.cli.sys.executable", "/usr/bin/python3"):
            cmd_setup(args)

        content = (codex_dir / "config.toml").read_text()
        assert 'model = "gpt-5.4"' in content
        assert "codex_hooks = true" in content

    def test_idempotent_feature_flag(self, tmp_path, monkeypatch):
        monkeypatch.setattr("staso.cli.Path.home", lambda: tmp_path)

        codex_dir = tmp_path / ".codex"
        codex_dir.mkdir(parents=True)
        (codex_dir / "config.toml").write_text("[features]\ncodex_hooks = true\n")

        import argparse
        args = argparse.Namespace(
            target="codex",
            api_key="ak_testkey123",
            base_url=None,
            workspace=None,
            environment="production",
            agent_id=None,
            scope="global",
        )

        with patch("staso.cli.sys.executable", "/usr/bin/python3"):
            cmd_setup(args)

        content = (codex_dir / "config.toml").read_text()
        assert content.count("codex_hooks") == 1


class TestEnsureCodexHooksEnabled:
    def test_creates_config_toml(self, tmp_path, monkeypatch):
        monkeypatch.setattr("staso.cli.Path.home", lambda: tmp_path)
        _ensure_codex_hooks_enabled("global")

        config_path = tmp_path / ".codex" / "config.toml"
        assert config_path.exists()
        content = config_path.read_text()
        assert "[features]" in content
        assert "codex_hooks = true" in content

    def test_appends_to_existing_features_section(self, tmp_path, monkeypatch):
        monkeypatch.setattr("staso.cli.Path.home", lambda: tmp_path)
        codex_dir = tmp_path / ".codex"
        codex_dir.mkdir(parents=True)
        (codex_dir / "config.toml").write_text("[features]\nsome_flag = true\n")

        _ensure_codex_hooks_enabled("global")

        content = (codex_dir / "config.toml").read_text()
        assert "codex_hooks = true" in content
        assert "some_flag = true" in content
        assert content.count("[features]") == 1

    def test_skips_if_already_present(self, tmp_path, monkeypatch):
        monkeypatch.setattr("staso.cli.Path.home", lambda: tmp_path)
        codex_dir = tmp_path / ".codex"
        codex_dir.mkdir(parents=True)
        original = "[features]\ncodex_hooks = true\n"
        (codex_dir / "config.toml").write_text(original)

        _ensure_codex_hooks_enabled("global")

        assert (codex_dir / "config.toml").read_text() == original

    def test_preserves_path_keys_with_quoting(self, tmp_path, monkeypatch):
        """Keys with special characters (like file paths) must be quoted in TOML."""
        monkeypatch.setattr("staso.cli.Path.home", lambda: tmp_path)
        codex_dir = tmp_path / ".codex"
        codex_dir.mkdir(parents=True)
        # Pre-create config with a [projects] section containing a path key
        (codex_dir / "config.toml").write_text(
            '[projects]\n"/home/user/my-project" = { trust_level = "trusted" }\n'
        )

        _ensure_codex_hooks_enabled("global")

        content = (codex_dir / "config.toml").read_text()
        # Path key must remain quoted
        assert '"/home/user/my-project"' in content
        # Value must be an inline table, not a Python repr string
        assert "trust_level" in content
        assert "{'trust_level'" not in content
        # Feature flag must be added
        assert "codex_hooks = true" in content

    def test_dict_values_serialized_as_inline_tables(self, tmp_path, monkeypatch):
        """Dict values in TOML must be inline tables, not Python repr strings."""
        monkeypatch.setattr("staso.cli.Path.home", lambda: tmp_path)
        codex_dir = tmp_path / ".codex"
        codex_dir.mkdir(parents=True)
        (codex_dir / "config.toml").write_text(
            '[projects]\nmy_project = { trust_level = "full", sandbox = true }\n'
        )

        _ensure_codex_hooks_enabled("global")

        content = (codex_dir / "config.toml").read_text()
        assert "trust_level" in content
        assert "sandbox" in content
        # Must not contain Python dict repr
        assert "{'trust_level'" not in content
        assert "codex_hooks = true" in content
