"""Tests for completing epics via store.complete_epic."""

from __future__ import annotations

import pytest

from loom.exceptions import TaskStateError
from loom.graph import store
from loom.graph.task import Task, TaskStatus
from loom.ids import task_id as gen_task_id


async def _make_epic(pool, project_id, title="test epic"):
    idea = await store.create_idea(pool, project_id, title)
    return await store.promote_idea(pool, idea.id)


async def _make_child(pool, project_id, parent_id, title="child task", status=TaskStatus.PENDING):
    task = Task(
        id=gen_task_id(), project_id=project_id, title=title,
        status=status, priority="p1", parent_id=parent_id,
    )
    return await store.create_task(pool, task)


@pytest.mark.asyncio
async def test_complete_epic_all_children_done(pool, project):
    """Epic can be completed when all children are done."""
    epic = await _make_epic(pool, project)
    child1 = await _make_child(pool, project, epic.id, "child 1")
    child2 = await _make_child(pool, project, epic.id, "child 2")

    await store.complete_task(pool, child1.id, {"summary": "done"})
    await store.complete_task(pool, child2.id, {"summary": "done"})

    result = await store.complete_epic(pool, epic.id, {"summary": "epic done"})
    assert result.status == TaskStatus.DONE
    assert result.output["summary"] == "epic done"


@pytest.mark.asyncio
async def test_complete_epic_incomplete_children_fails(pool, project):
    """Epic cannot be completed if children are still incomplete."""
    epic = await _make_epic(pool, project)
    await _make_child(pool, project, epic.id, "child 1")
    child2 = await _make_child(pool, project, epic.id, "child 2")

    await store.complete_task(pool, child2.id, {"summary": "done"})

    with pytest.raises(TaskStateError, match="1 child task.*still incomplete"):
        await store.complete_epic(pool, epic.id, {"summary": "epic done"})


@pytest.mark.asyncio
async def test_complete_epic_no_children(pool, project):
    """Epic with no children can be completed (vacuously true)."""
    epic = await _make_epic(pool, project)
    result = await store.complete_epic(pool, epic.id, {"summary": "empty epic"})
    assert result.status == TaskStatus.DONE


@pytest.mark.asyncio
async def test_complete_epic_wrong_status(pool, project):
    """Completing a non-epic task via complete_epic raises TaskStateError."""
    task = Task(
        id=gen_task_id(), project_id=project, title="regular task",
        status=TaskStatus.PENDING, priority="p1",
    )
    task = await store.create_task(pool, task)

    with pytest.raises(TaskStateError):
        await store.complete_epic(pool, task.id, {"summary": "nope"})


@pytest.mark.asyncio
async def test_complete_epic_not_found(pool):
    """Completing a nonexistent task raises TaskNotFoundError."""
    from loom.exceptions import TaskNotFoundError
    with pytest.raises(TaskNotFoundError):
        await store.complete_epic(pool, "loom-nonexistent", {"summary": "nope"})
