"""Tests for StreamHandler status callback."""

import asyncio

import pytest

from flowire_sdk.stream_handler import StreamHandler, StreamSubscription


class FakeHandler(StreamHandler):
    """Test handler that connects immediately."""

    def __init__(self, *args, fail_connect=False, **kwargs):
        super().__init__(*args, **kwargs)
        self.fail_connect = fail_connect

    async def connect(self):
        if self.fail_connect:
            raise ConnectionError("fake connection error")

    async def disconnect(self):
        pass

    async def listen(self):
        # Yield nothing, just wait until stopped
        while not self._stop_event.is_set():
            await asyncio.sleep(0.1)
            return


def make_subscription():
    return StreamSubscription(
        id="sub-1",
        workflow_id="wf-1",
        node_id="node-1",
        stream_type="test",
        credential_id=None,
        connection_config={},
        event_filter=None,
        status="pending",
        project_id="proj-1",
    )


async def noop_event_callback(sub, event):
    pass


async def noop_credential_resolver(cred_id):
    return {}


@pytest.mark.asyncio
async def test_status_callback_called_on_connect():
    statuses = []

    def on_status(subscription_id, status, error_message=None):
        statuses.append((subscription_id, status, error_message))

    handler = FakeHandler(
        subscription=make_subscription(),
        event_callback=noop_event_callback,
        credential_resolver=noop_credential_resolver,
    )
    handler.status_callback = on_status

    task = asyncio.create_task(handler.run())
    await asyncio.sleep(0.3)
    handler.stop()
    await task

    assert ("sub-1", "connecting", None) in statuses
    assert ("sub-1", "connected", None) in statuses


@pytest.mark.asyncio
async def test_status_callback_called_on_error():
    statuses = []

    def on_status(subscription_id, status, error_message=None):
        statuses.append((subscription_id, status, error_message))

    handler = FakeHandler(
        subscription=make_subscription(),
        event_callback=noop_event_callback,
        credential_resolver=noop_credential_resolver,
        fail_connect=True,
    )
    handler.status_callback = on_status

    # Let it try once, then stop
    task = asyncio.create_task(handler.run())
    await asyncio.sleep(0.5)
    handler.stop()
    await task

    connecting = [s for s in statuses if s[1] == "connecting"]
    errors = [s for s in statuses if s[1] == "error"]
    assert len(connecting) >= 1
    assert len(errors) >= 1
    assert "fake connection error" in errors[0][2]


@pytest.mark.asyncio
async def test_status_callback_not_required():
    """Handler should work fine without a status callback set."""
    handler = FakeHandler(
        subscription=make_subscription(),
        event_callback=noop_event_callback,
        credential_resolver=noop_credential_resolver,
    )
    # No status_callback set — should not raise

    task = asyncio.create_task(handler.run())
    await asyncio.sleep(0.3)
    handler.stop()
    await task
