"""
Tests: execute_async_deliver_guard module (register/clear); poll no longer uses guard.

After Step 02, poll loop does not skip by deliver_id; queue terminals always notify.
Guard module remains for any legacy or test use; poll correctness does not depend on it.
Author: Vasiliy Zdanovskiy
email: vasilyvz@gmail.com
"""

from __future__ import annotations

import asyncio
from unittest.mock import AsyncMock, MagicMock

import pytest

from mcp_proxy_adapter.core.job_push import execute_async_deliver_guard as guard
from mcp_proxy_adapter.core.job_push.lifespan_wiring import _job_push_poll_loop
from mcp_proxy_adapter.core.job_push.notifier import (
    NotificationDomain,
    clear_notifier_listeners,
    register_notifier_listener,
)
from mcp_proxy_adapter.integrations.queuemgr_integration import (
    QueueJobResult,
    QueueJobStatus,
)


@pytest.mark.asyncio
async def test_poll_loop_notifies_queue_subscribers_for_terminal_job(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Poll loop calls notifier for terminal queue job (no guard skip)."""
    clear_notifier_listeners()
    notifies: list[tuple[str, str, object]] = []

    async def capture_listener(
        domain: NotificationDomain,
        identifier: str,
        status: str,
        result: object,
        error: object,
        progress: int,
        description: str,
    ) -> None:
        notifies.append((identifier, status, result))

    register_notifier_listener(capture_listener)

    app = MagicMock()
    registry = AsyncMock()
    registry.get_subscribed_keys_for_queue_poll = AsyncMock(return_value=["job-x"])
    app.state.job_push_registry = registry
    app.state.ws_delivery_manager = AsyncMock()
    app.state.ws_delivery_manager.resolve_ws_id_for_job = AsyncMock(return_value=None)

    async def fake_get_qm() -> MagicMock:
        qm = MagicMock()

        async def gjs(job_id: str) -> QueueJobResult:
            return QueueJobResult(
                job_id=job_id,
                status=QueueJobStatus.COMPLETED,
                result={},
                error=None,
                progress=100,
                description="",
            )

        qm.get_job_status = gjs
        return qm

    monkeypatch.setattr(
        "mcp_proxy_adapter.integrations.queuemgr_integration.get_global_queue_manager",
        fake_get_qm,
    )
    monkeypatch.setattr(
        "mcp_proxy_adapter.core.job_push.lifespan_wiring.JOB_PUSH_POLL_INTERVAL",
        0.01,
    )

    task = asyncio.create_task(_job_push_poll_loop(app))
    await asyncio.sleep(0.08)
    task.cancel()
    try:
        await task
    except asyncio.CancelledError:
        pass

    assert len(notifies) >= 1
    assert notifies[0][0] == "job-x"
    assert notifies[0][1] == "completed"
    clear_notifier_listeners()


def test_guard_register_clear() -> None:
    """register / unregister / clear_execute_async_deliver_ids."""
    clear_notifier_listeners()
    assert not guard.is_execute_async_deliver_id_in_flight("a")
    guard.register_execute_async_deliver_id("a")
    assert guard.is_execute_async_deliver_id_in_flight("a")
    guard.unregister_execute_async_deliver_id("a")
    assert not guard.is_execute_async_deliver_id_in_flight("a")
    guard.register_execute_async_deliver_id("b")
    clear_notifier_listeners()
    assert not guard.is_execute_async_deliver_id_in_flight("b")
