import asyncio

import pytest

from app.runtime.config import GlobalVar


def test_global_loop_requires_lifecycle_owner() -> None:
    """启动前读取主循环不得隐式创建一个无法执行任务的循环。"""
    runtime = GlobalVar()
    runtime.CURRENT_EVENT_LOOP = None

    with pytest.raises(RuntimeError, match="主事件循环尚未启动或已经停止"):
        _ = runtime.loop

    assert runtime.CURRENT_EVENT_LOOP is None


def test_global_loop_rejects_closed_owner() -> None:
    """已关闭的生命周期 owner 不得继续接收跨线程任务。"""
    runtime = GlobalVar()
    loop = asyncio.new_event_loop()
    runtime.set_loop(loop)
    loop.close()

    with pytest.raises(RuntimeError, match="主事件循环尚未启动或已经停止"):
        _ = runtime.loop


def test_global_loop_rejects_owner_that_is_not_running() -> None:
    """未运行的循环不得成为跨线程任务投递目标。"""
    runtime = GlobalVar()
    loop = asyncio.new_event_loop()
    try:
        runtime.set_loop(loop)

        with pytest.raises(RuntimeError, match="主事件循环尚未启动或已经停止"):
            _ = runtime.loop
    finally:
        loop.close()


def test_clear_global_loop_preserves_new_owner() -> None:
    """迟到的旧生命周期清理不得清除后来登记的循环。"""
    runtime = GlobalVar()
    previous = asyncio.new_event_loop()

    async def verify() -> None:
        current = asyncio.get_running_loop()
        previous_owner = runtime.set_loop(previous)
        current_owner = runtime.set_loop(current)
        runtime.clear_loop(previous_owner)
        assert runtime.loop is current

        runtime.clear_loop(current_owner)
        assert runtime.CURRENT_EVENT_LOOP is None

    try:
        asyncio.run(verify())
    finally:
        previous.close()


def test_nested_owner_release_restores_same_event_loop() -> None:
    """同一循环上的内层生命周期退出后，外层 owner 仍保持登记。"""
    runtime = GlobalVar()

    async def verify() -> None:
        loop = asyncio.get_running_loop()
        outer_owner = runtime.set_loop(loop)
        inner_owner = runtime.set_loop(loop)

        runtime.clear_loop(inner_owner)
        assert runtime.loop is loop

        runtime.clear_loop(outer_owner)
        assert runtime.CURRENT_EVENT_LOOP is None

    asyncio.run(verify())
