# retoor <retoor@molodetz.nl>

import pytest
from starlette.websockets import WebSocketDisconnect

from devplacepy.services.manager import service_manager


def test_query_requires_auth(client):
    assert client.post("/dbapi/query", json={"sql": "SELECT 1"}).status_code == 403


def test_select_runs(client, auth):
    response = client.post("/dbapi/query", json={"sql": "SELECT 1 AS n"}, headers=auth)
    assert response.status_code == 200
    body = response.json()
    assert body["valid"] is True
    assert body["rows"] == [{"n": 1}]


def test_non_select_is_409(client, auth):
    response = client.post(
        "/dbapi/query", json={"sql": "DELETE FROM posts"}, headers=auth
    )
    assert response.status_code == 409
    assert response.json()["statement_type"] == "delete"


def test_invalid_sql_is_400(client, auth):
    response = client.post(
        "/dbapi/query", json={"sql": "SELECT * FROM no_such_table_zzz"}, headers=auth
    )
    assert response.status_code == 400


def test_suspicious_select_is_flagged(client, auth):
    response = client.post(
        "/dbapi/query", json={"sql": "SELECT * FROM users"}, headers=auth
    )
    assert response.status_code == 200
    assert response.json()["suspicious"]


def test_async_enqueue_and_status(client, auth):
    enqueued = client.post(
        "/dbapi/query/async", json={"sql": "SELECT uid FROM users LIMIT 3"}, headers=auth
    )
    assert enqueued.status_code == 200
    uid = enqueued.json()["uid"]
    assert enqueued.json()["ws_url"].endswith("/ws")
    assert client.get(f"/dbapi/query/{uid}", headers=auth).status_code == 200


def test_async_non_select_is_409(client, auth):
    response = client.post(
        "/dbapi/query/async", json={"sql": "UPDATE users SET role = 1"}, headers=auth
    )
    assert response.status_code == 409


def test_ws_unknown_job_is_closed(client, auth):
    with client.websocket_connect("/dbapi/query/not-a-real-uid/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("/dbapi/query/anything/ws") as ws:
            with pytest.raises(WebSocketDisconnect) as info:
                ws.receive_json()
        assert info.value.code == 4013
    finally:
        service_manager.set_lock_owner(True)
