"""A4 acceptance — single-flight is enforced by construction (the warden core)."""

from __future__ import annotations

import threading
from typing import Any

import pytest

from mgf.test_web.warden import RunRequest, Warden
from mgf.test_web.warden.leases import Lease


class Controllable:
    """A runner that blocks mid-run (on `release`) so concurrent submits hit the lease."""

    def __init__(self) -> None:
        self.started = threading.Event()
        self.release = threading.Event()
        self.calls: list[str] = []
        self._lock = threading.Lock()

    def __call__(self, request: RunRequest, emit: Any) -> str:
        with self._lock:
            self.calls.append(request.run_id)
        emit({"kind": "test_start"})
        self.started.set()
        self.release.wait(timeout=5)
        emit({"kind": "test_end", "result": "pass"})
        return "pass"


@pytest.mark.concurrency
def test_same_test_same_config_coalesces() -> None:
    runner = Controllable()
    warden = Warden("proj", runner)
    a = warden.submit(RunRequest("r1", "T-1", {"seed": 1}))
    assert a.status == "started"
    assert runner.started.wait(2)
    b = warden.submit(RunRequest("r2", "T-1", {"seed": 1}))  # same test + same config
    assert b.status == "coalesced"
    assert b.run_id == "r1"  # attached to the in-flight run
    runner.release.set()
    assert warden.wait_idle()
    assert runner.calls == ["r1"], "exactly one execution — the second was coalesced"
    assert any(e["event"] == "coalesced" for e in warden.registry.recent)


@pytest.mark.concurrency
def test_same_test_different_config_queues() -> None:
    runner = Controllable()
    warden = Warden("proj", runner)
    warden.submit(RunRequest("r1", "T-1", {"seed": 1}))
    assert runner.started.wait(2)
    c = warden.submit(RunRequest("r2", "T-1", {"seed": 2}))  # different config -> different work
    assert c.status == "queued"
    runner.release.set()
    assert warden.wait_idle()
    assert runner.calls == ["r1", "r2"], "both ran, serialized — never the wrong config's result"


@pytest.mark.concurrency
def test_different_test_queues() -> None:
    runner = Controllable()
    warden = Warden("proj", runner)
    warden.submit(RunRequest("r1", "T-1"))
    assert runner.started.wait(2)
    c = warden.submit(RunRequest("r2", "T-2"))  # different test on a busy project
    assert c.status == "queued"
    runner.release.set()
    assert warden.wait_idle()
    assert runner.calls == ["r1", "r2"]


@pytest.mark.concurrency
def test_independent_runs_alongside() -> None:
    runner = Controllable()
    warden = Warden("proj", runner)
    a = warden.submit(RunRequest("r1", "T-1"))  # key = project
    b = warden.submit(RunRequest("r2", "T-2", independent=True))  # key = test_id -> own lease
    assert a.status == "started"
    assert b.status == "started"
    runner.release.set()
    assert warden.wait_idle()
    assert set(runner.calls) == {"r1", "r2"}


def test_reclaim_stale_lease() -> None:
    warden = Warden("proj", lambda req, emit: "pass", ttl_s=30)
    warden.registry.running["proj"] = Lease(
        run_id="rX",
        key="proj",
        test_id="T-1",
        config_digest="sha256:x",
        origin="ci",
        who="",
        acquired_at="2020-01-01T00:00:00Z",
        heartbeat_at="2020-01-01T00:00:00Z",
        ttl_s=30,
    )
    reclaimed = warden.reclaim_stale(now="2026-01-01T00:00:00Z")
    assert reclaimed == ["rX"]
    assert "proj" not in warden.registry.running
    assert any(e["event"] == "lease_reclaimed" for e in warden.registry.recent)


def test_status_is_test_status_shaped() -> None:
    warden = Warden("proj", lambda req, emit: "pass")
    status = warden.status()
    assert status["kind"] == "test_status"
    assert status["broker"] == "up"
    assert status["project"] == "proj"
    assert status["running"] == [] and status["queued"] == []
