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

/**
 * Shortcode: [newssync]
 */

$newssync_swiper_file = __DIR__ . '/newssync-swiper.php';
if ( file_exists( $newssync_swiper_file ) ) {
    require_once $newssync_swiper_file;
}

// Define plugin path/url constants if not already defined.
if ( ! defined( 'NEWSSYNC_PLUGIN_PATH' ) ) {
    define( 'NEWSSYNC_PLUGIN_PATH', plugin_dir_path( __DIR__ . '/../../rss-newssync.php' ) );
}
if ( ! defined( 'NEWSSYNC_PLUGIN_URL' ) ) {
    define( 'NEWSSYNC_PLUGIN_URL', plugin_dir_url( __DIR__ . '/../../rss-newssync.php' ) );
}
if ( ! defined( 'NEWSSYNC_PLUGIN_DIR' ) ) {
    define( 'NEWSSYNC_PLUGIN_DIR', NEWSSYNC_PLUGIN_PATH );
}

add_shortcode('newssync', 'newssync_render_shortcode');

function newssync_render_shortcode($atts) {
    // Keep raw attrs to detect which were provided explicitly by the user
    $raw_atts = is_array($atts) ? $atts : [];

    // Defaults
    $atts = shortcode_atts([
        'layout'           => newssync_get_option('newssync_default_layout', 'grid'),
        'limit'            => null,
        'show_image'       => newssync_get_option('newssync_show_image', 1),
        'category'         => '',
        'autoplay'         => 'on',
        'list_mode'        => newssync_get_option('newssync_list_mode', 'standard'),
        'compact'          => 'no',
        'hide_image'       => 'no',
        'date_format'      => 'H:i - d/m',
        'source'           => 'rss',
        'show_title'       => 'yes',
        'show_excerpt'     => 'yes',
        'show_date'        => 'yes',
        'show_source'      => 'yes',
        'show_readmore'    => 'no',
        'excerpt_length'   => '25',
        'cache_ttl'        => '',
        // Advanced attributes (kept for compatibility)
        'title_length'     => '',
        'image_size'       => '',
        'custom_css_class' => '',
        'keyword_filter'   => '',
        // Ordering/offset (ordering may be applied when supported)
        'orderby'          => 'date',
        'order'            => 'DESC',
        'offset'           => 0,
    ], $atts, 'newssync');

    // Helper to normalize boolean-ish shortcode flags.
    $normalize_flag = function($key) use ($raw_atts, $atts) {
        if (!array_key_exists($key, $raw_atts)) {
            return null;
        }
        $val = $atts[$key];
        if (is_bool($val)) return $val ? 1 : 0;
        $str = strtolower(trim((string)$val));
        $true = ['1','yes','true','on'];
        return in_array($str, $true, true) ? 1 : 0;
    };

    // Normalize many flags (null means not provided)
    $norm_show_image   = $normalize_flag('show_image');
    $norm_show_title   = $normalize_flag('show_title');
    $norm_show_excerpt = $normalize_flag('show_excerpt');
    $norm_show_date    = $normalize_flag('show_date');
    $norm_show_source  = $normalize_flag('show_source');
    $norm_show_readmore= $normalize_flag('show_readmore');
    $norm_compact_raw  = $normalize_flag('compact');
    $norm_hide_image   = $normalize_flag('hide_image');

    // excerpt length
    $norm_excerpt_length = null;
    if (array_key_exists('excerpt_length', $raw_atts)) {
        $norm_excerpt_length = intval($atts['excerpt_length']);
        if ($norm_excerpt_length < 0) $norm_excerpt_length = 0;
    }

    // date_format
    $norm_date_format = null;
    if (array_key_exists('date_format', $raw_atts) && !empty($atts['date_format'])) {
        $norm_date_format = sanitize_text_field($atts['date_format']);
    }

    // list_mode
    $norm_list_mode = null;
    if (array_key_exists('list_mode', $raw_atts) && !empty($atts['list_mode'])) {
        $norm_list_mode = sanitize_text_field($atts['list_mode']);
    }

    $atts['compact'] = ($atts['compact'] === 'yes' || $atts['compact'] === '1') ? 'yes' : 'no';

    $normalized_display_overrides = [];

    if ($norm_hide_image !== null) {
        $normalized_display_overrides['image'] = $norm_hide_image ? 0 : 1;
    } elseif ($norm_show_image !== null) {
        $normalized_display_overrides['image'] = $norm_show_image ? 1 : 0;
    }

    if ($norm_show_title !== null)    $normalized_display_overrides['title'] = $norm_show_title ? true : false;
    if ($norm_show_excerpt !== null)  $normalized_display_overrides['excerpt'] = $norm_show_excerpt ? true : false;
    if ($norm_show_date !== null)     $normalized_display_overrides['date'] = $norm_show_date ? true : false;
    if ($norm_show_source !== null)   $normalized_display_overrides['source'] = $norm_show_source ? true : false;
    if ($norm_show_readmore !== null) $normalized_display_overrides['readmore'] = $norm_show_readmore ? true : false;
    if ($norm_compact_raw !== null)   $normalized_display_overrides['compact'] = $norm_compact_raw ? true : false;

    if ($norm_excerpt_length !== null) $normalized_display_overrides['excerpt_length'] = $norm_excerpt_length;
    if ($norm_date_format !== null)    $normalized_display_overrides['date_format'] = $norm_date_format;
    if ($norm_list_mode !== null)      $normalized_display_overrides['list_mode'] = $norm_list_mode;

    // Validate layout
    $valid_layouts = ['grid', 'list', 'carousel', 'hero', 'minimal'];
    $layout = in_array($atts['layout'], $valid_layouts, true) ? $atts['layout'] : 'grid';

    if ($layout === 'minimal') {
        $layout = 'list';
        if ($norm_list_mode === null) {
            $atts['list_mode'] = 'minimal';
            $normalized_display_overrides['list_mode'] = 'minimal';
        } else {
            $atts['list_mode'] = $norm_list_mode;
        }
        $atts['compact'] = 'yes';
        $normalized_display_overrides['compact'] = true;
    }

    // === Display / per-layout limit logic ===
    $user_provided_limit = null;
    if ( array_key_exists( 'limit', $raw_atts ) ) {
        $user_provided_limit = intval( $atts['limit'] );
        if ( $user_provided_limit < 0 ) $user_provided_limit = 0;
    }

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

    // Hero/Carousel cap: enforce configured cap (default 6)
    $hero_cap = intval( newssync_get_option( 'newssync_hero_max_items', 6 ) );
    if ( $hero_cap <= 0 ) $hero_cap = 6;
    if ( in_array( $layout, array( 'carousel', 'hero' ), true ) ) {
        // When offset is used, fetch more items to ensure we still have hero_cap items after offset
        $fetch_for_hero = $hero_cap;
        if ( $requested_offset > 0 ) {
            $fetch_for_hero = $hero_cap + $requested_offset;
        }

        if ( $user_provided_limit !== null && $user_provided_limit > 0 ) {
            $atts['limit'] = min( $user_provided_limit, $fetch_for_hero );
        } else {
            $atts['limit'] = $fetch_for_hero;
        }
    } else {
        if ( $user_provided_limit !== null ) {
            $atts['limit'] = $user_provided_limit;
        }
    }

    // Build display parts:
    // Use prefixed globals internally; expose legacy globals via $GLOBALS for backwards compatibility.
    $newssync_atts = $atts;
    // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- expose legacy global for backwards compatibility
    $GLOBALS['newssync_atts'] = $newssync_atts;

    // Get base display config from display-parts.php if present
    if (file_exists(NEWSSYNC_PLUGIN_DIR . 'includes/core/newssync-display-parts.php')) {
        require_once NEWSSYNC_PLUGIN_DIR . 'includes/core/newssync-display-parts.php';
        $display_base = function_exists('newssync_get_display_parts') ? newssync_get_display_parts($atts) : [];
    } else {
        $display_base = [];
    }

    $display_defaults = [
        'title' => true, 'image' => true, 'excerpt' => true, 'date' => true,
        'source' => false, 'readmore' => false, 'compact' => false,
        'date_format' => $atts['date_format'] ?? 'H:i - d/m', 'excerpt_length' => intval($atts['excerpt_length'] ?? 25),
        'list_mode' => $atts['list_mode'] ?? newssync_get_option('newssync_list_mode', 'standard'),
        'pro_teaser' => false,
    ];
    $display = wp_parse_args($display_base, $display_defaults);

    foreach ($normalized_display_overrides as $k => $v) {
        if ($v === null) continue;
        $display[$k] = $v;
    }

    $display['excerpt_length'] = isset($display['excerpt_length']) ? intval($display['excerpt_length']) : 25;
    if ($display['excerpt_length'] < 0) $display['excerpt_length'] = 0;
    if ($display['excerpt_length'] > 25) {
        // Enforce free distribution excerpt cap
        $display['excerpt_length'] = 25;
    }

    $newssync_display = $display;
    // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- expose legacy global for backwards compatibility
    $GLOBALS['newssync_display'] = $newssync_display;

    /**
     * FREE mode adjustments:
     * - Grid/List: leave limit unset so provider applies per-feed cap (3 per feed).
     * - Hero/Carousel: when user did NOT provide limit, force a global limit of 6 (or the option if larger).
     */
    // Free/default behavior: honor user-provided limit if present; otherwise keep provider defaults
    if ( $user_provided_limit !== null ) {
        $atts['limit'] = $user_provided_limit;
    }

    // Normal fetch: preserve provider limits and use provided attributes
    $items = newssync_get_items( $atts );

    // ---- Normalize orderby/order (sanitization + whitelist) ----
    $orderby = 'date';
    $order = 'DESC';
    // sanitize inputs (sanitize_text_field required by WP.org)
    $raw_orderby = isset( $atts['orderby'] ) ? sanitize_text_field( $atts['orderby'] ) : 'date';
    $raw_order = isset( $atts['order'] ) ? sanitize_text_field( $atts['order'] ) : 'DESC';

    // whitelist of allowed orderbys
    $allowed_orderbys = array( 'date', 'title', 'guid' );
    $orderby = in_array( $raw_orderby, $allowed_orderbys, true ) ? $raw_orderby : 'date';

    $order = strtoupper( $raw_order );
    if ( $order !== 'ASC' && $order !== 'DESC' ) $order = 'DESC';

    // ---- Sort items in-memory according to orderby/order when enabled ----
    if ( ! empty( $items ) && is_array( $items ) ) {

        // Helper to extract timestamp (tries common keys, falls back to strtotime on 'date' string)
        $get_timestamp = function( $it ) {
            if ( isset( $it['timestamp'] ) ) return intval( $it['timestamp'] );
            if ( isset( $it['date_timestamp'] ) ) return intval( $it['date_timestamp'] );
            if ( isset( $it['date'] ) ) {
                $ts = strtotime( $it['date'] );
                return $ts ? intval( $ts ) : 0;
            }
            return 0;
        };

        if ( $orderby === 'date' ) {
            usort( $items, function( $a, $b ) use ( $order, $get_timestamp ) {
                $ta = $get_timestamp( $a );
                $tb = $get_timestamp( $b );
                if ( $ta === $tb ) return 0;
                if ( $order === 'ASC' ) return ( $ta <=> $tb );
                return ( $tb <=> $ta );
            } );
        } elseif ( $orderby === 'title' ) {
            usort( $items, function( $a, $b ) use ( $order ) {
                $ta = isset( $a['title'] ) ? (string) $a['title'] : '';
                $tb = isset( $b['title'] ) ? (string) $b['title'] : '';
                $cmp = strcasecmp( $ta, $tb ); // case-insensitive
                return ( $order === 'ASC' ) ? $cmp : -$cmp;
            } );
        } elseif ( $orderby === 'guid' ) {
            usort( $items, function( $a, $b ) use ( $order ) {
                $ta = isset( $a['guid'] ) ? (string) $a['guid'] : '';
                $tb = isset( $b['guid'] ) ? (string) $b['guid'] : '';
                $cmp = strcmp( $ta, $tb );
                return ( $order === 'ASC' ) ? $cmp : -$cmp;
            } );
        } elseif ( $orderby === 'fetch_order' ) {
            usort( $items, function( $a, $b ) use ( $order ) {
                $ta = isset( $a['fetch_order'] ) ? intval( $a['fetch_order'] ) : 0;
                $tb = isset( $b['fetch_order'] ) ? intval( $b['fetch_order'] ) : 0;
                if ( $ta === $tb ) return 0;
                if ( $order === 'ASC' ) return ( $ta <=> $tb );
                return ( $tb <=> $ta );
            } );
        }
    }

    // ---- Apply offset (clamped) for available modes ----
    if ( ! empty( $items ) && is_array( $items ) && $requested_offset > 0 ) {
        $n = count( $items );

        // For Hero/Carousel with FREE cap, we already fetched extra items
        // Just apply offset directly, cap will be enforced below
        if ( in_array( $layout, array( 'carousel', 'hero' ), true ) ) {
            if ( $requested_offset < $n ) {
                $items = array_slice( $items, $requested_offset );
            }
        } else {
            // For other layouts, determine the number of items we aim to show (L)
            $L = $n; // default: show all remaining items after offset
            if ( isset( $atts['limit'] ) && intval( $atts['limit'] ) > 0 ) {
                $L = intval( $atts['limit'] );
            }

            // effective_offset clamped so we still can show up to L items when possible
            $effective_offset = min( $requested_offset, max( 0, $n - $L ) );

            if ( $effective_offset > 0 ) {
                $items = array_slice( $items, $effective_offset );
            }
        }
    }

    // Ensure visual cap for Hero/Carousel
    if ( ! empty( $items ) && in_array( $layout, array( 'carousel', 'hero' ), true ) ) {
        $hero_cap = intval( newssync_get_option( 'newssync_hero_max_items', 6 ) );
        if ( $hero_cap <= 0 ) $hero_cap = 6;
        if ( $hero_cap > 0 && count( $items ) > $hero_cap ) {
            $items = array_slice( $items, 0, $hero_cap );
        }
    }

    if (empty($items)) {
        return '<p style="text-align:center;color:#d63638;">' . esc_html__('No news found.', 'rss-newssync') . '</p>';
    }

    // Normalize images
    foreach ($items as &$item) {
            if (!empty($item['img_url'])) {
            $item['img'] = esc_url($item['img_url']);
        } elseif (!empty($item['img'])) {
            $item['img'] = esc_url($item['img']);
        } else {
            if (function_exists('newssync_get_random_placeholder')) {
                $item['img'] = esc_url(newssync_get_random_placeholder());
            } else {
                $item['img'] = '';
            }
        }
    }
    unset($item);

    // Enqueue CSS global
    if ( ! wp_style_is( 'rsp-frontend', 'enqueued' ) ) {
        wp_enqueue_style('rsp-frontend', NEWSSYNC_PLUGIN_URL . 'includes/assets/css/newssync-frontend.css', [], '1.0.0');
    }

    // Determine layout file
    $layout_file = NEWSSYNC_PLUGIN_DIR . "includes/layouts/newssync-{$layout}.php";

    if ($layout === 'list') {
        $list_mode = $atts['list_mode'] ?? ($display['list_mode'] ?? newssync_get_option('newssync_list_mode', 'standard'));
        if ($list_mode === 'minimal') {
            $candidate = NEWSSYNC_PLUGIN_DIR . 'includes/layouts/newssync-list-minimal.php';
            if (file_exists($candidate)) $layout_file = $candidate;
        } else {
            $candidate = NEWSSYNC_PLUGIN_DIR . 'includes/layouts/newssync-list.php';
            if (file_exists($candidate)) $layout_file = $candidate;
        }
    }

    if (!file_exists($layout_file)) {
        $layout_file = NEWSSYNC_PLUGIN_DIR . 'includes/layouts/newssync-grid.php';
    }

    // Render template into buffer
    ob_start();
    include $layout_file;
    $html = ob_get_clean();

    // Enqueue Swiper only for carousel/hero
    if ( in_array( $layout, array( 'carousel', 'hero' ), true ) && ! empty( $items ) ) {
        // Decide se Swiper should be used
        $enable_swiper = apply_filters( 'newssync_enable_swiper', false )
            || wp_style_is( 'swiper-css', 'registered' )
            || wp_script_is( 'swiper-js', 'registered' )
            || wp_script_is( 'swiper-js', 'enqueued' );

        // Init options
        $slides_per_view = ( $layout === 'hero' ) ? 1 : 3;
        $effect = ( $layout === 'hero' ) ? 'fade' : false;
        $breakpoints = array(
            640  => array( 'slidesPerView' => ( $layout === 'hero' ? 1 : 1 ) ),
            768  => array( 'slidesPerView' => ( $layout === 'hero' ? 1 : 2 ) ),
            1024 => array( 'slidesPerView' => ( $layout === 'hero' ? 1 : 3 ) ),
        );

        // Check if autoplay is enabled via shortcode parameter
        $autoplay_enabled = true;
        if ( array_key_exists( 'autoplay', $raw_atts ) ) {
            $autoplay_raw = isset( $raw_atts['autoplay'] ) ? $raw_atts['autoplay'] : $atts['autoplay'];
            $autoplay_val = strtolower( trim( (string) $autoplay_raw ) );
            if ( in_array( $autoplay_val, array( 'off', 'no', '0', 'false', 'disabled' ), true ) ) {
                $autoplay_enabled = false;
            }
        }

        $init = array(
            'slidesPerView'   => $slides_per_view,
            'spaceBetween'    => 20,
            'loop'            => true,
            'autoplay'        => $autoplay_enabled ? array( 'delay' => 5000, 'disableOnInteraction' => false ) : false,
            'pagination'      => array( 'el' => '.swiper-pagination', 'clickable' => true ),
            'navigation'      => array( 'nextEl' => '.swiper-button-next', 'prevEl' => '.swiper-button-prev' ),
            'effect'          => $effect,
            'observer'        => true,
            'observeParents'  => true,
            'breakpoints'     => $breakpoints,
        );

        if ( $enable_swiper ) {
            // Generate a cache-busting version hash based on plugin version + current timestamp
            // This ensures that when shortcode code changes, the cache is invalidated
            $cache_bust_version = '1.0.' . gmdate( 'YmdHi', filemtime( __FILE__ ) );

            // Enqueue (or rely on theme-registered)
                if ( wp_style_is( 'swiper-css', 'registered' ) && ! wp_style_is( 'swiper-css', 'enqueued' ) ) {
                wp_enqueue_style( 'swiper-css', false, array(), $cache_bust_version );
            }
            if ( wp_script_is( 'swiper-js', 'registered' ) && ! wp_script_is( 'swiper-js', 'enqueued' ) ) {
                wp_enqueue_script( 'swiper-js', false, array(), $cache_bust_version, true );
            }

            if ( wp_script_is( 'rsp-swiper-init', 'registered' ) && ! wp_script_is( 'rsp-swiper-init', 'enqueued' ) ) {
                wp_enqueue_script( 'rsp-swiper-init', false, array(), $cache_bust_version, true );
            }

            // Register & enqueue dots-cap script
            if ( ! wp_script_is( 'rsp-dots-cap', 'registered' ) ) {
                wp_register_script(
                    'rsp-dots-cap',
                    NEWSSYNC_PLUGIN_URL . 'includes/assets/js/slider-dots-cap.js',
                    array( 'swiper-js' ),
                    $cache_bust_version,
                    true
                );
            }
            if ( ! wp_script_is( 'rsp-dots-cap', 'enqueued' ) ) {
                wp_enqueue_script( 'rsp-dots-cap' );
                $hero_cap = intval( newssync_get_option( 'newssync_hero_max_items', 10 ) );
                $inline_call = 'if ( typeof window.rspCapSwiperDots === "function" ) { window.rspCapSwiperDots(' . $hero_cap . '); }';
                wp_add_inline_script( 'rsp-dots-cap', $inline_call );
            }

            // Push this instance init into the queue that rsp-swiper-init will process.
            $inline_push = 'window.newssync_swiper_queue = window.newssync_swiper_queue || []; window.newssync_swiper_queue.push( { selector: ".rsp-' . esc_js( $layout ) . '", options: ' . wp_json_encode( $init ) . ' } );';
            wp_add_inline_script( 'swiper-js', $inline_push );
        }
    }

    // 'upsell teaser' removed for this distribution: do not append promotional content.

    return $html;
}

// Backwards-compatible wrapper: keep original function name but forward to new implementation.
if ( ! function_exists( 'newss_render_shortcode' ) ) {
    // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- backwards compatibility wrapper
    function newss_render_shortcode( $atts ) {
        // Backwards-compatible forwarder: keep calling the new implementation
        // Intentionally avoid calling _deprecated_function here to prevent
        // noisy debug log entries in environments that still call the
        // legacy function name.
        return newssync_render_shortcode( $atts );
    }
}
