"""Shared fixtures for engine tests.

Engine integration tests need a real git repo with at least one commit
on `main` so `WorktreeManager.create` has a `base_ref` to seed from.
The `seeded_repo` fixture delegates to `attractor.testing.create_test_repo`
so the helper that hosts use is exercised on every CI run.
"""

from __future__ import annotations

import shutil
from collections.abc import Sequence
from pathlib import Path

import pytest

from attractor.execution import local as _local_exec
from attractor.testing import create_test_repo


def _pick_test_shell() -> tuple[str, Sequence[str]] | None:
    """Return a `(executable, leading_args)` pair we can run scripts under.

    Mirrors the strategy from `tests/test_execution/conftest.py`: prefer
    pwsh (the production shell on Windows), else sh (Git Bash). Allows
    integration tests to run on hosts that don't ship pwsh.
    """
    pwsh = shutil.which("pwsh")
    if pwsh is not None:
        return (pwsh, ("-NoProfile", "-Command"))
    sh = shutil.which("sh")
    if sh is not None:
        return (sh, ("-c",))
    return None


@pytest.fixture(autouse=True)
def _patch_shell(  # pyright: ignore[reportUnusedFunction]
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Autouse fixture: route tool-node scripts through whatever shell
    the test host has. Skips the test if neither pwsh nor sh is on PATH.

    Production code never reads from this seam — it's monkeypatched
    just for the duration of one test.
    """
    picked = _pick_test_shell()
    if picked is None:
        pytest.skip("no usable shell on PATH (need pwsh or sh)")

    def _patched() -> tuple[str, Sequence[str]]:
        return picked

    monkeypatch.setattr(_local_exec, "_resolve_shell", _patched)


@pytest.fixture()
def seeded_repo(tmp_path: Path) -> Path:
    """A repo at `tmp_path / repo/` with one commit on `main`."""
    return create_test_repo(tmp_path / "repo")


@pytest.fixture()
def tool_only_workflow() -> str:
    """A small SUCCESS-only tool-only workflow exercising the full lifecycle.

    Uses `echo`-style commands that work uniformly on bash and pwsh.
    Goal-gate satisfied via the `verify` node.
    """
    return _TOOL_ONLY


@pytest.fixture()
def goal_gate_unmet_workflow() -> str:
    """A tool-only workflow with a goal_gate that fails, so the run ends
    INCOMPLETE."""
    return _GOAL_GATE_UNMET


@pytest.fixture()
def human_gate_workflow() -> str:
    """A workflow with a hexagon to exercise pause / respond / resume."""
    return _HUMAN_GATE


@pytest.fixture()
def max_visits_workflow() -> str:
    """A workflow whose verify->fixup loop exhausts max_visits."""
    return _MAX_VISITS


# Workflow fixtures. Kept inline so each test reads with the source
# alongside its assertion. `echo > file` is the portable mutation that
# proves the worktree commit captures changes; both `sh -c` and
# `pwsh -Command` handle quoted echo identically on common installs.

_TOOL_ONLY = """\
digraph ToolOnly {
    graph [ default_max_visits = 3 ]
    start [shape=Mdiamond, label="Start"]
    exit  [shape=Msquare,  label="Exit"]
    build [
        shape  = parallelogram,
        label  = "Build",
        script = "echo built > build.log"
    ]
    verify [
        shape     = parallelogram,
        label     = "Verify",
        script    = "echo verified",
        goal_gate = true
    ]
    start -> build -> verify -> exit
}
"""

_GOAL_GATE_UNMET = """\
digraph GoalGateUnmet {
    graph [ default_max_visits = 3 ]
    start [shape=Mdiamond, label="Start"]
    exit  [shape=Msquare,  label="Exit"]
    verify [
        shape     = parallelogram,
        label     = "Verify",
        script    = "exit 1",
        goal_gate = true
    ]
    start -> verify
    verify -> exit [label="SUCCESS"]
}
"""

_HUMAN_GATE = """\
digraph HumanGate {
    graph [ default_max_visits = 3 ]
    start [shape=Mdiamond, label="Start"]
    exit  [shape=Msquare,  label="Exit"]
    prep  [
        shape  = parallelogram,
        label  = "Prep",
        script = "echo ready > prep.log"
    ]
    decide [shape=hexagon, label="Approve?"]
    start  -> prep -> decide
    decide -> exit [label="approve"]
    decide -> prep [label="revise"]
}
"""

_MAX_VISITS = """\
digraph MaxVisits {
    graph [ default_max_visits = 2 ]
    start [shape=Mdiamond, label="Start"]
    exit  [shape=Msquare,  label="Exit"]
    verify [
        shape      = parallelogram,
        label      = "Verify",
        script     = "exit 1",
        goal_gate  = true,
        max_visits = 2
    ]
    fixup [
        shape  = parallelogram,
        label  = "Fixup",
        script = "echo patched > patch.log"
    ]
    start -> verify
    verify -> exit  [label="SUCCESS"]
    verify -> fixup [label="FAILURE"]
    fixup -> verify
}
"""
