"""A4 acceptance — single-flight holds across processes (via the UDS daemon), fail-closed."""

from __future__ import annotations

import time
from collections.abc import Iterator
from pathlib import Path
from typing import Any

import pytest

from mgf.test_web.warden import (
    RunRequest,
    Warden,
    WardenClient,
    WardenDaemon,
    WardenUnreachable,
)


def _sleep_runner(request: RunRequest, emit: Any) -> str:
    emit({"kind": "test_start"})
    time.sleep(float(request.config.get("sleep", 0)))
    emit({"kind": "test_end", "result": "pass"})
    return "pass"


@pytest.fixture
def daemon(tmp_path: Path) -> Iterator[tuple[Warden, WardenClient, WardenDaemon]]:
    sock = tmp_path / "warden.sock"
    warden = Warden("proj", _sleep_runner)
    daemon = WardenDaemon(warden, sock)
    daemon.start_background()
    client = WardenClient(sock)
    for _ in range(200):
        if client.ping():
            break
        time.sleep(0.01)
    try:
        yield warden, client, daemon
    finally:
        daemon.shutdown()


@pytest.mark.concurrency
def test_cross_process_single_flight(daemon: tuple[Warden, WardenClient, WardenDaemon]) -> None:
    warden, client, _ = daemon
    a = client.run(RunRequest("r1", "T-1", {"seed": 1, "sleep": 1}))
    assert a["status"] == "started"
    b = client.run(RunRequest("r2", "T-1", {"seed": 1, "sleep": 1}))  # same test+config, in-flight
    assert b["status"] == "coalesced"
    assert b["run_id"] == "r1"
    assert warden.wait_idle(timeout=5)


@pytest.mark.concurrency
def test_status_over_socket(daemon: tuple[Warden, WardenClient, WardenDaemon]) -> None:
    _, client, _ = daemon
    status = client.status()
    assert status["ok"]
    assert status["kind"] == "test_status"
    assert status["broker"] == "up"


def test_fail_closed_when_warden_down(tmp_path: Path) -> None:
    client = WardenClient(tmp_path / "nope.sock")
    assert client.ping() is False
    with pytest.raises(WardenUnreachable):
        client.run(RunRequest("r1", "T-1"))


def test_singleton_refuses_a_second_warden(tmp_path: Path) -> None:
    sock = tmp_path / "w.sock"
    first = WardenDaemon(Warden("proj", _sleep_runner), sock)
    first.start_background()
    try:
        second = WardenDaemon(Warden("proj", _sleep_runner), sock)
        with pytest.raises(RuntimeError):
            second.start_background()
    finally:
        first.shutdown()
