"""Tests for launcher.cli module."""

from __future__ import annotations

from unittest.mock import patch


class TestBuildParser:
    """Test the argparse configuration."""

    def test_has_launch_subcommand(self):
        """Should register the 'launch' subcommand."""
        from launcher.cli import _build_parser

        parser = _build_parser()
        args, _ = parser.parse_known_args(["launch"])
        assert args.command == "launch"

    def test_has_version_subcommand(self):
        """Should register the 'version' subcommand."""
        from launcher.cli import _build_parser

        parser = _build_parser()
        args, _ = parser.parse_known_args(["version"])
        assert args.command == "version"

    def test_has_update_subcommand(self):
        """Should register the 'update' subcommand."""
        from launcher.cli import _build_parser

        parser = _build_parser()
        args, _ = parser.parse_known_args(["update"])
        assert args.command == "update"

    def test_has_statusline_subcommand(self):
        """Should register the 'statusline' subcommand."""
        from launcher.cli import _build_parser

        parser = _build_parser()
        args, _ = parser.parse_known_args(["statusline"])
        assert args.command == "statusline"

    def test_no_banner_flag(self):
        """Should accept --no-banner flag."""
        from launcher.cli import _build_parser

        parser = _build_parser()
        args, _ = parser.parse_known_args(["--no-banner"])
        assert args.no_banner is True

    def test_default_no_subcommand(self):
        """Should default to None when no subcommand given."""
        from launcher.cli import _build_parser

        parser = _build_parser()
        args, _ = parser.parse_known_args([])
        assert args.command is None

    def test_launch_accepts_model_flag(self):
        """Should parse --model flag on launch subparser."""
        from launcher.cli import _build_parser

        parser = _build_parser()
        args, _ = parser.parse_known_args(["launch", "--model", "opus"])

        assert hasattr(args, "model")
        assert args.model == "opus"

    def test_run_accepts_model_flag(self):
        """Should parse --model flag on run subparser."""
        from launcher.cli import _build_parser

        parser = _build_parser()
        args, _ = parser.parse_known_args(["run", "--model", "haiku"])

        assert hasattr(args, "model")
        assert args.model == "haiku"

    def test_model_flag_separates_from_remaining(self):
        """Should parse --model separately from unknown remaining args."""
        from launcher.cli import _build_parser

        parser = _build_parser()
        args, remaining = parser.parse_known_args(["run", "--model", "sonnet", "--verbose"])

        assert args.model == "sonnet"
        assert remaining == ["--verbose"]


class TestMain:
    """Test the main() entry point dispatch."""

    def test_default_calls_launch(self):
        """Should call launch_claude when no subcommand given."""
        with patch("launcher.cli.launch_claude") as mock_launch:
            with patch("launcher.cli.print_banner"):
                from launcher.cli import main

                main([])

        mock_launch.assert_called_once()

    def test_run_with_model_passes_to_launch(self):
        """Should pass --model value through to launch_claude."""
        with patch("launcher.cli.launch_claude") as mock_launch:
            with patch("launcher.cli.print_banner"):
                from launcher.cli import main

                main(["--no-banner", "run", "--model", "opus"])

        mock_launch.assert_called_once()
        _, kwargs = mock_launch.call_args
        assert kwargs.get("model") == "opus"

    def test_no_banner_suppresses_banner(self):
        """Should not call print_banner when --no-banner is passed."""
        with patch("launcher.cli.launch_claude"):
            with patch("launcher.cli.print_banner") as mock_banner:
                from launcher.cli import main

                main(["--no-banner"])

        mock_banner.assert_not_called()

    def test_version_prints_version(self, capsys):
        """Should print version string for 'version' subcommand."""
        from launcher.cli import main

        main(["version"])

        captured = capsys.readouterr()
        assert "Tribunal v" in captured.out

    def test_update_calls_check_for_updates(self):
        """Should call check_for_updates for 'update' subcommand."""
        with patch("launcher.cli.check_for_updates") as mock_update:
            from launcher.cli import main

            main(["update"])

        mock_update.assert_called_once()

    def test_statusline_renders_output(self):
        """Should call render_statusline for 'statusline' subcommand."""
        with patch("launcher.cli.sys.stdout"):
            with patch("launcher.statusline.render_statusline", return_value="test-output") as mock_render:
                from launcher.cli import main

                main(["statusline"])

        mock_render.assert_called_once()


