"""Tests for force_leaf behavior in _build_task_graph (B6 regression)."""

from __future__ import annotations

from loom.graph.task import TaskStatus
from loom.skills.decomposer import TaskDefinition, _build_task_graph

PROJECT = "test-project-id"


def _td(title: str, type: str = "task", parent_epic: str | None = None,
        depends_on_titles: list[str] | None = None) -> TaskDefinition:
    return TaskDefinition(
        title=title, type=type, parent_epic=parent_epic,
        depends_on_titles=depends_on_titles or [],
    )


def test_force_leaf_converts_childless_epics():
    """Childless epics become pending when force_leaf=True."""
    defs = [
        _td("Parent Epic", type="epic"),
        _td("Child Task", parent_epic="Parent Epic"),
        _td("Lonely Epic", type="epic"),  # no children
    ]
    result = _build_task_graph(defs, PROJECT, force_leaf=True)
    by_title = {t.title: t for t in result.tasks}

    # Childless epic should be converted to pending
    assert by_title["Lonely Epic"].status == TaskStatus.PENDING

    # Parent epic with children must stay as epic
    assert by_title["Parent Epic"].status == TaskStatus.EPIC

    # Regular child task stays pending
    assert by_title["Child Task"].status == TaskStatus.PENDING


def test_force_leaf_preserves_parent_epics_with_children():
    """Epics with children must NOT be converted even when force_leaf=True."""
    defs = [
        _td("Epic A", type="epic"),
        _td("Task A1", parent_epic="Epic A"),
        _td("Task A2", parent_epic="Epic A"),
        _td("Epic B", type="epic"),
        _td("Task B1", parent_epic="Epic B"),
    ]
    result = _build_task_graph(defs, PROJECT, force_leaf=True)
    by_title = {t.title: t for t in result.tasks}

    # Both epics have children — must remain as epics
    assert by_title["Epic A"].status == TaskStatus.EPIC
    assert by_title["Epic B"].status == TaskStatus.EPIC


def test_force_leaf_false_warns_childless():
    """Without force_leaf, childless epics get _warning tag instead of conversion."""
    defs = [
        _td("Lonely Epic", type="epic"),
        _td("Some Task"),
    ]
    result = _build_task_graph(defs, PROJECT, force_leaf=False)
    by_title = {t.title: t for t in result.tasks}

    assert by_title["Lonely Epic"].status == TaskStatus.EPIC
    assert by_title["Lonely Epic"].context.get("_warning") == "empty_epic"


def test_force_leaf_blocked_when_has_deps():
    """Childless epic with dependencies becomes blocked, not pending."""
    defs = [
        _td("First Task"),
        _td("Lonely Epic", type="epic", depends_on_titles=["First Task"]),
    ]
    result = _build_task_graph(defs, PROJECT, force_leaf=True)
    by_title = {t.title: t for t in result.tasks}

    assert by_title["Lonely Epic"].status == TaskStatus.BLOCKED


def test_force_leaf_all_childless():
    """When all epics are childless, all get converted."""
    defs = [
        _td("Epic 1", type="epic"),
        _td("Epic 2", type="epic"),
        _td("Plain Task"),
    ]
    result = _build_task_graph(defs, PROJECT, force_leaf=True)
    by_title = {t.title: t for t in result.tasks}

    assert by_title["Epic 1"].status == TaskStatus.PENDING
    assert by_title["Epic 2"].status == TaskStatus.PENDING
    assert by_title["Plain Task"].status == TaskStatus.PENDING


def test_force_leaf_mixed_hierarchy():
    """Mix of childless and parented epics — only childless converted."""
    defs = [
        _td("Root Epic", type="epic"),
        _td("Sub-epic", type="epic", parent_epic="Root Epic"),
        _td("Leaf Task", parent_epic="Sub-epic"),
        _td("Orphan Epic", type="epic"),  # childless
    ]
    result = _build_task_graph(defs, PROJECT, force_leaf=True)
    by_title = {t.title: t for t in result.tasks}

    # Root has Sub-epic as child → stays epic
    assert by_title["Root Epic"].status == TaskStatus.EPIC
    # Sub-epic has Leaf Task as child → stays epic
    assert by_title["Sub-epic"].status == TaskStatus.EPIC
    # Orphan has no children → converted
    assert by_title["Orphan Epic"].status == TaskStatus.PENDING
