function publicaciones($args = [], $is_ajax = false, $paged = 1)
{
    $user_id = obtenerUserId($is_ajax);
    $current_user_id = get_current_user_id();

    $defaults = [
        'filtro' => '',
        'tab_id' => '',
        'posts' => 12,
        'exclude' => [],
        'post_type' => 'social_post',
        'similar_to' => null,
    ];
    $args = array_merge($defaults, $args);
    $query_args = configuracionQueryArgs($args, $paged, $user_id, $current_user_id);
    $output = procesarPublicaciones($query_args, $args, $is_ajax);

    if ($is_ajax) {
        echo $output;
        die();
    } else {
        return $output;
    }
}

function configuracionQueryArgs($args, $paged, $user_id, $current_user_id)
{
    global $FALLBACK_USER_ID;
    if (!isset($FALLBACK_USER_ID)) {
        $FALLBACK_USER_ID = 44;
    }

    $is_authenticated = $current_user_id && $current_user_id != 0;
    $is_admin = current_user_can('administrator');
    if (!$is_authenticated) {
        $current_user_id = $FALLBACK_USER_ID;
    }

    $identifier = $_POST['identifier'] ?? '';
    $posts = $args['posts'];
    $similar_to = $args['similar_to'] ?? null;
    $filtroTiempo = (int)get_user_meta($current_user_id, 'filtroTiempo', true);

    $query_args = construirQueryArgs($args, $paged, $current_user_id, $identifier, $is_admin, $posts, $filtroTiempo, $similar_to);
    $query_args = aplicarFiltrosUsuario($query_args, $current_user_id);
    $query_args = aplicarFiltroGlobal($query_args, $args, $current_user_id);
    return $query_args;
}

function construirQueryArgs($args, $paged, $current_user_id, $identifier, $is_admin, $posts, $filtroTiempo, $similar_to)
{
    global $wpdb;
    $query_args = [
        'post_type' => $args['post_type'],
        'posts_per_page' => $posts,
        'paged' => $paged,
        'ignore_sticky_posts' => true,
        'suppress_filters' => false,
    ];
    if (!empty($identifier)) {
        $query_args = filtrarIdentifier($identifier, $query_args);
    }
    if ($args['post_type'] === 'social_post') {
        $query_args = ordenamientoQuery($query_args, $filtroTiempo, $current_user_id, $identifier, $similar_to, $paged, $is_admin, $posts);
    }
    return $query_args;
}

function obtenerDatosFeed($userId)
{
    global $wpdb;
    $table_likes = "{$wpdb->prefix}post_likes";
    $table_intereses = INTERES_TABLE;
    $siguiendo = (array) get_user_meta($userId, 'siguiendo', true);
    $interesesUsuario = $wpdb->get_results($wpdb->prepare(
        "SELECT interest, intensity FROM $table_intereses WHERE user_id = %d",
        $userId
    ), OBJECT_K);
    $vistas_posts = get_user_meta($userId, 'vistas_posts', true);
    
    chatgpt: esto aqui calcula muchos post para saber como ordenarlos eficientemente
    $args = [
        'post_type'      => 'social_post',
        'posts_per_page' => 50000,
        'date_query'     => [
            'after' => date('Y-m-d', strtotime('-100 days'))
        ],
        'fields'         => 'ids',
        'no_found_rows'  => true,
    ];
    $posts_ids = get_posts($args);

    if (empty($posts_ids)) {
        return [];
    }
    $placeholders = implode(', ', array_fill(0, count($posts_ids), '%d'));
    $meta_keys = ['datosAlgoritmo', 'Verificado', 'postAut'];
    $meta_keys_placeholders = implode(',', array_fill(0, count($meta_keys), '%s'));
    $sql_meta = "
        SELECT post_id, meta_key, meta_value
        FROM {$wpdb->postmeta}
        WHERE meta_key IN ($meta_keys_placeholders) AND post_id IN ($placeholders)
    ";

    $prepared_sql_meta = $wpdb->prepare($sql_meta, array_merge($meta_keys, $posts_ids));

    $meta_results = $wpdb->get_results($prepared_sql_meta);
    $meta_data = [];
    foreach ($meta_results as $meta_row) {
        $meta_data[$meta_row->post_id][$meta_row->meta_key] = $meta_row->meta_value;
    }
    $sql_likes = "
        SELECT post_id, COUNT(*) as likes_count
        FROM $table_likes
        WHERE post_id IN ($placeholders)
        GROUP BY post_id
    ";

    $likes_results = $wpdb->get_results($wpdb->prepare($sql_likes, $posts_ids));
    $likes_by_post = [];
    foreach ($likes_results as $like_row) {
        $likes_by_post[$like_row->post_id] = $like_row->likes_count;
    }
    $sql_posts = "
        SELECT ID, post_author, post_date, post_content
        FROM {$wpdb->posts}
        WHERE ID IN ($placeholders)
    ";
    $posts_results = $wpdb->get_results($wpdb->prepare($sql_posts, $posts_ids), OBJECT_K);
    $post_content = [];
    foreach ($posts_results as $post) {
        $post_content[$post->ID] = $post->post_content;
    }

    return [
        'siguiendo'        => $siguiendo,
        'interesesUsuario' => $interesesUsuario,
        'posts_ids'        => $posts_ids,
        'likes_by_post'    => $likes_by_post,
        'meta_data'        => $meta_data,
        'author_results'   => $posts_results,
        'post_content'     => $post_content,
    ];
}