class TestGetRuntimeStatus:
    """Test the _get_runtime_status() helper."""

    def test_returns_configured_model(self):
        with patch("launcher.config.get_config", return_value={"model": "claude-opus-4-6", "mode": "quick"}):
            with patch("launcher.worktree._load_worktree_state", return_value=None):
                from launcher.cli import _get_runtime_status

                result = _get_runtime_status()
        assert result["model"] == "claude-opus-4-6"

    def test_returns_none_when_no_model(self):
        with patch("launcher.config.get_config", return_value={"model": None, "mode": "quick"}):
            with patch("launcher.worktree._load_worktree_state", return_value=None):
                from launcher.cli import _get_runtime_status

                result = _get_runtime_status()
        assert result["model"] is None

    def test_returns_mode_from_config(self):
        with patch("launcher.config.get_config", return_value={"model": None, "mode": "spec"}):
            with patch("launcher.worktree._load_worktree_state", return_value=None):
                from launcher.cli import _get_runtime_status

                result = _get_runtime_status()
        assert result["mode"] == "spec"

    def test_returns_worktree_state_when_active(self):
        state = {"slug": "my-feature", "branch": "spec/my-feature", "path": "/tmp/wt", "base_branch": "main"}
        with patch("launcher.config.get_config", return_value={"model": None, "mode": "quick"}):
            with patch("launcher.worktree._load_worktree_state", return_value=state):
                from launcher.cli import _get_runtime_status

                result = _get_runtime_status()
        assert result["worktree"] == state

    def test_returns_none_worktree_when_inactive(self):
        with patch("launcher.config.get_config", return_value={"model": None, "mode": "quick"}):
            with patch("launcher.worktree._load_worktree_state", return_value=None):
                from launcher.cli import _get_runtime_status

                result = _get_runtime_status()
        assert result["worktree"] is None


class TestPrintRuntimeStatus:
    """Test the _print_runtime_status() helper."""

    def test_prints_configured_model(self, capsys):
        from launcher.cli import _print_runtime_status

        _print_runtime_status({"model": "claude-opus-4-6", "mode": "quick", "worktree": None})
        assert "claude-opus-4-6" in capsys.readouterr().out

    def test_prints_default_when_no_model(self, capsys):
        from launcher.cli import _print_runtime_status

        _print_runtime_status({"model": None, "mode": "quick", "worktree": None})
        assert "default" in capsys.readouterr().out.lower()

    def test_prints_mode(self, capsys):
        from launcher.cli import _print_runtime_status

        _print_runtime_status({"model": None, "mode": "quick", "worktree": None})
        assert "quick" in capsys.readouterr().out

    def test_prints_worktree_slug_when_active(self, capsys):
        from launcher.cli import _print_runtime_status

        state = {"slug": "my-feature", "branch": "spec/my-feature", "path": "/tmp/wt", "base_branch": "main"}
        _print_runtime_status({"model": None, "mode": "quick", "worktree": state})
        assert "my-feature" in capsys.readouterr().out

    def test_prints_none_when_no_worktree(self, capsys):
        from launcher.cli import _print_runtime_status

        _print_runtime_status({"model": None, "mode": "quick", "worktree": None})
        assert "none" in capsys.readouterr().out.lower()


