# retoor <retoor@molodetz.nl>

import pytest
from starlette.websockets import WebSocketDisconnect

from devplacepy.services.manager import service_manager


def test_publish_requires_auth(client):
    assert client.post("/pubsub/publish", json={"topic": "public.x", "data": 1}).status_code == 403


def test_topics_requires_auth(client):
    assert client.get("/pubsub/topics").status_code == 403


def test_http_publish_and_topics(client, auth):
    assert (
        client.post(
            "/pubsub/publish", json={"topic": "public.demo", "data": {"a": 1}}, headers=auth
        ).status_code
        == 200
    )
    assert client.get("/pubsub/topics", headers=auth).status_code == 200


def test_ws_pubsub_delivery(client, auth):
    with client.websocket_connect("/pubsub/ws", headers=auth) as receiver:
        assert receiver.receive_json()["type"] == "ready"
        receiver.send_json({"type": "subscribe", "topic": "public.room"})
        assert receiver.receive_json()["type"] == "subscribed"
        with client.websocket_connect("/pubsub/ws", headers=auth) as sender:
            sender.receive_json()
            sender.send_json(
                {"type": "publish", "topic": "public.room", "data": {"hi": 1}}
            )
            ack = sender.receive_json()
            assert ack["type"] == "ack" and ack["delivered"] == 1
            message = receiver.receive_json()
            assert message["type"] == "message"
            assert message["topic"] == "public.room"
            assert message["data"] == {"hi": 1}


def test_ws_invalid_topic_errors(client, auth):
    with client.websocket_connect("/pubsub/ws", headers=auth) as ws:
        ws.receive_json()
        ws.send_json({"type": "subscribe", "topic": "bad topic"})
        assert ws.receive_json()["type"] == "error"


def test_ws_guest_closed_when_disabled(client):
    with client.websocket_connect("/pubsub/ws") as ws:
        with pytest.raises(WebSocketDisconnect) as info:
            ws.receive_json()
    assert info.value.code == 1008


def test_ws_non_owner_retries(client, auth):
    service_manager.set_lock_owner(False)
    try:
        with client.websocket_connect("/pubsub/ws", headers=auth) as ws:
            with pytest.raises(WebSocketDisconnect) as info:
                ws.receive_json()
        assert info.value.code == 4013
    finally:
        service_manager.set_lock_owner(True)
