from __future__ import annotations

import asyncio
import threading

from infra_core.asyncio_utils import LoopBoundAsyncLock


def test_loop_bound_async_lock_reuses_lock_within_event_loop() -> None:
    helper = LoopBoundAsyncLock()

    async def runner() -> tuple[asyncio.Lock, asyncio.Lock]:
        return helper.get(), helper.get()

    first, second = asyncio.run(runner())

    assert first is second


def test_loop_bound_async_lock_is_safe_across_threads() -> None:
    helper = LoopBoundAsyncLock()
    barrier = threading.Barrier(2)
    results: dict[str, tuple[int, int]] = {}

    def worker(name: str) -> None:
        async def runner() -> None:
            barrier.wait()
            first = helper.get()
            second = helper.get()
            results[name] = (id(first), id(second))

        asyncio.run(runner())

    threads = [threading.Thread(target=worker, args=(name,)) for name in ("a", "b")]
    for thread in threads:
        thread.start()
    for thread in threads:
        thread.join(timeout=1.0)

    assert results["a"][0] == results["a"][1]
    assert results["b"][0] == results["b"][1]
    assert results["a"][0] != results["b"][0]