class TestStatusCommandRuntime:
    """Test that 'tribunal status' includes runtime info."""

    def test_status_json_includes_model(self, capsys):
        import json

        details = {"authorized": True, "method": "anthropic", "cache": {}, "sources": {}}
        with patch("launcher.access.get_access_details", return_value=details):
            with patch("launcher.config.get_config", return_value={"model": "claude-opus", "mode": "quick"}):
                with patch("launcher.worktree._load_worktree_state", return_value=None):
                    from launcher.cli import main

                    main(["status", "--json"])
        output = json.loads(capsys.readouterr().out)
        assert output["model"] == "claude-opus"

    def test_status_json_includes_mode(self, capsys):
        import json

        details = {"authorized": True, "method": "anthropic", "cache": {}, "sources": {}}
        with patch("launcher.access.get_access_details", return_value=details):
            with patch("launcher.config.get_config", return_value={"model": None, "mode": "spec"}):
                with patch("launcher.worktree._load_worktree_state", return_value=None):
                    from launcher.cli import main

                    main(["status", "--json"])
        output = json.loads(capsys.readouterr().out)
        assert output["mode"] == "spec"

    def test_status_text_shows_model(self, capsys):
        details = {"authorized": True, "method": None, "cache": {}, "sources": {}}
        with patch("launcher.access.get_access_details", return_value=details):
            with patch("launcher.config.get_config", return_value={"model": "claude-haiku", "mode": "quick"}):
                with patch("launcher.worktree._load_worktree_state", return_value=None):
                    from launcher.cli import main

                    main(["status"])
        assert "claude-haiku" in capsys.readouterr().out

    def test_status_text_shows_mode(self, capsys):
        details = {"authorized": True, "method": None, "cache": {}, "sources": {}}
        with patch("launcher.access.get_access_details", return_value=details):
            with patch("launcher.config.get_config", return_value={"model": None, "mode": "quick"}):
                with patch("launcher.worktree._load_worktree_state", return_value=None):
                    from launcher.cli import main

                    main(["status"])
        assert "quick" in capsys.readouterr().out


class TestActivateCommand:
    """UX-1: activate should guide users to the web portal, not dead-end."""

    def test_activate_shows_url(self, capsys):
        """activate should print the tribunal.thebotclub.ai URL."""
        import pytest

        from launcher.cli import main

        with pytest.raises(SystemExit):
            main(["activate"])
        out = capsys.readouterr().out
        assert "tribunal.thebotclub.ai" in out

    def test_activate_json_includes_url(self, capsys):
        """activate --json should return URL in structured output."""
        import json

        import pytest

        from launcher.cli import main

        with pytest.raises(SystemExit):
            main(["activate", "--json"])
        data = json.loads(capsys.readouterr().out)
        assert "tribunal.thebotclub.ai" in data.get("url", "")


class TestCostStatus:
    """UX-2: _print_cost_status should show session count and last date."""

    def test_cost_status_no_sessions_returns_empty(self, tmp_path):
        """No sessions dir → empty dict, no crash."""
        from launcher.cli import _get_cost_status

        result = _get_cost_status(sessions_dir=tmp_path / "nonexistent")
        assert result == {}

    def test_cost_status_counts_sessions(self, tmp_path):
        """Sessions dir with 3 subdirs → sessions count is 3."""
        sessions_dir = tmp_path / "sessions"
        sessions_dir.mkdir()
        for name in ("abc123", "def456", "ghi789"):
            (sessions_dir / name).mkdir()

        from launcher.cli import _get_cost_status

        result = _get_cost_status(sessions_dir=sessions_dir)
        assert result.get("sessions") == 3

    def test_print_cost_status_silent_on_empty(self, capsys):
        """_print_cost_status with empty dict should print nothing."""
        from launcher.cli import _print_cost_status

        _print_cost_status({})
        assert capsys.readouterr().out == ""

    def test_print_cost_status_shows_count(self, capsys):
        """_print_cost_status with data should show session count."""
        from launcher.cli import _print_cost_status

        _print_cost_status({"sessions": 5, "last_session_date": "2026-03-01"})
        out = capsys.readouterr().out
        assert "5" in out


class TestVaultCommand:
    """UX-5: vault subcommand should list/show/search installed assets."""

    def test_vault_parser_registered(self):
        """vault subcommand should be parseable."""
        from launcher.cli import _build_parser

        parser = _build_parser()
        args, _ = parser.parse_known_args(["vault", "list"])
        assert args.command == "vault"

    def test_vault_list_runs_without_error(self, capsys, tmp_path):
        """vault list should run without error even if no assets dir."""
        from unittest.mock import patch

        from launcher.cli import main

        with patch("launcher.cli._PLUGIN_DIR", tmp_path):
            main(["vault", "list"])

    def test_vault_search_filters_by_name(self, capsys, tmp_path):
        """vault search <query> should show only assets matching query."""
        (tmp_path / "commands").mkdir()
        (tmp_path / "commands" / "spec-plan.md").write_text("# spec-plan")
        (tmp_path / "commands" / "learn.md").write_text("# learn")

        from unittest.mock import patch

        from launcher.cli import main

        with patch("launcher.cli._PLUGIN_DIR", tmp_path):
            main(["vault", "search", "spec"])
        out = capsys.readouterr().out
        assert "spec" in out.lower()
