<?php
/**
 * Server-Sent Events (SSE) - Push de eventos en tiempo real
 * Este endpoint mantiene una conexión abierta y envía eventos cuando ocurren cambios
 * Fecha: 27 de enero de 2026
 */

require_once '../config/config.php';

// Configurar headers para SSE primero (antes de cualquier output)
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('X-Accel-Buffering: no'); // Nginx

// Deshabilitar buffer de salida
if (ob_get_level()) ob_end_clean();
@ini_set('output_buffering', 'off');
@ini_set('zlib.output_compression', 'off');

// Función para enviar un evento SSE
function sendSSEEvent($event, $data, $id = null) {
    if ($id !== null) {
        echo "id: {$id}\n";
    }
    echo "event: {$event}\n";
    echo "data: " . json_encode($data) . "\n\n";
    
    if (ob_get_level()) ob_flush();
    flush();
}

// Función para leer eventos pendientes de un archivo temporal
function readPendingEvents($userId) {
    $eventsFile = __DIR__ . "/../uploads/events_{$userId}.json";
    
    if (!file_exists($eventsFile)) {
        return [];
    }
    
    $content = @file_get_contents($eventsFile);
    if (!$content) return [];
    
    $events = json_decode($content, true);
    if (!is_array($events)) return [];
    
    // Limpiar archivo después de leer
    @file_put_contents($eventsFile, json_encode([]));
    
    return $events;
}

