"""Tests for the CLI."""

from unittest.mock import patch

import pytest
from click.testing import CliRunner

from ship_score.cli import cli
from ship_score.models import HealthStatus, ScoreResult, ToolInfo


@pytest.fixture
def runner() -> CliRunner:
    return CliRunner()


class TestScoreCommand:
    def test_score_output(self, runner: CliRunner) -> None:
        mock_result = ScoreResult(
            score=73,
            grade="B",
            confidence=0.82,
            factors={},
            recommendations=["Add tests"],
        )
        with patch("ship_score.cli.ShipClient") as MC:
            MC.return_value.score.return_value = mock_result
            result = runner.invoke(
                cli,
                [
                    "score",
                    "--repo", "owner/repo",
                    "--message", "feat: add auth",
                ],
            )
            assert result.exit_code == 0
            assert "73/100" in result.output
            assert "B" in result.output

    def test_score_json(self, runner: CliRunner) -> None:
        mock_result = ScoreResult(
            score=73,
            grade="B",
            confidence=0.82,
            factors={},
            recommendations=[],
        )
        with patch("ship_score.cli.ShipClient") as MC:
            MC.return_value.score.return_value = mock_result
            result = runner.invoke(
                cli,
                [
                    "score",
                    "--repo", "owner/repo",
                    "--message", "test",
                    "--json",
                ],
            )
            assert result.exit_code == 0
            assert '"score": 73' in result.output

    def test_score_api_error(
        self, runner: CliRunner,
    ) -> None:
        with patch("ship_score.cli.ShipClient") as MC:
            MC.return_value.score.side_effect = Exception(
                "API error",
            )
            result = runner.invoke(
                cli,
                [
                    "score",
                    "--repo", "owner/repo",
                    "--message", "test",
                ],
            )
            assert result.exit_code == 1


class TestHealthCommand:
    def test_health_ok(self, runner: CliRunner) -> None:
        mock_status = HealthStatus(
            api_reachable=True,
            api_url="http://test",
            total_commits=22000,
            total_repos=10000,
        )
        with patch("ship_score.cli.ShipClient") as MC:
            MC.return_value.health.return_value = mock_status
            result = runner.invoke(cli, ["health"])
            assert result.exit_code == 0
            assert "reachable" in result.output

    def test_health_error(self, runner: CliRunner) -> None:
        mock_status = HealthStatus(
            api_reachable=False,
            api_url="http://test",
            error="timeout",
        )
        with patch("ship_score.cli.ShipClient") as MC:
            MC.return_value.health.return_value = mock_status
            result = runner.invoke(cli, ["health"])
            assert result.exit_code == 1


class TestToolsCommand:
    def test_tools_list(self, runner: CliRunner) -> None:
        mock_tools = [
            ToolInfo(
                name="claude",
                display_name="Claude",
                reliability_score=44,
                grade="F",
            ),
        ]
        with patch("ship_score.cli.ShipClient") as MC:
            MC.return_value.tools.return_value = mock_tools
            result = runner.invoke(cli, ["tools"])
            assert result.exit_code == 0
            assert "Claude" in result.output