function ordenamientoQuery($query_args, $filtroTiempo, $current_user_id, $identifier, $similar_to, $paged, $is_admin, $posts)
{
    global $wpdb;
    $likes_table = $wpdb->prefix . 'post_likes';

    // Asegúrate de que query_args sea un array
    if (!is_array($query_args)) {
        $query_args = array();
    }

    switch ($filtroTiempo) {
        case 1:
            $query_args['orderby'] = 'date';
            $query_args['order'] = 'DESC';
            break;

        case 2: // Top semanal
        case 3: // Top mensual
            $interval = ($filtroTiempo === 2) ? '1 WEEK' : '1 MONTH';

            $sql = "
                SELECT p.ID, 
                       COUNT(pl.post_id) as like_count 
                FROM {$wpdb->posts} p 
                LEFT JOIN {$likes_table} pl ON p.ID = pl.post_id 
                WHERE p.post_type = 'social_post' 
                AND p.post_status = 'publish'
                AND p.post_date >= DATE_SUB(NOW(), INTERVAL $interval)  
                AND pl.like_date >= DATE_SUB(NOW(), INTERVAL $interval) 
                GROUP BY p.ID
                HAVING like_count > 0
                ORDER BY like_count DESC, p.post_date DESC
            ";

            $posts_with_likes = $wpdb->get_results($sql, ARRAY_A);

            if (!empty($posts_with_likes)) {
                $post_ids = wp_list_pluck($posts_with_likes, 'ID');
                if (!empty($post_ids)) {
                    $query_args['post__in'] = $post_ids;
                    $query_args['orderby'] = 'post__in';
                }
            } else {
                $query_args['orderby'] = 'date';
                $query_args['order'] = 'DESC';
            }
            break;

        default: // Feed personalizado
            $feed_result = obtenerFeedPersonalizado($current_user_id, $identifier, $similar_to, $paged, $is_admin, $posts);

            if (!empty($feed_result['post_ids'])) {
                $query_args['post__in'] = $feed_result['post_ids'];
                $query_args['orderby'] = 'post__in';

                if (!empty($feed_result['post_not_in'])) {
                    $query_args['post__not_in'] = $feed_result['post_not_in'];
                }
            } else {
                $query_args['orderby'] = 'date';
                $query_args['order'] = 'DESC';
            }
            break;
    }

    // Asegúrate de que siempre haya un orderby por defecto
    if (empty($query_args['orderby'])) {
        $query_args['orderby'] = 'date';
        $query_args['order'] = 'DESC';
    }

    return $query_args;
}


function obtenerFeedPersonalizado($current_user_id, $identifier, $similar_to, $paged, $is_admin, $posts_per_page)
{
    $post_not_in = [];

    if ($similar_to) {
        $post_not_in[] = $similar_to;
        $cache_suffix = "_similar_" . $similar_to;
        
        // Usar cache global para similar_to
        $similar_to_cache_key = "similar_to_{$similar_to}";
        $cached_data = get_transient($similar_to_cache_key);

        if ($cached_data) {
            $posts_personalizados = $cached_data;
        } else {
            // Si no está cacheado, calcular y cachear
            $posts_personalizados = calcularFeedPersonalizado($current_user_id, $identifier, $similar_to);
            set_transient($similar_to_cache_key, $posts_personalizados, 15 * DAY_IN_SECONDS);
        }
    } else {
        $cache_suffix = "";
    }

    $transient_key = $current_user_id == 44
        ? "feed_personalizado_anonymous_{$identifier}{$cache_suffix}"
        : "feed_personalizado_user_{$current_user_id}_{$identifier}{$cache_suffix}";

    $cache_time = $is_admin ? 7200 : 43200;  
    $cached_data = get_transient($transient_key);

    if ($cached_data) {
        $posts_personalizados = $cached_data['posts'];
    } else {
        if ($paged === 1) {
            $posts_personalizados = calcularFeedPersonalizado($current_user_id, $identifier, $similar_to);
        } else {
            $posts_personalizados = get_option($transient_key . '_backup', []);
            if (empty($posts_personalizados)) {
                $posts_personalizados = calcularFeedPersonalizado($current_user_id, $identifier, $similar_to);
            }

            $cache_data = ['posts' => $posts_personalizados, 'timestamp' => time()];
            set_transient($transient_key, $cache_data, $cache_time);
            update_option($transient_key . '_backup', $posts_personalizados);
        }
    }

    $post_ids = array_keys($posts_personalizados);
    if ($similar_to) {
        $post_ids = array_filter($post_ids, function ($post_id) use ($similar_to) {
            return $post_id != $similar_to;
        });
    }

    return [
        'post_ids' => $post_ids,
        'post_not_in' => $post_not_in,
    ];
}


