"""Tests for StatsService."""

from unittest.mock import AsyncMock

import pytest

from hangar.models.beads import BeadsDependencyRef, BeadsTask, BeadsTaskList
from hangar.services.stats import StatsService


@pytest.fixture
def mock_beads_service() -> AsyncMock:
    """Create a mock BeadsService."""
    return AsyncMock()


@pytest.fixture
def service(mock_beads_service: AsyncMock) -> StatsService:
    """Create a StatsService with mocked BeadsService."""
    return StatsService(beads_service=mock_beads_service)


def _make_task(
    id: str,
    title: str,
    status: str = "open",
    issue_type: str = "task",
    created_at: str | None = None,
    closed_at: str | None = None,
    close_reason: str | None = None,
    dependencies: list[dict] | None = None,
) -> BeadsTask:
    """Helper to create a BeadsTask."""
    deps = []
    if dependencies:
        deps = [BeadsDependencyRef(**d) for d in dependencies]
    return BeadsTask(
        id=id,
        title=title,
        status=status,
        issue_type=issue_type,
        created_at=created_at,
        closed_at=closed_at,
        close_reason=close_reason,
        dependencies=deps,
    )


@pytest.mark.asyncio
async def test_empty_stats(service: StatsService, mock_beads_service: AsyncMock) -> None:
    """Stats with no tasks should return zeroes."""
    mock_beads_service.list_tasks.return_value = BeadsTaskList(tasks=[])
    result = await service.get_stats()
    assert result.total_tasks == 0
    assert result.completion_rate == 0.0


@pytest.mark.asyncio
async def test_basic_stats(service: StatsService, mock_beads_service: AsyncMock) -> None:
    """Stats should count tasks correctly by status."""
    mock_beads_service.list_tasks.return_value = BeadsTaskList(tasks=[
        _make_task("t1", "Open", "open", created_at="2026-02-07T10:00:00+01:00"),
        _make_task("t2", "In Progress", "in_progress", created_at="2026-02-07T10:00:00+01:00"),
        _make_task("t3", "Closed", "closed",
                   created_at="2026-02-07T10:00:00+01:00",
                   closed_at="2026-02-07T12:00:00+01:00"),
    ])
    result = await service.get_stats()
    assert result.total_tasks == 3
    assert result.open_tasks == 1
    assert result.in_progress_tasks == 1
    assert result.closed_tasks == 1
    assert result.completion_rate == 33.3


@pytest.mark.asyncio
async def test_completion_rate_all_closed(service: StatsService, mock_beads_service: AsyncMock) -> None:
    """100% completion when all tasks closed."""
    mock_beads_service.list_tasks.return_value = BeadsTaskList(tasks=[
        _make_task("t1", "Done 1", "closed",
                   created_at="2026-02-07T10:00:00+01:00",
                   closed_at="2026-02-07T12:00:00+01:00"),
        _make_task("t2", "Done 2", "closed",
                   created_at="2026-02-07T11:00:00+01:00",
                   closed_at="2026-02-07T13:00:00+01:00"),
    ])
    result = await service.get_stats()
    assert result.completion_rate == 100.0
    assert result.avg_lead_time_hours is not None
    assert result.avg_lead_time_hours == 2.0


@pytest.mark.asyncio
async def test_epic_stats(service: StatsService, mock_beads_service: AsyncMock) -> None:
    """Per-epic stats should group child tasks correctly."""
    mock_beads_service.list_tasks.return_value = BeadsTaskList(tasks=[
        _make_task("epic-1", "My Epic", "open", issue_type="epic"),
        _make_task("epic-1.1", "Child 1", "closed",
                   created_at="2026-02-07T10:00:00+01:00",
                   closed_at="2026-02-07T12:00:00+01:00"),
        _make_task("epic-1.2", "Child 2", "open",
                   created_at="2026-02-07T11:00:00+01:00"),
    ])
    result = await service.get_stats()
    assert len(result.epic_stats) == 1
    epic = result.epic_stats[0]
    assert epic.epic_id == "epic-1"
    assert epic.task_count == 2
    assert epic.closed_count == 1


@pytest.mark.asyncio
async def test_throughput(service: StatsService, mock_beads_service: AsyncMock) -> None:
    """Throughput should be calculated as tasks closed per day."""
    mock_beads_service.list_tasks.return_value = BeadsTaskList(tasks=[
        _make_task("t1", "Done", "closed",
                   created_at="2026-02-07T00:00:00+01:00",
                   closed_at="2026-02-08T00:00:00+01:00"),
        _make_task("t2", "Done too", "closed",
                   created_at="2026-02-07T00:00:00+01:00",
                   closed_at="2026-02-09T00:00:00+01:00"),
    ])
    result = await service.get_stats()
    assert result.throughput_per_day is not None
    # 2 tasks closed over 2 days = 1.0/day
    assert result.throughput_per_day == 1.0
