<?php
/**
 * API - Obtener mensajes de un usuario específico
 * Fecha: 4 de enero de 2026
 */

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

// Verificar autenticación
requireAuthentication();

header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET');
header('Access-Control-Allow-Headers: Content-Type');

try {
    $userId = intval($_GET['user_id'] ?? 0);
    
    if (!$userId) {
        http_response_code(400);
        echo json_encode(['error' => 'user_id es requerido']);
        exit;
    }

    // Paginación: limit y before (timestamp) - cargamos N mensajes anteriores a 'before'
    $limit = isset($_GET['limit']) ? intval($_GET['limit']) : 50;
    $limit = max(1, min(200, $limit));
    $before = !empty($_GET['before']) ? $_GET['before'] : null; // expect timestamp string
    // We also support a 'since' parameter to fetch only messages strictly newer than a timestamp
    $since = !empty($_GET['since']) ? $_GET['since'] : null;

    // Validar formato de 'before' si se proporcionó (evitar SQL/parse errors por input malformado)
    if (!is_null($before)) {
        // Aceptar formato 'YYYY-MM-DD HH:MM:SS' (espacio entre fecha y hora)
        if (!preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $before)) {
            http_response_code(400);
            echo json_encode(['success' => false, 'error' => 'before timestamp inválido']);
            exit;
        }
    }

    // Validar 'since' si se pasó
    if (!is_null($since)) {
        if (!preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $since)) {
            http_response_code(400);
            echo json_encode(['success' => false, 'error' => 'since timestamp inválido']);
            exit;
        }
    }

    $db = Database::getInstance();

    // Construir consulta: by default paginamos hacia atrás (before) y ordenamos DESC
    // Pero cuando se solicita 'since' queremos sólo mensajes más nuevos => orden ASC (para retornar cronológicamente)
    $sql = "SELECT 
            c.id as id,
            c.user_id as user_id,
            c.content as content,
            c.message_id as message_id,
            c.media_url,
            c.local_file,
            c.filename,
            c.mime_type,
            u.phone_number as user_phone,
            c.direction as direction,
            c.message_type as message_type,
            c.status as status,
            c.created_at as created_at,
            COALESCE(c.is_read, 0) as is_read,
            c.reply_to_message_id as reply_to_message_id,
            c.reaction_emoji as reaction_emoji,
            c.reaction_to_message_id as reaction_to_message_id
         FROM conversations c
         LEFT JOIN users u ON c.user_id = u.id
         WHERE c.user_id = :user_id AND (c.canal IS NULL OR c.canal = 'bot')";

    // Soporte para paginación estable: before (timestamp) y before_id (id del mensaje más antiguo del bloque)
    $beforeId = isset($_GET['before_id']) ? intval($_GET['before_id']) : null;

    $params = ['user_id' => $userId];

    if (!is_null($since)) {
        // If 'since' is provided, return only messages strictly newer than 'since' ordered ascending
        $sql .= " AND c.created_at > :since";
        $params['since'] = $since;
        $sql .= " ORDER BY c.created_at ASC, c.id ASC LIMIT " . $limit;
    } else {
        if ($before) {
            $sql .= " AND (c.created_at < :before_lt";
            $params['before_lt'] = $before;
            if ($beforeId) {
                // Incluir mensajes con mismo timestamp pero id menor (paginación estable)
                // Usamos placeholder distinto para evitar duplicar el mismo nombre en la query
                $sql .= " OR (c.created_at = :before_eq AND c.id < :before_id)";
                $params['before_eq'] = $before;
                $params['before_id'] = $beforeId;
            }
            $sql .= ")";
        }

        $sql .= " ORDER BY c.created_at DESC, c.id DESC LIMIT " . $limit;
    }

    // Log params/consulta para diagnóstico si algo falla (no sensible)
    error_log('get_user_messages.php - params: ' . json_encode(['user_id' => $userId, 'limit' => $limit, 'before' => $before]));
    error_log('get_user_messages.php - executing SQL: ' . $sql . ' params: ' . json_encode($params));

    $conversations = $db->fetchAll($sql, $params);

    // Si no hay mensajes, intentar fallback si se pidió paginación con 'before'
    if (empty($conversations) && $before) {
        error_log('get_user_messages.php - initial query returned empty, attempting fallback with inclusive <= for before param');
        try {
            $sqlFallback = str_replace('c.created_at < :before', 'c.created_at <= :before', $sql);
            $conversationsFallback = $db->fetchAll($sqlFallback, $params);
            if (!empty($conversationsFallback)) {
                error_log('get_user_messages.php - fallback query returned ' . count($conversationsFallback) . ' rows');
                $conversations = $conversationsFallback;
            }
        } catch (Exception $e) {
            error_log('get_user_messages.php - fallback query failed: ' . $e->getMessage());
        }
    }

    // Si todavía no hay mensajes, devolver array vacío
    if (empty($conversations)) {
        echo json_encode(['success' => true, 'data' => [], 'has_more' => false], JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR);
        exit;
    }

    // Si se solicitó 'since' ya devolvimos en orden ASC (cronológico). Si no, revertimos
    $sinceProvided = !is_null($since);
    if (!$sinceProvided) {
        $conversations = array_reverse($conversations);
    }

    // Recalcular usando el resultado final para decidir paginación
    $finalCount = is_array($conversations) ? count($conversations) : 0;
    $hasMore = ($finalCount > 0 && $finalCount == $limit) ? true : false;

    // Si no hay mensajes en conversations, intentar con conversaciones (compatibilidad antigua)
    if (empty($conversations)) {
        $conversations = $db->fetchAll(
            "SELECT 
                id,
                user_id,
                message_text as content,
                direction,
                message_type,
                media_url,
                local_file,
                filename,
                mime_type,
                status,
                created_at
             FROM conversations
             WHERE user_id = :user_id AND (canal IS NULL OR canal = 'bot')
             ORDER BY created_at ASC",
            ['user_id' => $userId]
        );
    }
    
    // Formatear fechas y limpiar datos
    $conversations = array_map(function($msg) {
        $external = (isset($msg['media_url']) && $msg['media_url']) ? (preg_match('#^https?://#i', $msg['media_url']) ? $msg['media_url'] : ("api/get_media.php?id=" . urlencode($msg['media_url']))) : null;
        $contentStr = $msg['content'] ?? '';
        if (!$external && $contentStr) {
            $j = json_decode($contentStr, true);
            if (is_array($j)) {
                foreach (['image','document','audio','video'] as $k) {
                    if (isset($j[$k]) && is_array($j[$k])) {
                        if (!empty($j[$k]['link'])) { $external = $j[$k]['link']; break; }
                        if (!empty($j[$k]['url'])) { $external = $j[$k]['url']; break; }
                        if (!empty($j[$k]['id'])) { $external = "api/get_media.php?id=" . urlencode($j[$k]['id']); break; }
                    }
                }
                if (!$external && !empty($j['link'])) $external = $j['link'];
            }
        }

        return [
            'id' => intval($msg['id']),
            'user_id' => intval($msg['user_id']),
            'content' => $msg['content'] ?? '',
            'message_id' => $msg['message_id'] ?? null,
            'media_url' => null,
            'local_file' => $msg['local_file'] ?? null,
            'media_url_external' => $external,
            'filename' => $msg['filename'] ?? null,
            'mime_type' => $msg['mime_type'] ?? null,
            'user_phone' => $msg['user_phone'] ?? null,
            'direction' => $msg['direction'] ?? 'incoming',
            'message_type' => $msg['message_type'] ?? 'text',
            'status' => $msg['status'] ?? 'sent',
            'created_at' => $msg['created_at'],
            'reply_to_message_id' => $msg['reply_to_message_id'] ?? null,
            'reaction_emoji' => $msg['reaction_emoji'] ?? null,
            'reaction_to_message_id' => $msg['reaction_to_message_id'] ?? null
        ];
    }, $conversations);

    // earliest message timestamp (para paginación hacia atrás)
    $earliest = $conversations[0]['created_at'] ?? null;
    $earliestId = $conversations[0]['id'] ?? null;

    // Si usamos fallback y el earliest coincide o es >= al 'before' solicitado,
    // decrementamos 1 segundo para evitar que la próxima petición repita el mismo bloque
    $fallbackUsed = (isset($conversationsFallback) && !empty($conversationsFallback));
    if ($fallbackUsed && $earliest && $before) {
        $earliest_ts = strtotime($earliest);
        $before_ts = strtotime($before);
        if ($earliest_ts !== false && $before_ts !== false && $earliest_ts >= $before_ts) {
            // restar 1 segundo
            $earliest = date('Y-m-d H:i:s', $earliest_ts - 1);
            error_log('get_user_messages.php - adjusted earliest to avoid duplicate pagination: ' . $earliest);
        }
    }

    // Recalculate final_count for debug
    $finalCount = is_array($conversations) ? count($conversations) : 0;

    // Añadir debug information cuando se solicita (solo con ?debug=1)
    $debugInfo = null;
    if (!empty($_GET['debug']) && $_GET['debug'] == '1') {
        $debugInfo = [
            'original_sql' => substr($sql, 0, 2000),
            'params' => $params,
            'final_count' => $finalCount,
            'fallback_used' => $fallbackUsed,
            'fallback_count' => $fallbackUsed ? count($conversationsFallback) : 0
        ];
    }

    $out = ['success' => true, 'data' => $conversations, 'has_more' => $hasMore, 'earliest' => $earliest, 'earliest_id' => $earliestId];
    if ($debugInfo) $out['debug'] = $debugInfo;

    echo json_encode($out, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR);
    
} catch (Exception $e) {
    // Log detallado con stack trace para diagnóstico
    error_log("Error in get_user_messages.php: " . $e->getMessage() . "\n" . $e->getTraceAsString());
    http_response_code(500);

    // Responder con detalle sólo si se pasa ?debug=1 (NO activar en producción)
    if (!empty($_GET['debug']) && $_GET['debug'] == '1') {
        echo json_encode([
            'error' => 'Error interno del servidor',
            'details' => $e->getMessage(),
            'trace' => explode("\n", $e->getTraceAsString())
        ]);
    } else {
        echo json_encode(['error' => 'Error interno del servidor']);
    }
}
?>