<?php
if (!defined('ABSPATH')) exit;

function newssync_get_items( $atts ) {
    $source = $atts['source'] ?? 'rss';
    if ( $source === 'posts' ) {
        return newssync_get_items_from_posts( $atts );
    }
    return newssync_get_items_from_rss( $atts );
}

function newssync_get_items_from_rss( $atts ) {
    $raw_items = newssync_get_feed_items_raw( $atts );

    // Deduplicação
    $seen = [];
    $unique = [];
    foreach ( $raw_items as $item ) {
        if ( ! empty( $item['link'] ) && in_array( $item['link'], $seen ) ) continue;
        if ( ! empty( $item['link'] ) ) $seen[] = $item['link'];
        $unique[] = $item;
    }

    foreach ($unique as &$item) {
        newssync_normalize_timestamp($item); // Normaliza antes de sort
    }
    unset($item);

    // ORDENA PRIMEIRO por timestamp
    usort( $unique, function($a, $b) {
        return $b['timestamp'] - $a['timestamp']; // DESC por timestamp normalizado
    } );

    foreach ($unique as &$item) {
        newssync_normalize_timestamp($item); // Normaliza
    }
    unset($item);

    // ==== CATEGORY FILTER (if specified) ====
    if ( ! empty( $atts['category'] ) ) {
        $category_filter = sanitize_text_field( $atts['category'] );
        $unique = array_filter( $unique, function( $item ) use ( $category_filter ) {
            $item_category = $item['category'] ?? $item['source'] ?? '';
            return ( strcasecmp( $item_category, $category_filter ) === 0 );
        } );
        $unique = array_values( $unique ); // Re-index
    }

    // ==== PER-FEED LIMIT (default behavior) ====
    // Default behavior: use the configured per-feed cap
    $per_feed_limit = intval( newssync_get_max_per_feed( $atts ) );
    if ( $per_feed_limit <= 0 ) $per_feed_limit = 3; // defensive fallback

    $count = [];
    $final = [];
    foreach ( $unique as $item ) {
        $fid = $item['feed_id'] ?? '';
        if ( !isset($count[$fid]) ) $count[$fid] = 0;
        if ( $count[$fid] < $per_feed_limit ) {
            $final[] = $item;
            $count[$fid]++;
        }
    }

    // ==== Interpret user-provided overall limit (0 or missing => unlimited) ====
    $requested_limit = null;
    if ( array_key_exists( 'limit', $atts ) && is_numeric( $atts['limit'] ) ) {
        $tmp = intval( $atts['limit'] );
        // Treat 0 as "unlimited" (do not enforce)
        if ( $tmp > 0 ) {
            $requested_limit = $tmp;
        } else {
            $requested_limit = null;
        }
    }

    /**
     * Filter: newssync/items_overall_limit
     *
     * Extensions can return null to defer (disable) the overall limit at this
     * stage. Useful when a post-render filter (e.g. keyword_filter in PRO)
     * will apply the limit itself AFTER it finishes matching — ensuring the
     * keyword filter has access to the full candidate pool before cutting.
     *
     * @param int|null $requested_limit The resolved limit, or null for unlimited.
     * @param array    $atts            Shortcode attributes.
     */
    $requested_limit = apply_filters( 'newssync/items_overall_limit', $requested_limit, $atts );

    if ( $requested_limit !== null ) {
        $final = array_slice( $final, 0, $requested_limit );
    }

    // Aplica filtro final (normalmente usado para limitar carousel/hero)
    $final = apply_filters('newssync_final_items_before_render', $final, $atts);

    // Normalize field names for layout compatibility: raw feed items use 'img_url'
    // but all layout templates expect 'img'. Map here so both modes work identically.
    $use_placeholders = get_option( 'newssync_use_placeholders', '1' ) !== '0';
    foreach ( $final as &$item ) {
        if ( ! isset( $item['img'] ) ) {
            if ( ! empty( $item['img_url'] ) ) {
                $item['img'] = (string) $item['img_url'];
            } elseif ( $use_placeholders && function_exists( 'newssync_get_random_placeholder' ) ) {
                $item['img'] = newssync_get_random_placeholder();
            } else {
                $item['img'] = '';
            }
        }

        /**
         * Filter: newssync/live_item_img
         *
         * Allows extensions to override or enrich the image URL for a live RSS
         * item before it reaches the layout template. If the item has no image,
         * extensions may attempt an async og:image lookup and return a cached
         * result, or schedule a background fetch for the next page load.
         *
         * @param string $img  Current image URL (may be a placeholder or '').
         * @param array  $item Full item array (keys: link, title, img, img_url, …).
         */
        $item['img'] = (string) apply_filters( 'newssync/live_item_img', $item['img'], $item );
    }
    unset( $item );

    return $final;
}

