import pytest
from rwl.core import RWLSystem  # Assuming your core logic is here
from rwl.models import User, Resource, Lock  # Assuming you have models

@pytest.fixture
def rwl_system():
    """Fixture to provide a clean RWLSystem instance for each test."""
    return RWLSystem()

def test_user_creation(rwl_system):
    user = rwl_system.create_user("test_user")
    assert user.user_id is not None
    assert user.username == "test_user"

def test_resource_creation(rwl_system):
    resource = rwl_system.create_resource("test_resource")
    assert resource.resource_id is not None
    assert resource.name == "test_resource"

def test_read_lock_acquisition(rwl_system):
    user = rwl_system.create_user("test_user")
    resource = rwl_system.create_resource("test_resource")

    lock = rwl_system.acquire_read_lock(user.user_id, resource.resource_id)
    assert lock is not None
    assert lock.lock_type == "read"
    assert lock.user_id == user.user_id
    assert lock.resource_id == resource.resource_id
    assert resource.is_read_locked()

def test_write_lock_acquisition(rwl_system):
    user = rwl_system.create_user("test_user")
    resource = rwl_system.create_resource("test_resource")

    lock = rwl_system.acquire_write_lock(user.user_id, resource.resource_id)
    assert lock is not None
    assert lock.lock_type == "write"
    assert lock.user_id == user.user_id
    assert lock.resource_id == resource.resource_id
    assert resource.is_write_locked()

def test_multiple_read_locks(rwl_system):
    user1 = rwl_system.create_user("test_user1")
    user2 = rwl_system.create_user("test_user2")
    resource = rwl_system.create_resource("test_resource")

    lock1 = rwl_system.acquire_read_lock(user1.user_id, resource.resource_id)
    lock2 = rwl_system.acquire_read_lock(user2.user_id, resource.resource_id)

    assert lock1 is not None
    assert lock2 is not None
    assert resource.is_read_locked()
    assert not resource.is_write_locked()  # Ensure write lock is not acquired.

def test_write_lock_blocks_read_locks(rwl_system):
    user1 = rwl_system.create_user("test_user1")
    user2 = rwl_system.create_user("test_user2")
    resource = rwl_system.create_resource("test_resource")

    rwl_system.acquire_write_lock(user1.user_id, resource.resource_id)
    lock2 = rwl_system.acquire_read_lock(user2.user_id, resource.resource_id)

    assert lock2 is None # Read lock should fail

def test_read_lock_blocks_write_locks(rwl_system):
    user1 = rwl_system.create_user("test_user1")
    user2 = rwl_system.create_user("test_user2")
    resource = rwl_system.create_resource("test_resource")

    rwl_system.acquire_read_lock(user1.user_id, resource.resource_id)
    lock2 = rwl_system.acquire_write_lock(user2.user_id, resource.resource_id)

    assert lock2 is None  # Write lock should fail.

def test_releasing_read_lock(rwl_system):
    user = rwl_system.create_user("test_user")
    resource = rwl_system.create_resource("test_resource")
    lock = rwl_system.acquire_read_lock(user.user_id, resource.resource_id)

    rwl_system.release_lock(lock.lock_id)
    assert not resource.is_read_locked()
    assert not resource.is_write_locked()

def test_releasing_write_lock(rwl_system):
    user = rwl_system.create_user("test_user")
    resource = rwl_system.create_resource("test_resource")
    lock = rwl_system.acquire_write_lock(user.user_id, resource.resource_id)

    rwl_system.release_lock(lock.lock_id)
    assert not resource.is_read_locked()
    assert not resource.is_write_locked()

def test_release_nonexistent_lock(rwl_system):
    with pytest.raises(ValueError):  # Or whatever exception your system throws
        rwl_system.release_lock("nonexistent_lock_id")

def test_user_cannot_acquire_same_lock_twice(rwl_system):
    user = rwl_system.create_user("test_user")
    resource = rwl_system.create_resource("test_resource")

    rwl_system.acquire_read_lock(user.user_id, resource.resource_id)
    lock2 = rwl_system.acquire_read_lock(user.user_id, resource.resource_id)
    assert lock2 is None