"""Tests for /api/tasks router."""

from unittest.mock import AsyncMock

import pytest
from fastapi.testclient import TestClient

from hangar.dependencies import get_beads_service
from hangar.main import app
from hangar.models.beads import BeadsTask, BeadsTaskList


def _mock_beads_service() -> AsyncMock:
    """Create a mock BeadsService."""
    service = AsyncMock()
    service.list_tasks.return_value = BeadsTaskList(
        tasks=[
            BeadsTask(id="hangar-abc", title="Test task 1", status="open", priority=1),
            BeadsTask(id="hangar-def", title="Test task 2", status="in_progress", priority=2),
        ]
    )
    service.ready_tasks.return_value = BeadsTaskList(
        tasks=[
            BeadsTask(id="hangar-abc", title="Test task 1", status="open", priority=1),
        ]
    )
    service.show_task.return_value = BeadsTask(
        id="hangar-abc", title="Test task 1", status="open", priority=1
    )
    return service


@pytest.fixture(autouse=True)
def _override_deps():
    """Override BeadsService dependency for all tests in this module."""
    mock = _mock_beads_service()
    app.dependency_overrides[get_beads_service] = lambda: mock
    yield mock
    app.dependency_overrides.clear()


def test_list_tasks(client: TestClient, _override_deps: AsyncMock) -> None:
    """GET /api/tasks should return all tasks."""
    response = client.get("/api/tasks")
    assert response.status_code == 200
    data = response.json()
    assert len(data["tasks"]) == 2


def test_ready_tasks(client: TestClient, _override_deps: AsyncMock) -> None:
    """GET /api/tasks/ready should return ready tasks."""
    response = client.get("/api/tasks/ready")
    assert response.status_code == 200
    data = response.json()
    assert len(data["tasks"]) == 1


def test_get_task(client: TestClient, _override_deps: AsyncMock) -> None:
    """GET /api/tasks/{id} should return a single task."""
    response = client.get("/api/tasks/hangar-abc")
    assert response.status_code == 200
    data = response.json()
    assert data["id"] == "hangar-abc"


def test_get_task_not_found(client: TestClient) -> None:
    """GET /api/tasks/{id} should return 502 for CLI failure."""
    mock = AsyncMock()
    mock.show_task.side_effect = RuntimeError("bd show hangar-nope failed: not found")
    app.dependency_overrides[get_beads_service] = lambda: mock
    response = client.get("/api/tasks/hangar-nope")
    assert response.status_code == 502
    app.dependency_overrides.clear()


def test_claim_task(client: TestClient, _override_deps: AsyncMock) -> None:
    """POST /api/tasks/{id}/claim should claim the task."""
    response = client.post("/api/tasks/hangar-abc/claim")
    assert response.status_code == 200
    data = response.json()
    assert data["status"] == "claimed"
    _override_deps.claim_task.assert_called_once_with("hangar-abc")


def test_close_task(client: TestClient, _override_deps: AsyncMock) -> None:
    """POST /api/tasks/{id}/close should close with reason."""
    response = client.post(
        "/api/tasks/hangar-abc/close",
        json={"reason": "Feature complete"},
    )
    assert response.status_code == 200
    data = response.json()
    assert data["status"] == "closed"
    _override_deps.close_task.assert_called_once_with("hangar-abc", "Feature complete")


def test_get_task_includes_close_reason(client: TestClient) -> None:
    """GET /api/tasks/{id} should include close_reason for closed tasks."""
    mock = AsyncMock()
    mock.show_task.return_value = BeadsTask(
        id="hangar-closed",
        title="Closed task",
        status="closed",
        priority=1,
        close_reason="Implemented with full test coverage",
    )
    app.dependency_overrides[get_beads_service] = lambda: mock
    response = client.get("/api/tasks/hangar-closed")
    assert response.status_code == 200
    data = response.json()
    assert data["close_reason"] == "Implemented with full test coverage"
    app.dependency_overrides.clear()


def test_get_task_close_reason_null_for_open(client: TestClient, _override_deps: AsyncMock) -> None:
    """GET /api/tasks/{id} should have null close_reason for open tasks."""
    response = client.get("/api/tasks/hangar-abc")
    assert response.status_code == 200
    data = response.json()
    assert data["close_reason"] is None