function calcularFeedPersonalizado($userId, $identifier = '', $similar_to = null)
{
    $datos = obtenerDatosFeedConCache($userId); 
    if (empty($datos)) {
        return [];
    }
    $usuario = get_userdata($userId);
    if (!$usuario || !is_object($usuario)) {
        return [];
    }
    $posts_personalizados = [];
    $current_timestamp = current_time('timestamp');
    $vistas_posts_processed = obtenerYProcesarVistasPosts($userId);
    $esAdmin = in_array('administrator', (array)$usuario->roles);
    $decay_factors = [];
    foreach ($datos['author_results'] as $post_data) {
        $post_date = $post_data->post_date;
        $post_timestamp = is_string($post_date) ? strtotime($post_date) : $post_date;
        $diasDesdePublicacion = floor(($current_timestamp - $post_timestamp) / (3600 * 24));
        if (!isset($decay_factors[$diasDesdePublicacion])) {
            $decay_factors[$diasDesdePublicacion] = getDecayFactor($diasDesdePublicacion);
        }
    }
    $posts_data = $datos['author_results'];
    $puntos_por_post = calcularPuntosPostBatch(
        $posts_data,
        $datos,
        $esAdmin,
        $vistas_posts_processed,
        $identifier,
        $similar_to,
        $current_timestamp,
        $userId,
        $decay_factors
    );

    if (!empty($puntos_por_post)) {
        arsort($puntos_por_post);
    }
    return $puntos_por_post;
}

pero aca al final solo necesito los 2.500 primeros en todos los casos, como sería 
function procesarPublicaciones($query_args, $args, $is_ajax)
{
    ob_start();
    $user_id = get_current_user_id();
    $cache_key = 'posts_count_' . md5(serialize($query_args)) . '_user_' . $user_id;
    $posts_count = 0;

    // Verificar que query_args no esté vacío
    if (empty($query_args)) {
        error_log('Query args está vacío en procesarPublicaciones');
        return '';
    }

    // Asegurarse de que query_args sea un array
    if (!is_array($query_args)) {
        error_log('Query args no es un array en procesarPublicaciones');
        return '';
    }

    $total_posts = get_transient($cache_key);
    if ($total_posts === false) {
        $query_args['no_found_rows'] = false;

        // Crear la consulta con manejo de errores
        try {
            $query = new WP_Query($query_args);

            // Verificar si la consulta es válida
            if (!is_a($query, 'WP_Query')) {
                error_log('Error al crear WP_Query');
                return '';
            }

            $total_posts = $query->found_posts;
            set_transient($cache_key, $total_posts, 12 * HOUR_IN_SECONDS);
        } catch (Exception $e) {
            error_log('Error en WP_Query: ' . $e->getMessage());
            return '';
        }
    } else {
        // Si usamos el caché, aún necesitamos crear la consulta
        $query = new WP_Query($query_args);
    }

    // Verificar que $query sea válido antes de continuar
    if (!is_object($query) || !method_exists($query, 'have_posts')) {
        error_log('Query inválido en procesarPublicaciones');
        return '';
    }

    echo '<input type="hidden" class="total-posts total-posts-' . esc_attr($args['filtro']) . '" value="' . esc_attr($total_posts) . '" />';

    if ($query->have_posts()) {
        $filtro = !empty($args['filtro']) ? $args['filtro'] : $args['filtro'];
        $tipoPost = $args['post_type'];

        if (!wp_doing_ajax()) {
            $clase_extra = 'clase-' . esc_attr($filtro);
            if (in_array($filtro, ['rolasEliminadas', 'rolasRechazadas', 'rola', 'likes'])) {
                $clase_extra = 'clase-rolastatus';
            }

            echo '<ul class="social-post-list ' . esc_attr($clase_extra) . '" 
                  data-filtro="' . esc_attr($filtro) . '" 
                  data-posttype="' . esc_attr($tipoPost) . '" 
                  data-tab-id="' . esc_attr($args['tab_id']) . '">';
        }

        while ($query->have_posts()) {
            $query->the_post();
            $posts_count++;

            if ($tipoPost === 'social_post') {
                echo htmlPost($filtro);
            } elseif ($tipoPost === 'colab') {
                echo htmlColab($filtro);
            } else {
                echo '<p>Tipo de publicación no reconocido.</p>';
            }
        }

        if (!wp_doing_ajax()) {
            echo '</ul>';
        }
    } else {
        echo nohayPost($filtro, $is_ajax);
    }
    wp_reset_postdata();
    return ob_get_clean();
}