"""CLI tests for `attractor run abort`. SPEC §13.

Engine-side abort coverage is in `tests/test_engine/test_abort.py`;
this file drives the CLI surface end-to-end.
"""

from __future__ import annotations

import os
from pathlib import Path

from click.testing import CliRunner

from attractor.cli.main import cli

_HUMAN_GATE = """\
digraph HG {
    graph [ default_max_visits = 3 ]
    start [shape=Mdiamond, label="S"]
    exit  [shape=Msquare,  label="E"]
    prep  [shape=parallelogram, script="echo prep"]
    decide [shape=hexagon, label="Approve?"]
    start  -> prep -> decide
    decide -> exit  [label="approve"]
    decide -> prep  [label="revise"]
}
"""

_TOOL_ONLY = """\
digraph T {
    graph [ default_max_visits = 2 ]
    start [shape=Mdiamond, label="S"]
    exit  [shape=Msquare,  label="E"]
    build [shape=parallelogram, script="echo built > build.log"]
    start -> build -> exit
}
"""


def _run_to_pause(seeded_repo: Path, source: str) -> str:
    """Drop a workflow, run it to PAUSED, return the run-id."""
    wf = seeded_repo / "wf.dot"
    wf.write_text(source, encoding="utf-8")
    cwd = os.getcwd()
    try:
        os.chdir(seeded_repo)
        result = CliRunner().invoke(cli, ["run", str(wf)])
        assert result.exit_code == 0, result.output  # PAUSED is exit 0
    finally:
        os.chdir(cwd)
    from attractor.engine import Engine
    handles = [h for h in Engine(seeded_repo).list() if h.status.value == "paused"]
    assert len(handles) == 1, handles
    return handles[0].run_id


def _run_to_completion(seeded_repo: Path, source: str) -> str:
    wf = seeded_repo / "wf.dot"
    wf.write_text(source, encoding="utf-8")
    cwd = os.getcwd()
    try:
        os.chdir(seeded_repo)
        result = CliRunner().invoke(cli, ["run", str(wf)])
        assert result.exit_code == 0, result.output
    finally:
        os.chdir(cwd)
    from attractor.engine import Engine
    return Engine(seeded_repo).list_all_run_ids()[0]


# [int->REQ-CLI-RUN-ABORT]
def test_run_abort_terminates_paused_run(seeded_repo: Path) -> None:
    run_id = _run_to_pause(seeded_repo, _HUMAN_GATE)
    cwd = os.getcwd()
    try:
        os.chdir(seeded_repo)
        result = CliRunner().invoke(cli, ["run", "abort", run_id])
    finally:
        os.chdir(cwd)
    assert result.exit_code == 0, result.output
    assert "aborted" in result.output.lower()
    assert "paused" in result.output.lower()
    assert "incomplete" in result.output.lower()

    from attractor.engine import Engine, RunStatus
    summary = Engine(seeded_repo).show(run_id)
    assert summary.status == RunStatus.INCOMPLETE


# [int->REQ-CLI-RUN-ABORT]
def test_run_abort_unknown_run_exits_2(seeded_repo: Path) -> None:
    cwd = os.getcwd()
    try:
        os.chdir(seeded_repo)
        result = CliRunner().invoke(
            cli, ["run", "abort", "00000000-0000-0000-0000-000000000000"]
        )
    finally:
        os.chdir(cwd)
    assert result.exit_code == 2, result.output
    assert "unknown run" in result.output.lower()


# [int->REQ-CLI-RUN-ABORT]
def test_run_abort_refuses_completed_run(seeded_repo: Path) -> None:
    run_id = _run_to_completion(seeded_repo, _TOOL_ONLY)
    cwd = os.getcwd()
    try:
        os.chdir(seeded_repo)
        result = CliRunner().invoke(cli, ["run", "abort", run_id])
    finally:
        os.chdir(cwd)
    assert result.exit_code == 2, result.output
    assert "not paused" in result.output.lower()
    assert "prune" in result.output.lower()
