"""Tests for distributed merge lock helpers."""

from __future__ import annotations

import pytest

from loom.bus.locks import acquire_merge_lock, release_merge_lock


@pytest.mark.asyncio
async def test_acquire_returns_token_when_free(redis_conn):
    """Acquiring an unheld lock returns a non-empty token string."""
    token = await acquire_merge_lock(redis_conn)
    assert token is not None
    assert isinstance(token, str)
    assert len(token) == 32  # uuid4 hex


@pytest.mark.asyncio
async def test_acquire_returns_none_when_held(redis_conn):
    """A second acquire while the lock is held returns None."""
    token = await acquire_merge_lock(redis_conn)
    assert token is not None
    second = await acquire_merge_lock(redis_conn)
    assert second is None


@pytest.mark.asyncio
async def test_release_correct_token_returns_true(redis_conn):
    """Releasing with the correct token succeeds."""
    token = await acquire_merge_lock(redis_conn)
    assert token is not None
    released = await release_merge_lock(redis_conn, token)
    assert released is True


@pytest.mark.asyncio
async def test_release_wrong_token_returns_false(redis_conn):
    """Releasing with a wrong token fails."""
    token = await acquire_merge_lock(redis_conn)
    assert token is not None
    released = await release_merge_lock(redis_conn, "wrong-token-value")
    assert released is False


@pytest.mark.asyncio
async def test_release_when_key_gone_returns_false(redis_conn):
    """Releasing when no lock is held returns False."""
    released = await release_merge_lock(redis_conn, "some-token")
    assert released is False


@pytest.mark.asyncio
async def test_acquire_after_release_succeeds(redis_conn):
    """After releasing, a new acquire should succeed."""
    token1 = await acquire_merge_lock(redis_conn)
    assert token1 is not None
    released = await release_merge_lock(redis_conn, token1)
    assert released is True
    token2 = await acquire_merge_lock(redis_conn)
    assert token2 is not None
    assert token2 != token1


@pytest.mark.asyncio
async def test_acquire_raises_on_non_positive_ttl(redis_conn):
    """ttl_seconds <= 0 raises ValueError."""
    with pytest.raises(ValueError, match="ttl_seconds must be positive"):
        await acquire_merge_lock(redis_conn, ttl_seconds=0)
    with pytest.raises(ValueError, match="ttl_seconds must be positive"):
        await acquire_merge_lock(redis_conn, ttl_seconds=-5)


@pytest.mark.asyncio
async def test_release_raises_on_empty_token(redis_conn):
    """Empty token raises ValueError."""
    with pytest.raises(ValueError, match="token must not be empty"):
        await release_merge_lock(redis_conn, "")
