"""Tests for ShipClient with mocked HTTP."""

from unittest.mock import MagicMock, patch

import httpx
import pytest

from ship_score.client import ShipClient


def _mock_response(
    data: dict,  # type: ignore[type-arg]
    status_code: int = 200,
) -> httpx.Response:
    resp = MagicMock(spec=httpx.Response)
    resp.status_code = status_code
    resp.json.return_value = data
    resp.raise_for_status.return_value = None
    if status_code >= 400:
        resp.raise_for_status.side_effect = (
            httpx.HTTPStatusError(
                "error", request=MagicMock(), response=resp,
            )
        )
    return resp


class TestScore:
    def test_score_success(self) -> None:
        client = ShipClient(base_url="http://test")
        mock_resp = _mock_response({
            "score": 73,
            "grade": "B",
            "confidence": 0.82,
            "factors": {},
            "recommendations": ["Add tests"],
        })
        with patch.object(
            client._client, "post", return_value=mock_resp,
        ) as mock_post:
            result = client.score(
                repo="owner/repo",
                message="feat: add auth",
                language="python",
            )
            assert result.score == 73
            assert result.grade == "B"
            mock_post.assert_called_once()
            call_kwargs = mock_post.call_args
            body = call_kwargs[1]["json"]
            assert body["repo"] == "owner/repo"
            assert body["owner"] == "owner"

    def test_score_http_error(self) -> None:
        client = ShipClient(base_url="http://test")
        mock_resp = _mock_response({}, status_code=500)
        with patch.object(
            client._client, "post", return_value=mock_resp,
        ):
            with pytest.raises(httpx.HTTPStatusError):
                client.score(
                    repo="owner/repo",
                    message="test",
                    language="python",
                )


class TestDetect:
    def test_detect_ai(self) -> None:
        client = ShipClient(base_url="http://test")
        mock_resp = _mock_response({
            "is_ai_generated": True,
            "confidence": 0.89,
            "features_used": 174,
        })
        with patch.object(
            client._client, "post", return_value=mock_resp,
        ):
            result = client.detect(
                code="print('hello')", language="python",
            )
            assert result.is_ai is True
            assert result.confidence == 0.89

    def test_detect_not_ai(self) -> None:
        client = ShipClient(base_url="http://test")
        mock_resp = _mock_response({
            "is_ai_generated": False,
            "confidence": 0.15,
            "features_used": 100,
        })
        with patch.object(
            client._client, "post", return_value=mock_resp,
        ):
            result = client.detect(code="x = 1", language="python")
            assert result.is_ai is False


class TestTools:
    def test_tools_list(self) -> None:
        client = ShipClient(base_url="http://test")
        mock_resp = _mock_response({
            "tools": [
                {
                    "name": "claude",
                    "display_name": "Claude",
                    "reliability_score": 44,
                    "grade": "F",
                },
            ],
        })
        with patch.object(
            client._client, "get", return_value=mock_resp,
        ):
            tools = client.tools()
            assert len(tools) == 1
            assert tools[0].name == "claude"


class TestHealth:
    def test_health_ok(self) -> None:
        client = ShipClient(base_url="http://test")
        mock_resp = _mock_response({
            "total_commits": 22000,
            "total_repos": 10000,
        })
        with patch.object(
            client._client, "get", return_value=mock_resp,
        ):
            h = client.health()
            assert h.api_reachable is True
            assert h.total_commits == 22000

    def test_health_error(self) -> None:
        client = ShipClient(base_url="http://test")
        with patch.object(
            client._client,
            "get",
            side_effect=Exception("connection refused"),
        ):
            h = client.health()
            assert h.api_reachable is False
            assert "connection refused" in (h.error or "")


class TestContextManager:
    def test_context_manager(self) -> None:
        with ShipClient(base_url="http://test") as client:
            assert client is not None
