from flask_socketio import emit
from extensions import socketio, db
from models import Event, Inventory
from flask import request
import json
from dateutil import parser
from datetime import datetime

@socketio.on('connect')
def handle_connect():
    print('Client connected')
    emit('clear_events')
    
    # Send history
    try:
        recent_events = Event.query.order_by(Event.timestamp.desc()).limit(30).all()
        print(f"Sending history: {len(recent_events)} events")
        for event in reversed(recent_events):
            emit('game_event', event.to_dict())
    except Exception as e:
        print(f"Error sending history: {e}")

@socketio.on('disconnect')
def handle_disconnect():
    print('Client disconnected')

@socketio.on('game_event')
def handle_game_event(data):
    # data = {type: 'CHAT', player: 'Name', content: 'Message', ...}
    print(f"Received event: {data}")
    
    # Save to DB
    try:
        if not data.get('type'):
            print(f"Error: Missing event type in {data}")
            return

        event_timestamp = None
        if data.get('timestamp'):
            try:
                event_timestamp = parser.parse(data.get('timestamp'))
            except Exception as e:
                print(f"Error parsing timestamp: {e}")
                event_timestamp = datetime.utcnow()

        event = Event(
            event_type=data.get('type'),
            player_uuid=data.get('uuid'),
            player_name=data.get('player'),
            content=data.get('content'),
            location=data.get('location'),
            timestamp=event_timestamp or datetime.utcnow()
        )
        db.session.add(event)
        db.session.commit()
        print(f"Event saved to DB: {event.id}")

        # If inventory data is present, save it
        if 'inventory' in data:
            inventory = Inventory(
                event_id=event.id,
                player_uuid=data.get('uuid'),
                items=json.dumps(data.get('inventory'))
            )
            db.session.add(inventory)
            db.session.commit()
            print(f"Inventory saved for event {event.id}")
            
    except Exception as e:
        print(f"Error saving event to DB: {str(e)}")
        db.session.rollback()

    # Broadcast to admin dashboard
    print(f"Broadcasting event: {data}")
    emit('game_event', data, broadcast=True)

@socketio.on('universal_event')
def handle_universal_event(data):
    # data = {type: 'EventName', package: 'pkg', timestamp: '...', event_data: {...}, player: 'Name'}
    print(f"Received universal event: {data.get('type')}")
    
    # Save to DB
    try:
        event_timestamp = None
        if data.get('timestamp'):
            try:
                event_timestamp = parser.parse(data.get('timestamp'))
            except Exception as e:
                even_timestamp = datetime.utcnow()

        # Flatten event_data to string for content if no content provided
        content = data.get('content')
        if not content and 'event_data' in data:
            content = json.dumps(data.get('event_data'))

        # Map to existing schema
        event = Event(
            event_type=data.get('type'),
            player_uuid=data.get('uuid'), # Might be missing in generic events
            player_name=data.get('player'),
            content=content, 
            location=data.get('event_data', {}).get('location'), # Try to find location
            timestamp=event_timestamp or datetime.utcnow()
        )
        db.session.add(event)
        db.session.commit()
    except Exception as e:
        print(f"Error saving universal event: {e}")
        db.session.rollback()

    emit('universal_event', data, broadcast=True)

DEFAULT_IGNORED_EVENTS = {
    "org.bukkit.event.player.PlayerMoveEvent",
    "org.bukkit.event.player.PlayerInputEvent",
    "org.bukkit.event.player.PlayerStatisticIncrementEvent",
    "org.bukkit.event.player.PlayerVelocityEvent",
    "org.bukkit.event.vehicle.VehicleMoveEvent",
    "org.bukkit.event.block.BlockPhysicsEvent",
    "org.bukkit.event.world.ChunkLoadEvent",
    "org.bukkit.event.world.ChunkUnloadEvent",
    "com.destroystokyo.paper.event.server.ServerTickEndEvent",
    "com.destroystokyo.paper.event.server.ServerTickStartEvent",
    "org.bukkit.event.vehicle.VehicleUpdateEvent",
    "org.bukkit.event.entity.EntityAirChangeEvent",
    "org.bukkit.event.entity.CreatureSpawnEvent",
    "org.bukkit.event.world.GenericGameEvent",
    "org.bukkit.event.world.EntitiesLoadEvent",
    "org.bukkit.event.world.EntitiesUnloadEvent",
    "org.bukkit.event.entity.BatToggleSleepEvent",
    "org.bukkit.event.entity.EntityPoseChangeEvent",
    "org.bukkit.event.entity.EntityRemoveEvent"
}

@socketio.on('event_metadata')
def handle_event_metadata(data):
    from models import EventConfig
    print(f"Received event metadata: {len(data.get('events', []))} events registered")
    
    # Sync with DB
    received_events = data.get('events', [])
    try:
        # Get existing configs
        existing = {c.event_name: c for c in EventConfig.query.all()}
        
        for event_name in received_events:
            if event_name not in existing:
                # Add new event
                package_name = event_name.rsplit('.', 1)[0]
                is_enabled = event_name not in DEFAULT_IGNORED_EVENTS
                new_config = EventConfig(event_name=event_name, package_name=package_name, is_enabled=is_enabled)
                db.session.add(new_config)
            
        db.session.commit()
        
        # Send back configuration
        send_config_update()
        
    except Exception as e:
        print(f"Error syncing event config: {e}")
        db.session.rollback()

    emit('event_metadata', data, broadcast=True)

def send_config_update():
    from models import EventConfig
    try:
        enabled_events = [c.event_name for c in EventConfig.query.filter_by(is_enabled=True).all()]
        print(f"Sending config update: {len(enabled_events)} enabled events")
        emit('config_update', {'enabled_events': enabled_events}, broadcast=True)
    except Exception as e:
        print(f"Error sending configs: {e}")

@socketio.on("*")
def handle_any_event(event, methods=None, data=None):
    if event not in ['connect', 'disconnect', 'game_event', 'universal_event', 'event_metadata']:
        print(f"Server received event: {event} with data: {data}")
