"""Tests for event-driven swarm orchestration."""
from __future__ import annotations

import asyncio

import pytest

from logos_adk.event_bus import InMemoryEventBus
from logos_adk.swarm import Swarm


@pytest.mark.asyncio
async def test_swarm_claims_event_and_publishes_response():
    bus = InMemoryEventBus()
    swarm = Swarm("seo-swarm", event_bus=bus)

    async def optimize(event):
        return {"optimized": event.payload["prompt"].upper()}

    swarm.subscribe("need_seo", optimize, publish_to="seo_done")
    request = bus.publish(
        "need_seo",
        {"prompt": "summer sale"},
        correlation_id="corr-1",
        run_id="run-1",
        publisher="graph",
    )

    processed = await swarm.drain()

    assert processed == 1
    request_after = bus.get_event(request.id)
    assert request_after is not None
    assert request_after.status == "completed"

    responses = bus.list_events(topic="seo_done", correlation_id="corr-1", run_id="run-1")
    assert len(responses) == 1
    assert responses[0].payload == {"optimized": "SUMMER SALE"}
    assert responses[0].status == "queued"


@pytest.mark.asyncio
async def test_swarm_dispatch_events_requeues_failed_event():
    bus = InMemoryEventBus()
    swarm = Swarm("seo-swarm", event_bus=bus, retry_delay_seconds=0.0)

    async def fail(event):
        raise RuntimeError("boom")

    swarm.subscribe("need_seo", fail, publish_to="seo_done")

    with pytest.raises(RuntimeError, match="boom"):
        async for _ in swarm.dispatch_events(
            "summer sale",
            request_topic="need_seo",
            response_topic="seo_done",
            correlation_id="corr-2",
            run_id="run-2",
        ):
            pass

    request = bus.list_events(topic="need_seo", correlation_id="corr-2", run_id="run-2")[0]
    assert request.status == "queued"
    assert request.last_error == "RuntimeError: boom"
    assert request.lease_owner is None


@pytest.mark.asyncio
async def test_swarm_dispatch_events_emits_progress_for_slow_handler():
    bus = InMemoryEventBus()
    swarm = Swarm(
        "seo-swarm",
        event_bus=bus,
        slow_step_notice_seconds=0.01,
        slow_step_repeat_seconds=0.01,
    )

    async def slow(event):
        await asyncio.sleep(0.03)
        return {"optimized": event.payload["prompt"].upper()}

    swarm.subscribe("need_seo", slow, publish_to="seo_done")

    events = [
        event
        async for event in swarm.dispatch_events(
            "summer sale",
            request_topic="need_seo",
            response_topic="seo_done",
            correlation_id="corr-3",
            run_id="run-3",
        )
    ]

    assert any(event["event"] == "node_progress" for event in events)
    progress = next(event for event in events if event["event"] == "node_progress")
    assert progress["user_facing"]["visible"] is True
    assert "дольше обычного" in progress["user_facing"]["detail"]
