import pytest
import time
import sys
from unittest.mock import MagicMock, patch

# Mock the database connection before importing app
sys.modules['mysql'] = MagicMock()
sys.modules['mysql.connector'] = MagicMock()

# Mock the database connection in functions module
mock_db = MagicMock()
mock_cursor = MagicMock()
mock_db.cursor.return_value = mock_cursor

with patch('functions.connect_to_database', return_value=mock_db):
    from app import UserRegistry

def test_user_registry_add_remove():
    """Test adding and removing users"""
    registry = UserRegistry()

    # Mock websocket
    class MockWebSocket:
        def __init__(self, user_id):
            self.userID = user_id

    ws1 = MockWebSocket("user1")
    ws2 = MockWebSocket("user2")

    registry.add(ws1)
    registry.add(ws2)

    assert registry.get("user1") == ws1
    assert registry.get("user2") == ws2
    assert registry.count() == 2

    registry.remove(ws1)
    assert registry.get("user1") is None
    assert registry.count() == 1

def test_user_registry_performance():
    """Test O(1) lookup performance with many users"""
    registry = UserRegistry()

    # Mock websockets
    class MockWebSocket:
        def __init__(self, user_id):
            self.userID = user_id

    # Add 1000 users
    users = [MockWebSocket(f"user_{i}") for i in range(1000)]
    for user in users:
        registry.add(user)

    # Lookup should be O(1) - test 1000 lookups
    start = time.time()
    for i in range(1000):
        result = registry.get(f"user_{i}")
        assert result is not None
    elapsed = time.time() - start

    # Should be < 10ms for 1000 lookups (O(1))
    assert elapsed < 0.01, f"Lookups too slow: {elapsed}s"

    # Compare with O(n) performance
    # If it was O(n), 1000 lookups on 1000 users = 1M iterations
    # O(1) should be ~1000x faster

def test_compare_old_vs_new():
    """Compare O(n) vs O(1) performance"""
    import time

    # O(n) approach (old)
    users_set = set()
    class MockWS:
        def __init__(self, uid):
            self.userID = uid

    # Add 1000 users (more users = clearer O(n) vs O(1) difference)
    for i in range(1000):
        users_set.add(MockWS(f"user_{i}"))

    # O(n) lookup - iterate through set (repeat 100 times for reliable timing)
    start = time.time()
    for _ in range(100):
        target_id = "user_500"  # Target in middle for average case
        found = None
        for user in users_set:
            if user.userID == target_id:
                found = user
                break
    old_time = time.time() - start

    # O(1) approach (new)
    registry = UserRegistry()
    for i in range(1000):
        registry.add(MockWS(f"user_{i}"))

    start = time.time()
    for _ in range(100):
        found = registry.get("user_500")
    new_time = time.time() - start

    print(f"\nO(n) time (100 lookups): {old_time*1000:.3f}ms")
    print(f"O(1) time (100 lookups): {new_time*1000:.3f}ms")
    print(f"Speedup: {old_time/new_time:.1f}x")

    # O(1) should be at least 10x faster
    assert new_time < old_time / 10
