"""Tests for BridgeClient — connection lifecycle, auth handshake, reconnect."""

from __future__ import annotations

import asyncio
import json

import pytest

from beeos_bridge_client import (
    BridgeClient,
    BridgeClientOptions,
    ClientState,
    ReconnectConfig,
    generate_key_pair,
)


def _make_client(**overrides) -> BridgeClient:
    kp = generate_key_pair()
    opts = BridgeClientOptions(
        bridge_url="wss://localhost:9999",
        service="acp",
        private_key=kp.private_key,
        public_key=kp.public_key,
        reconnect=ReconnectConfig(enabled=False),
        **overrides,
    )
    return BridgeClient(opts)


def test_initial_state():
    client = _make_client()
    assert client.state == ClientState.IDLE


def test_public_key_properties():
    kp = generate_key_pair()
    client = BridgeClient(BridgeClientOptions(
        bridge_url="wss://localhost:9999",
        service="acp",
        private_key=kp.private_key,
        public_key=kp.public_key,
        reconnect=ReconnectConfig(enabled=False),
    ))
    assert len(client.public_key_b64) > 0
    assert len(client.public_key_fingerprint) == 64


def test_requires_key_material():
    with pytest.raises(ValueError, match="requires either"):
        BridgeClient(BridgeClientOptions(
            bridge_url="wss://localhost:9999",
            service="acp",
            reconnect=ReconnectConfig(enabled=False),
        ))


@pytest.mark.asyncio
async def test_send_before_connect_raises():
    client = _make_client()
    with pytest.raises(RuntimeError, match="Not connected"):
        await client.send("hello")


@pytest.mark.asyncio
async def test_connect_failure_raises():
    client = _make_client()
    with pytest.raises(Exception):
        await client.connect()


@pytest.mark.asyncio
async def test_close_idempotent():
    client = _make_client()
    await client.close()
    assert client.state == ClientState.CLOSED
    await client.close()  # should not raise


def test_event_registration():
    client = _make_client()
    calls = []
    client.on("connected", lambda: calls.append("connected"))
    client._emit("connected")
    assert calls == ["connected"]


def test_event_with_args():
    client = _make_client()
    received = []
    client.on("message", lambda data: received.append(data))
    client._emit("message", '{"foo": "bar"}')
    assert received == ['{"foo": "bar"}']
