from __future__ import annotations

import asyncio

import pytest
import respx
from httpx import Response

from app.clients.mci_server_client import MciServerClient
from app.models.event import EventStatus, EventType, OutboundEvent
from app.repositories.event_store import EventStore
from app.services.event_publisher import EventPublisher


@pytest.fixture
def publisher(tmp_path):
    db_path = tmp_path / "events.db"
    store = EventStore(str(db_path))
    client = MciServerClient("http://mock-mci-server/msg-platform")
    pub = EventPublisher(store, client, max_retry=2, base_delay_seconds=1, interval_seconds=0.1)
    yield pub


@respx.mock
def test_publish_delivers_event(publisher):
    route = respx.post("http://mock-mci-server/msg-platform/api/v1/channel-account/event").mock(
        return_value=Response(200)
    )
    event = OutboundEvent(EventType.HEARTBEAT, "bot-001", "rescue", {"online_status": "online"})
    publisher.store.save(event)

    async def run():
        await publisher._tick()

    asyncio.run(run())
    assert route.called
    pending = publisher.store.fetch_pending(limit=10)
    assert len(pending) == 0


@respx.mock
def test_publish_retries_then_dead_letter(publisher):
    route = respx.post("http://mock-mci-server/msg-platform/api/v1/channel-account/event").mock(
        return_value=Response(500)
    )
    event = OutboundEvent(EventType.HEARTBEAT, "bot-001", "rescue", {})
    publisher.store.save(event)

    async def run():
        await publisher._tick()

    asyncio.run(run())
    assert route.call_count == 1
    updated = publisher.store.get(event.event_id)
    assert updated is not None
    assert updated.status == EventStatus.RETRYING
    assert updated.attempt_count == 1
