"""Dispatcher heartbeat — a silently-dead dispatch loop must be detectable.

Live outage (2026-07-01): zero spawns fleet-wide for 4h25m; the old
orchestrator's dispatch loop died with no log line, no audit row, nothing —
the deploy's restart is what fixed it, and the cause is unrecoverable. A
periodic ``dispatcher.alive`` audit row makes "loop dead" distinguishable
from "no work" straight from the DB (and gives the panel a staleness signal).
"""

from __future__ import annotations

from datetime import UTC, datetime, timedelta
from typing import Any, cast
from unittest.mock import MagicMock
from uuid import uuid4  # noqa: F401 - parity with sibling harnesses

import pytest
from roboco.runtime.orchestrator import AgentOrchestrator

_TWO_HEARTBEATS = 2


def _orch() -> AgentOrchestrator:
    orch = AgentOrchestrator.__new__(AgentOrchestrator)
    o = cast("Any", orch)
    o._last_dispatch_heartbeat = None
    o._fire_audit = MagicMock()
    return orch


@pytest.mark.asyncio
async def test_first_tick_emits_heartbeat() -> None:
    orch = _orch()
    await orch._emit_dispatcher_heartbeat()
    cast("Any", orch)._fire_audit.assert_called_once()
    kwargs = cast("Any", orch)._fire_audit.call_args.kwargs
    assert kwargs["event_type"] == "dispatcher.alive"


@pytest.mark.asyncio
async def test_heartbeat_throttled_within_window() -> None:
    orch = _orch()
    await orch._emit_dispatcher_heartbeat()
    await orch._emit_dispatcher_heartbeat()
    assert cast("Any", orch)._fire_audit.call_count == 1


@pytest.mark.asyncio
async def test_heartbeat_re_emits_after_window() -> None:
    orch = _orch()
    await orch._emit_dispatcher_heartbeat()
    cast("Any", orch)._last_dispatch_heartbeat = datetime.now(UTC) - timedelta(
        seconds=400
    )
    await orch._emit_dispatcher_heartbeat()
    assert cast("Any", orch)._fire_audit.call_count == _TWO_HEARTBEATS
