from __future__ import annotations

import json
import subprocess
import sys
from pathlib import Path
from typing import Any

# [unit->REQ-API-IN-PROCESS]
from attractor.testing import create_test_repo


def _bridge_path() -> Path:
    return Path(__file__).resolve().parents[1] / "scripts" / "pi" / "attractor_bridge.py"


def _invoke_bridge(
    repo_root: Path,
    command: str,
    payload: dict[str, Any] | None = None,
) -> tuple[int, dict[str, Any], str]:
    proc = subprocess.run(
        [sys.executable, str(_bridge_path()), command],
        cwd=repo_root,
        input=json.dumps(payload or {}),
        capture_output=True,
        text=True,
        check=False,
    )
    stdout_lines = [line for line in proc.stdout.splitlines() if line.strip()]
    assert stdout_lines, (
        f"bridge emitted no stdout for {command}; stderr was: {proc.stderr}"
    )
    return proc.returncode, json.loads(stdout_lines[-1]), proc.stdout


# [unit->REQ-API-IN-PROCESS]
def test_bridge_validates_workflow_in_temp_repo(tmp_path: Path) -> None:
    repo = create_test_repo(tmp_path / "repo")
    workflow = repo / "hello.dot"
    workflow.write_text(
        """
        digraph Hello {
            start [shape=Mdiamond]
            build [shape=parallelogram, script=\"echo hello\"]
            exit [shape=Msquare]
            start -> build -> exit
        }
        """.strip()
        + "\n",
        encoding="utf-8",
    )

    code, payload, _ = _invoke_bridge(
        repo, "validate", {"workflow_path": str(workflow)}
    )

    assert code == 0
    assert payload["type"] == "result"
    assert payload["command"] == "validate"
    assert payload["graph_name"] == "Hello"
    assert payload["node_count"] == 3
    assert payload["edge_count"] == 2


# [unit->REQ-API-IN-PROCESS]
def test_bridge_run_pause_show_respond_resume_cycle(tmp_path: Path) -> None:
    repo = create_test_repo(tmp_path / "repo")
    workflow = repo / "pause.dot"
    workflow.write_text(
        """
        digraph PauseCycle {
            start [shape=Mdiamond]
            prep [shape=parallelogram, script=\"echo ready > ready.txt\"]
            gate [shape=hexagon, prompt=\"Continue?\"]
            exit [shape=Msquare]
            start -> prep -> gate
            gate -> exit [label=\"continue\"]
        }
        """.strip()
        + "\n",
        encoding="utf-8",
    )

    code, run_payload, stdout = _invoke_bridge(
        repo, "run", {"workflow_path": str(workflow)}
    )

    assert code == 0
    assert run_payload["type"] == "result"
    assert run_payload["command"] == "run"
    assert run_payload["status"] == "paused"
    run_id = run_payload["run_id"]
    assert run_payload["summary"]["paused_choices"] == ["continue"]
    assert "human_gate" in stdout

    code, list_payload, _ = _invoke_bridge(repo, "list")
    assert code == 0
    assert list_payload["type"] == "result"
    assert any(item["run_id"] == run_id for item in list_payload["runs"])

    code, show_payload, _ = _invoke_bridge(repo, "show", {"run_id": run_id})
    assert code == 0
    assert show_payload["type"] == "result"
    assert show_payload["run"]["status"] == "paused"
    assert show_payload["run"]["paused_choices"] == ["continue"]

    code, respond_payload, _ = _invoke_bridge(
        repo,
        "respond",
        {"run_id": run_id, "choice": "continue", "reason": "looks good"},
    )
    assert code == 0
    assert respond_payload["type"] == "result"
    assert respond_payload["command"] == "respond"
    assert respond_payload["choice"] == "continue"

    code, resume_payload, resume_stdout = _invoke_bridge(
        repo, "resume", {"run_id": run_id}
    )
    assert code == 0
    assert resume_payload["type"] == "result"
    assert resume_payload["command"] == "resume"
    assert resume_payload["status"] == "completed"
    assert resume_payload["summary"]["status"] == "completed"
    assert "run_completed" in resume_stdout