function newssync_get_items_from_posts( $atts ) {
    // Determine requested limit and offset from $atts
    $requested_limit = null;
    if ( array_key_exists( 'limit', $atts ) && is_numeric( $atts['limit'] ) && intval( $atts['limit'] ) > 0 ) {
        $requested_limit = intval( $atts['limit'] );
    }

    $requested_offset = 0;
    if ( array_key_exists( 'offset', $atts ) && is_numeric( $atts['offset'] ) ) {
        $requested_offset = max( 0, intval( $atts['offset'] ) );
    }

    // Decide quantos posts pedir ao WP:
    // - se houver offset, pedimos offset + requested_limit (ou offset + 6 se limit não fornecido), para garantir margem para aplicar o offset depois
    // - se não houver offset mas houver limit, pedimos limit
    // - se nenhum, pedimos todos (-1)
    $fetch_count = -1; // -1 => all
    if ( $requested_offset > 0 ) {
        if ( $requested_limit !== null ) {
            $fetch_count = $requested_offset + $requested_limit;
        } else {
            // sem limit explícito, garantir pelo menos offset + 6 para layouts hero/carousel free
            $fetch_count = $requested_offset + 6;
        }
    } else {
        if ( $requested_limit !== null ) {
            $fetch_count = $requested_limit;
        } else {
            $fetch_count = -1;
        }
    }

    // Prefer indexed lookup via item-map table when available to avoid slow meta_query.
    $posts = [];
    $use_map = false;
    if ( function_exists( 'newssync_table_exists' ) && function_exists( 'newssync_find_post_id_by_guid' ) && newssync_table_exists() ) {
        $use_map = true;
        $map_get_name = 'newssync_get_item_map_table_name';
    } elseif ( function_exists( 'newssync_table_exists' ) && function_exists( 'newssync_find_post_id_by_guid' ) && newssync_table_exists() ) {
        $use_map = true;
        $map_get_name = 'newssync_get_item_map_table_name';
    }

    if ( $use_map ) {
        global $wpdb;
        if ( function_exists( $map_get_name ) ) {
            $map_table = call_user_func( $map_get_name );
            // Select recent mapped posts by joining posts to mapping table
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table names from safe functions
            $sql = $wpdb->prepare( "SELECT p.ID FROM {$wpdb->posts} p INNER JOIN {$map_table} m ON p.ID = m.post_id WHERE p.post_type = %s AND p.post_status = 'publish' ORDER BY p.post_date DESC LIMIT %d", 'post', $fetch_count );
            // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- JOIN query for custom table with safe table names, results used immediately to fetch posts
            $ids = $wpdb->get_col( $sql );
            if ( ! empty( $ids ) ) {
                $posts = get_posts([
                    'post_type' => 'post',
                    'posts_per_page' => $fetch_count,
                    'post__in' => $ids,
                    'orderby' => 'post__in',
                ]);
            }
        }
    }

    // Fallback: optimized query with JOIN when item-map table unavailable
    if ( empty( $posts ) ) {
        global $wpdb;

        $limit = $fetch_count > 0 ? $fetch_count : 999999;

        $sql = $wpdb->prepare(
            "SELECT DISTINCT p.ID
            FROM {$wpdb->posts} p
            INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
            WHERE p.post_type = %s
            AND p.post_status = 'publish'
            AND pm.meta_key = %s
            ORDER BY p.post_date DESC
            LIMIT %d",
            'post',
            '_newssync_original_url',
            $limit
        );

        // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Fallback query with JOIN for performance when item-map table unavailable, query is prepared above
        $ids = $wpdb->get_col( $sql );

        if ( ! empty( $ids ) ) {
            $posts = get_posts([
                'post_type'      => 'post',
                'posts_per_page' => $fetch_count,
                'post__in'       => $ids,
                'orderby'        => 'post__in',
            ]);
        }
    }

    $items = [];
    foreach ($posts as $p) {
        // Buscar metadados do post
        $source_name = get_post_meta($p->ID, '_newssync_source_name', true);
        $source_url = get_post_meta($p->ID, '_newssync_source_url', true);
        $author = get_post_meta($p->ID, '_newssync_author', true);
        $category = get_post_meta($p->ID, '_newssync_source', true) ?: 'Unknown';

        $items[] = [
            'title'       => $p->post_title,
            'link'        => get_permalink($p->ID),
            'date'        => date_i18n('d/m/Y H:i', strtotime($p->post_date)),
            'desc'        => wp_trim_words(wp_strip_all_tags($p->post_content), 25, '...'),
            'img'         => has_post_thumbnail($p->ID) ? wp_get_attachment_url(get_post_thumbnail_id($p->ID)) : ( get_option( 'newssync_use_placeholders', '1' ) !== '0' ? newssync_get_random_placeholder() : '' ),
            'category'    => $category,
            'feed_id'     => 'imported',
            // ✅ NOVO: Adicionar source_name, source_url e author
            'source_name' => $source_name ?: '',
            'source_url'  => $source_url ?: '',
            'author'      => $author ?: '',
        ];
    }

    // NOTE: não aplicamos array_slice pelo limit aqui — deixamos o shortcode aplicar offset+limit/slicing final.
    // Aplica limite contextual de 6 itens para Hero/Carousel (Free) via filtro
    $items = apply_filters('newssync_final_items_before_render', $items, $atts);

    return $items;
}

/**
 * Limita Hero e Carousel a apenas 6 itens por padrão
 * Extended builds may ignore this filter to allow larger displays
 */
add_filter('newssync_final_items_before_render', 'newssync_limit_hero_carousel_to_6', 10, 2);
function newssync_limit_hero_carousel_to_6($items, $atts) {
    // Apply cap for Hero/Carousel layouts (limit to 6 items by default)
    $layout = $atts['layout'] ?? '';
    if ( in_array( $layout, ['hero', 'carousel'], true ) ) {
        return array_slice($items, 0, 6);
    }
    return $items;
}