try {
    // Verificar autenticación (sesión o token)
    $userId = null;
    $authenticated = false;
    
    // Opción 1: Sesión PHP
    if (isset($_SESSION['user']['id'])) {
        $userId = $_SESSION['user']['id'];
        $authenticated = true;
    }
    
    // Opción 2: Token en query string (para EventSource sin credenciales)
    $token = $_GET['token'] ?? null;
    if (!$authenticated && $token) {
        // Validar token simple (en producción usar JWT o token en BD)
        if ($token === 'demo_token' || strlen($token) > 10) {
            // Modo autenticado con token
            $userId = 'token_' . substr(md5($token), 0, 8);
            $authenticated = true;
        }
    }
    
    // Si aún no está autenticado, usar modo global
    if (!$authenticated) {
        // Modo global: recibir eventos broadcast a todos
        $userId = 'global';
        error_log('SSE: Conexión en modo global (sin autenticación específica)');
    }
    
    // IMPORTANTE: Enviar evento connected ANTES de hacer cualquier otra cosa
    error_log("SSE: Enviando evento connected (userId: {$userId})");
    sendSSEEvent('connected', [
        'timestamp' => time(),
        'user_id' => $userId,
        'mode' => $authenticated ? 'authenticated' : 'global',
        'status' => 'ready'
    ]);
    
    // Ahora sí, conectar a BD
    $db = Database::getInstance();
    
    // Obtener último timestamp conocido por el cliente
    $lastEventId = $_SERVER['HTTP_LAST_EVENT_ID'] ?? null;
    $lastCheck = time();
    $connectionStart = time();
    $maxConnectionTime = 1800; // 30 minutos máximo (aumentado para evitar desconexiones frecuentes)
    
    // Loop principal - revisar eventos cada 2 segundos
    while (true) {
        // Verificar tiempo máximo de conexión (evitar conexiones eternas)
        if (time() - $connectionStart > $maxConnectionTime) {
            error_log("SSE: Conexión alcanzó tiempo máximo ({$maxConnectionTime}s), cerrando...");
            sendSSEEvent('timeout', ['message' => 'Conexión reiniciándose', 'reconnect' => true]);
            break;
        }
        
        // Verificar si la conexión sigue activa
        if (connection_aborted()) {
            error_log("SSE: Cliente desconectado (userId: {$userId})");
            break;
        }
        
        // Leer eventos pendientes del archivo temporal
        $pendingEvents = readPendingEvents($userId);
        
        foreach ($pendingEvents as $event) {
            sendSSEEvent(
                $event['type'] ?? 'message',
                $event['data'] ?? [],
                $event['id'] ?? null
            );
        }
        
        // Revisar nuevos mensajes en BD cada 3 segundos
        if (time() - $lastCheck >= 3) {
            // Mantener track de mensajes ya enviados para evitar duplicados
            static $lastMessageId = 0;
            static $lastConversationCheck = null;
            
            if ($lastConversationCheck === null) {
                // Primera vez: obtener el ID más alto y timestamp actual de la BD, sin enviar nada
                $maxMsg = $db->fetch("SELECT MAX(id) as max_id FROM conversations");
                $lastMessageId = $maxMsg['max_id'] ?? 0;
                // Usar el timestamp de la BD para evitar problemas de zona horaria
                $dbTime = $db->fetch("SELECT NOW() as now");
                $lastConversationCheck = $dbTime['now'] ?? date('Y-m-d H:i:s');
            } else {
                // 1. Verificar mensajes NUEVOS (solo los que tienen ID mayor al último visto)
                $recentMessages = $db->fetchAll(
                    "SELECT c.*, u.phone_number, u.name as user_name
                     FROM conversations c
                     INNER JOIN users u ON c.user_id = u.id
                     WHERE c.id > ?
                     AND c.direction = 'incoming'
                     ORDER BY c.id ASC
                     LIMIT 10",
                    [$lastMessageId]
                );
            
                foreach ($recentMessages as $msg) {
                    sendSSEEvent('new_message', [
                        'message_id' => $msg['id'],
                        'user_id' => $msg['user_id'],
                        'phone_number' => $msg['phone_number'],
                        'user_name' => $msg['user_name'],
                        'content' => $msg['message_content'],
                        'message_type' => $msg['message_type'] ?? 'text',
                        'direction' => $msg['direction'],
                        'created_at' => $msg['created_at'],
                        'timestamp' => time()
                    ]);
                    // Actualizar último ID visto
                    if ($msg['id'] > $lastMessageId) {
                        $lastMessageId = $msg['id'];
                    }
                }
            
                // 2. Verificar si hay nuevas conversaciones desde la última revisión
                $recentConversations = $db->fetchAll(
                    "SELECT DISTINCT c.user_id, u.phone_number, u.name, 
                            MAX(c.created_at) as last_message_time,
                            COUNT(*) as message_count
                     FROM conversations c
                     INNER JOIN users u ON c.user_id = u.id
                     WHERE c.created_at > ?
                     GROUP BY c.user_id
                     ORDER BY last_message_time DESC
                     LIMIT 5",
                    [$lastConversationCheck]
                );
            
                foreach ($recentConversations as $conv) {
                    sendSSEEvent('new_conversation', [
                        'user_id' => $conv['user_id'],
                        'phone_number' => $conv['phone_number'],
                        'name' => $conv['name'],
                        'message_count' => $conv['message_count'],
                        'timestamp' => $conv['last_message_time']
                    ]);
                    // Actualizar timestamp
                    if ($conv['last_message_time'] > $lastConversationCheck) {
                        $lastConversationCheck = $conv['last_message_time'];
                    }
                }
            } // Fin del else (primera inicialización vs verificaciones posteriores)
            
            // Verificar notificaciones NUEVAS (solo las creadas desde la última verificación)
            // NO enviar notificaciones guardadas - solo las que llegan en tiempo real
            try {
                static $lastNotificationCheck = null;
                if ($lastNotificationCheck === null) {
                    // Primera vez: usar el timestamp de la BD, NO enviar nada
                    $dbTimeNotif = $db->fetch("SELECT NOW() as now");
                    $lastNotificationCheck = $dbTimeNotif['now'] ?? date('Y-m-d H:i:s');
                } else {
                    // Verificaciones posteriores: solo notificaciones NUEVAS
                    $notifications = $db->fetchAll(
                        "SELECT id, user_id, type, message, data, is_read, created_at 
                         FROM notifications 
                         WHERE created_at > ? 
                         ORDER BY created_at ASC 
                         LIMIT 10",
                        [$lastNotificationCheck]
                    );
                    
                    if ($notifications && count($notifications) > 0) {
                        foreach ($notifications as $notification) {
                            sendSSEEvent('notification', $notification);
                            // Actualizar timestamp para evitar duplicados
                            if ($notification['created_at'] > $lastNotificationCheck) {
                                $lastNotificationCheck = $notification['created_at'];
                            }
                        }
                    }
                }
            } catch (Exception $e) {
                error_log('SSE: Error leyendo notificaciones: ' . $e->getMessage());
            }
            
            $lastCheck = time();
        }
        
        // Enviar heartbeat cada 30 segundos para mantener conexión viva
        if (time() % 30 === 0) {
            sendSSEEvent('heartbeat', ['timestamp' => time()]);
        }
        
        // Esperar 2 segundos antes de la siguiente verificación
        sleep(2);
    }
    
} catch (Exception $e) {
    error_log("SSE Error: " . $e->getMessage());
    error_log("SSE Error trace: " . $e->getTraceAsString());
    sendSSEEvent('error', [
        'message' => $e->getMessage(),
        'code' => $e->getCode()
    ]);
}
