"""Tests for CLI commands.

Uses Typer's CliRunner for isolated command testing.
Tests error handling and validation — commands are placeholders.
"""

from __future__ import annotations

from typing import TYPE_CHECKING
from unittest.mock import patch

from typer.testing import CliRunner

from unfamiliar import __version__
from unfamiliar.cli import app

if TYPE_CHECKING:
    from pathlib import Path

runner = CliRunner()


class TestVersionFlag:
    """Tests for --version flag."""

    def test_version_flag_prints_version(self):
        """--version prints version string and exits cleanly."""
        result = runner.invoke(app, ["--version"])

        assert result.exit_code == 0
        assert f"unfamiliar {__version__}" in result.stdout


class TestValidateGitRepo:
    """Tests for _validate_git_repo via CLI commands."""

    def test_investigate_rejects_non_git_directory(self, tmp_path: Path):
        """investigate exits with error for non-git directory."""
        non_git_dir = tmp_path / "not_a_repo"
        non_git_dir.mkdir()

        result = runner.invoke(app, ["investigate", str(non_git_dir)])

        assert result.exit_code == 1
        assert "not a git repository" in result.stderr

    def test_investigate_accepts_git_directory(self, tmp_path: Path):
        """investigate proceeds for valid git directory."""
        from unfamiliar.models.campaign import Campaign

        git_dir = tmp_path / "repo"
        git_dir.mkdir()
        (git_dir / ".git").mkdir()  # Fake git dir

        # Mock both config and create_campaign
        from unfamiliar.constants import CampaignStatus

        mock_campaign = Campaign(
            id=1,
            repo_path=str(git_dir.resolve()),
            status=CampaignStatus.ACTIVE,
        )
        # Create a mock config with theme attribute
        mock_config = type("MockConfig", (), {"theme": "film_noir"})()
        with (
            patch("unfamiliar.cli.load_config", return_value=mock_config),
            patch(
                "unfamiliar.cli.create_campaign",
                return_value=mock_campaign,
            ),
            patch(
                "unfamiliar.cli.get_campaign_progress",
            ) as mock_progress,
            patch("unfamiliar.cli._launch_tui"),
        ):
            # Mock progress to return something sensible
            from unfamiliar.campaign.types import CampaignProgress
            mock_progress.return_value = CampaignProgress(
                category_progress=[],
                total_missions=10,
                completed_missions=3,
                available_missions=7,
                locked_missions=0,
                in_progress_missions=0,
                overall_percent=30,
                security_total=0,
                security_completed=0,
            )
            result = runner.invoke(app, ["investigate", str(git_dir)])

        assert result.exit_code == 0


class TestConfigErrorHandling:
    """Tests for ConfigError handling in commands."""

    def test_campaigns_exits_cleanly_on_config_error(self):
        """campaigns command exits with clean error on ConfigError."""
        from unfamiliar.config import ConfigError

        with patch(
            "unfamiliar.cli.load_config",
            side_effect=ConfigError("No config found"),
        ):
            result = runner.invoke(app, ["campaigns"])

        assert result.exit_code == 1
        assert "Configuration error" in result.stderr
        assert "No config found" in result.stderr
        # No traceback should appear
        assert "Traceback" not in result.stderr

    def test_investigate_exits_cleanly_on_config_error(self, tmp_path: Path):
        """investigate exits with clean error on ConfigError."""
        from unfamiliar.config import ConfigError

        git_dir = tmp_path / "repo"
        git_dir.mkdir()
        (git_dir / ".git").mkdir()

        with patch(
            "unfamiliar.cli.load_config",
            side_effect=ConfigError("API key not found"),
        ):
            result = runner.invoke(app, ["investigate", str(git_dir)])

        assert result.exit_code == 1
        assert "Configuration error" in result.stderr
        assert "API key not found" in result.stderr


class TestCommandRouting:
    """Tests for command existence and basic routing."""

    def test_campaigns_command_exists(self):
        """campaigns command is registered."""
        with patch("unfamiliar.cli.load_config"):
            result = runner.invoke(app, ["campaigns"])

        assert result.exit_code == 0

    def test_resume_command_exists(self):
        """resume command is registered."""
        with (
            patch("unfamiliar.cli.load_config"),
            patch("unfamiliar.cli.resume_campaign", return_value=None),
        ):
            result = runner.invoke(app, ["resume"])

        assert result.exit_code == 0

    def test_upgrade_command_exists(self):
        """upgrade command is registered."""
        with patch("unfamiliar.cli.load_config"):
            result = runner.invoke(app, ["upgrade"])

        assert result.exit_code == 0
