import logging

# Initialize logger
logger = logging.getLogger(__name__)

# Make this a module variable to be set by the Flask app on initialization
socketio = None
# Socket subscription tracking
socket_subscriptions = {}


def set_socketio(socket_instance):
    """Set the Socket.IO instance for the service."""
    global socketio
    socketio = socket_instance
    logger.info("Socket.IO instance attached to socket service")


def emit_socket_event(event, data, room=None):
    """
    Emit a socket event to clients.

    Args:
        event: The event name to emit
        data: The data to send with the event
        room: Optional room ID to send to specific client

    Returns:
        bool: True if emission was successful, False otherwise
    """
    global socketio

    if not socketio:
        logger.error("Socket.IO not initialized when attempting to emit event")
        return False

    try:
        # If room is specified, only emit to that room
        if room:
            socketio.emit(event, data, room=room)
        else:
            # Otherwise broadcast to all
            socketio.emit(event, data)
        return True
    except Exception as e:
        logger.error(f"Error emitting socket event {event}: {str(e)}")
        return False


def emit_to_subscribers(event_base, research_id, data):
    """
    Emit an event to all subscribers of a specific research.

    Args:
        event_base: Base event name (will be formatted with research_id)
        research_id: ID of the research
        data: The data to send with the event

    Returns:
        bool: True if emission was successful, False otherwise
    """
    global socketio

    if not socketio:
        logger.error("Socket.IO not initialized when attempting to emit to subscribers")
        return False

    try:
        # Emit to the general channel for the research
        full_event = f"{event_base}_{research_id}"
        socketio.emit(full_event, data)

        # Emit to specific subscribers
        if research_id in socket_subscriptions and socket_subscriptions[research_id]:
            for sid in socket_subscriptions[research_id]:
                try:
                    socketio.emit(full_event, data, room=sid)
                except Exception as sub_err:
                    logger.error(f"Error emitting to subscriber {sid}: {str(sub_err)}")

        return True
    except Exception as e:
        logger.error(
            f"Error emitting to subscribers for research {research_id}: {str(e)}"
        )
        return False


# Socket event handlers moved from app.py
def handle_connect(request):
    """Handle client connection"""
    logger.info(f"Client connected: {request.sid}")


def handle_disconnect(request):
    """Handle client disconnection"""
    try:
        logger.info(f"Client disconnected: {request.sid}")
        # Clean up subscriptions for this client
        global socket_subscriptions
        for research_id, subscribers in list(socket_subscriptions.items()):
            if request.sid in subscribers:
                subscribers.remove(request.sid)
            if not subscribers:
                socket_subscriptions.pop(research_id, None)
                logger.info(f"Removed empty subscription for research {research_id}")
    except Exception as e:
        logger.error(f"Error handling disconnect: {e}")


def handle_subscribe(data, request, active_research=None):
    """Handle client subscription to research updates"""
    from datetime import datetime

    from ..models.database import get_db_connection

    research_id = data.get("research_id")
    if research_id:
        # First check if this research is still active
        conn = get_db_connection()
        cursor = conn.cursor()
        cursor.execute(
            "SELECT status FROM research_history WHERE id = ?", (research_id,)
        )
        result = cursor.fetchone()
        conn.close()

        # Only allow subscription to valid research
        if result:
            status = result[0]

            # Initialize subscription set if needed
            global socket_subscriptions
            if research_id not in socket_subscriptions:
                socket_subscriptions[research_id] = set()

            # Add this client to the subscribers
            socket_subscriptions[research_id].add(request.sid)
            logger.info(f"Client {request.sid} subscribed to research {research_id}")

            # Send current status immediately if available
            if active_research and research_id in active_research:
                progress = active_research[research_id]["progress"]
                latest_log = (
                    active_research[research_id]["log"][-1]
                    if active_research[research_id]["log"]
                    else None
                )

                if latest_log:
                    emit_socket_event(
                        f"research_progress_{research_id}",
                        {
                            "progress": progress,
                            "message": latest_log.get("message", "Processing..."),
                            "status": "in_progress",
                            "log_entry": latest_log,
                        },
                        room=request.sid,
                    )
            elif status in ["completed", "failed", "suspended"]:
                # Send final status for completed research
                emit_socket_event(
                    f"research_progress_{research_id}",
                    {
                        "progress": 100 if status == "completed" else 0,
                        "message": (
                            "Research completed successfully"
                            if status == "completed"
                            else (
                                "Research failed"
                                if status == "failed"
                                else "Research was suspended"
                            )
                        ),
                        "status": status,
                        "log_entry": {
                            "time": datetime.utcnow().isoformat(),
                            "message": f"Research is {status}",
                            "progress": 100 if status == "completed" else 0,
                            "metadata": {
                                "phase": (
                                    "complete" if status == "completed" else "error"
                                )
                            },
                        },
                    },
                    room=request.sid,
                )
        else:
            # Research not found
            emit_socket_event(
                "error",
                {"message": f"Research ID {research_id} not found"},
                room=request.sid,
            )


def handle_socket_error(e):
    """Handle Socket.IO errors"""
    logger.error(f"Socket.IO error: {str(e)}")
    # Don't propagate exceptions to avoid crashing the server
    return False


def handle_default_error(e):
    """Handle unhandled Socket.IO errors"""
    logger.error(f"Unhandled Socket.IO error: {str(e)}")
    # Don't propagate exceptions to avoid crashing the server
    return False
