import pytest
import json
import sys
import os

# Add parent directory to path to import BatchedUpdate directly
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))


def ComplexHandler(Obj):
    """
    JSON serialization handler for complex objects.
    """
    if hasattr(Obj, 'jsonable'):
        return Obj.jsonable()
    elif isinstance(Obj, set):
        return list(Obj)
    elif hasattr(Obj, '__dict__'):
        return Obj.__dict__
    else:
        raise TypeError(f"Object of type {type(Obj).__name__} is not JSON serializable")


# Define BatchedUpdate locally for testing (avoids DB connection on import)
class BatchedUpdate:
    """
    Accumulator for batched game state updates.

    Instead of sending 14+ separate messages per tick,
    batch all updates into a single message.
    """

    def __init__(self):
        self._updates = {}

    def add(self, key: str, value: any) -> None:
        """Add an update to the batch"""
        self._updates[key] = value

    def to_dict(self) -> dict:
        """Convert to dictionary for sending"""
        if not self._updates:
            return None

        return {
            'type': 'batch_update',
            'updates': self._updates
        }

    def to_json(self) -> str:
        """Convert to JSON string"""
        data = self.to_dict()
        if data is None:
            return None
        return json.dumps(data, default=ComplexHandler)

    def is_empty(self) -> bool:
        """Check if batch is empty"""
        return len(self._updates) == 0


def test_batched_update_creation():
    """Test creating batched update object"""
    batch = BatchedUpdate()

    batch.add('energy', 100)
    batch.add('money', 5000)
    batch.add('hourOfDay', 10)

    result = batch.to_dict()
    assert result['type'] == 'batch_update'
    assert result['updates']['energy'] == 100
    assert result['updates']['money'] == 5000
    assert result['updates']['hourOfDay'] == 10

def test_batched_update_json_serialization():
    """Test that batched updates serialize correctly"""
    batch = BatchedUpdate()
    batch.add('test_field', 'test_value')

    json_str = batch.to_json()
    parsed = json.loads(json_str)

    assert parsed['type'] == 'batch_update'
    assert parsed['updates']['test_field'] == 'test_value'

def test_empty_batch():
    """Test that empty batches return None"""
    batch = BatchedUpdate()
    assert batch.to_dict() is None

def test_is_empty():
    """Test is_empty method"""
    batch = BatchedUpdate()
    assert batch.is_empty() == True

    batch.add('test', 'value')
    assert batch.is_empty() == False

def test_batch_multiple_updates():
    """Test batching multiple updates"""
    batch = BatchedUpdate()

    # Add all typical game state updates
    batch.add('date', '11-12')
    batch.add('hourOfDay', 14)
    batch.add('minuteOfHour', 0)
    batch.add('weekDayText', 'Tuesday')
    batch.add('energy', 75)
    batch.add('calcEnergy', 80)
    batch.add('money', 15000)
    batch.add('diamonds', 50)
    batch.add('prestige', 100)
    batch.add('stress', 30)
    batch.add('happiness', 85)
    batch.add('occupation', 'Student')
    batch.add('location', 'School')
    batch.add('schedules', [])
    batch.add('intraDayMessage', 'Studying hard')
    batch.add('dailyPlan', [])
    batch.add('gameSpeed', 50)

    result = batch.to_dict()
    assert result['type'] == 'batch_update'
    assert len(result['updates']) == 17
    assert result['updates']['energy'] == 75
    assert result['updates']['money'] == 15000
    assert result['updates']['hourOfDay'] == 14
