<?php
/**
 * RDG-Blocks
 *
 * @package       RDGBLOCKS
 * @author        RDGCorp
 * @version 1.3.108
 *
 * @wordpress-plugin
 * Plugin Name:   RDG-Blocks
 * Plugin URI:    https://www.rdgcorp.com
 * Description:   Custom Gutenberg Blocks that extends Advanced Custom Fields Pro. Requires ACF Pro to be active.
 * Version: 1.3.108
 * Author:        RDGCorp
 * Author URI:    https://www.rdgcorp.com
 * Text Domain:   rdg-blocks
 * Domain Path:   /languages
 */

// Exit if accessed directly.
if (!defined('ABSPATH')) exit;

/**
 * HELPER COMMENT START
 *
 * This file contains the main information about the plugin.
 * It is used to register all components necessary to run the plugin.
 *
 * The comment above contains all information about the plugin
 * that are used by WordPress to differenciate the plugin and register it properly.
 * It also contains further PHPDocs parameter for a better documentation
 *
 * The function RDGBLOCKS() is the main function that you will be able to
 * use throughout your plugin to extend the logic. Further information
 * about that is available within the sub classes.
 *
 * HELPER COMMENT END
 */
// Plugin name
define('RDGBLOCKS_NAME', 'RDG-Blocks');
define('RDGBLOCKS_NAME_SLUG', 'rdg-blocks');

// Plugin version
define('RDGBLOCKS_VERSION', '1.3.108');

// Plugin upload path suffix
define('RDGBLOCKS_BASE_PATH', rdgblocksGetUploadPathSuffix());

// Plugin Root File
define('RDGBLOCKS_PLUGIN_FILE', __FILE__);

// Plugin base
define('RDGBLOCKS_PLUGIN_BASE', plugin_basename(RDGBLOCKS_PLUGIN_FILE));

// Plugin Folder Path
define('RDGBLOCKS_PLUGIN_DIR', plugin_dir_path(RDGBLOCKS_PLUGIN_FILE));

// Plugin Folder URL
define('RDGBLOCKS_PLUGIN_URL', plugin_dir_url(RDGBLOCKS_PLUGIN_FILE));

// Plugin Blocks Folder URL
define('RDGBLOCKS_PLUGIN_BLOCKS_DIR', plugin_dir_path(RDGBLOCKS_PLUGIN_FILE).'blocks/');

// Plugin Vendor Folder
define('RDGBLOCKS_PLUGIN_VENDOR_DIR', plugin_dir_path(RDGBLOCKS_PLUGIN_FILE).'vendor/');

// Images Maintenance Path
define('IMAGES_MAINTENANCE_FOLDER', wp_upload_dir()['basedir'].'/'.RDGBLOCKS_NAME_SLUG.'/images/');

// Cache Maintenance Path
define('CACHE_MAINTENANCE_FOLDER', wp_upload_dir()['basedir'].'/'.RDGBLOCKS_NAME_SLUG.'/');

// Cache Maintenance Uri
define('CACHE_MAINTENANCE_FOLDER_URI', wp_upload_dir()['baseurl'].'/'.RDGBLOCKS_NAME_SLUG.'/');

// Block List Const
define('BLOCK_RDG_CALL_TO_ACTION', 'rdg-call-to-action');
define('BLOCK_RDG_IMAGE_COLUMN', 'rdg-image-column');
define('BLOCK_RDG_MAIN_BANNER', 'rdg-main-banner');
define('BLOCK_RDG_SPORTS_PICKS', 'rdg-sports-picks');
define('BLOCK_RDG_TITLE', 'rdg-title');
define('BLOCK_RDG_TOP_WINNERS', 'rdg-top-winners');
define('BLOCK_RDG_ADMIN_CAPPERS', 'rdg-admin-cappers');
define('BLOCK_RDG_NEXT_GAME', 'rdg-next-game');
define('BLOCK_RDG_SLIDER_LATEST_POST', 'rdg-slider-latest-post');
define('BLOCK_RDG_LATEST_POST', 'rdg-latest-post');
define('BLOCK_RDG_PICKS_LIST', 'rdg-picks-list');
define('BLOCK_RDG_FAQ', 'rdg-faq');
define('BLOCK_RDG_BUTTONS', 'rdg-buttons');
define('BLOCK_RDG_LOGO_TEAM', 'rdg-logo-team');
define('BLOCK_RDG_ODD_BETTING_SELECT', 'rdg-odd-betting-select');
define('BLOCK_RDG_ODD_BETTING_DATE', 'rdg-odd-betting-date');
define('BLOCK_RDG_SPORTS_PICKS_VS', 'rdg-sports-picks-vs');
define('BLOCK_RDG_PARAGRAPH_CUSTOM', 'rdg-paragraph-custom');
define('BLOCK_RDG_POSTS_LIST', 'rdg-posts-list');
define('BLOCK_RDG_NEW_PARAGRAPH_CUSTOM', 'rdg-new-paragraph-custom');
define('BLOCK_RDG_PICKS_VS', 'rdg-picks-vs');
define('BLOCK_RDG_PICKS_VS_CATEGORIES', 'rdg-picks-vs-categories');
define('BLOCK_RDG_MAIN_PROMOTIONS', 'rdg-main-promotions');
define('BLOCK_RDG_TOP_CAPPERS', 'rdg-top-cappers');
define('BLOCK_RDG_FAVORITE_CAPPERS', 'rdg-favorite-cappers');
define('BLOCK_RDG_LEADER_BOARD', 'rdg-leader-board');
define('BLOCK_RDG_LOGO_RANKING', 'rdg-logo-ranking');
define('BLOCK_RDG_TABLE', 'rdg-table');
define('BLOCK_RDG_ADMIN_CAPPERS_SIMPLE', 'rdg-admin-cappers-simple');
define('BLOCK_RDG_TABLE_LEAGUES', 'rdg-table-leagues');
define('BLOCK_RDG_COLUMNS_PICKS', 'rdg-columns-picks');
define('BLOCK_RDG_SEPARATOR', 'rdg-separator');
define('BLOCK_RDG_SINGLE_PICK', 'rdg-single-pick');
define('BLOCK_RDG_PARAGRAPH_COLOR', 'rdg-paragraph-color');
define('BLOCK_RDG_LOGIN', 'rdg-login');
define('BLOCK_RDG_REGISTER', 'rdg-register');
define('BLOCK_RDG_BOX_LIST', 'rdg-box-list');
define('BLOCK_RDG_SOCIALS_ICONS', 'rdg-socials-icons');
define('BLOCK_RDG_CONSENSUS', 'rdg-consensus');
define('BLOCK_RDG_POSTS_AJAX', 'rdg-posts-ajax');
define('BLOCK_RDG_EXPERTS_BANNER', 'rdg-experts-banner');
define('BLOCK_RDG_PREVIEWS_AND_PREDICTIONS', 'rdg-previews-and-predictions');
define('BLOCK_RDG_SECONDARY_BANNER', 'rdg-secondary-banner');
define('BLOCK_RDG_BUTTONS_COLUMN', 'rdg-buttons-column');
define('BLOCK_RDG_RANKING_BOOKIE', 'rdg-ranking-bookie');
define('BLOCK_RDG_BOOKIE_LOGO', 'rdg-bookie-logo');
define('BLOCK_RDG_PRODUCT_REPORT', 'rdg-product-report');
define('BLOCK_RDG_BEST_PPH', 'rdg-best-pph');
define('BLOCK_RDG_SINGLE_TOP_HANDICAPPERS', 'rdg-single-top-handicappers');
define('BLOCK_RDG_SIMPLE_POST_LIST', 'rdg-simple-post-list');
define('BLOCK_RDG_HEADING', 'rdg-heading');
define('BLOCK_RDG_PROS_CONS', 'rdg-pros-cons');
define('BLOCK_RDG_HEADING_PARAGRAPH', 'rdg-heading-paragraph');
define('BLOCK_RDG_MEMBERSHIPS', 'rdg-memberships');
define('BLOCK_RDG_BOOKIE_SUMMARY', 'rdg-bookie-summary');
define('BLOCK_RDG_QUICK_LINKS', 'rdg-quick-links');
define('BLOCK_RDG_BOOKIE_SUMMARY_SIDEBAR', 'rdg-bookie-summary-sidebar');
define('BLOCK_RDG_QUICK_LINKS_SIDEBAR', 'rdg-quick-links-sidebar');
define('BLOCK_RDG_CPT_LIST', 'rdg-cpt-list');
define('BLOCK_RDG_BEST_PPH_SITES', 'rdg-best-pph-sites');
define('BLOCK_RDG_GAMBLING_CENTER', 'rdg-gambling-center');
define('BLOCK_RDG_BOOKIE_SELECTOR', 'rdg-bookie-selector');
define('BLOCK_RDG_BANNER_SIDEBAR', 'rdg-banner-sidebar');
define('BLOCK_RDG_SPORT_INFORMATION', 'rdg-sport-information');
define('BLOCK_RDG_MEMBERSHIP_INFO', 'rdg-membership-info');
define('BLOCK_RDG_PROMOTE_SITE', 'rdg-promote-site');
define('BLOCK_RDG_TOP_SITES', 'rdg-top-sites');
define('BLOCK_RDG_TEAM_SCHEDULES', 'rdg-team-schedules');
define('BLOCK_RDG_TOP_CAPPERS_SPORT', 'rdg-top-cappers-sport');
define('BLOCK_RDG_INJURY_REPORT', 'rdg-injury-report');
define('BLOCK_RDG_SAS_NAVBAR', 'rdg-sas-navbar');
define('BLOCK_RDG_SPORT_BETTING_ODDS', 'rdg-sport-betting-odds');
define('BLOCK_RDG_CAROUSEL', 'rdg-carousel');
define('BLOCK_RDG_SH_QUERY_POSTS', 'sh-query-posts');
define('BLOCK_RDG_TRENDS', 'rdg-trends');
define('BLOCK_RDG_HANDICAPPERS_HUB', 'rdg-handicappers-hub');
define('BLOCK_RDG_SCORES_AND_ODDS', 'rdg-scores-and-odds');
define('BLOCK_RDG_HANDICAPPER_PICK_RESULTS', 'rdg-handicapper-pick-results');
define('BLOCK_RDG_PARLAY_CALCULATOR', 'rdg-parlay-calculator');
define('BLOCK_RDG_SH_YOUTUBE_VIDEO', 'sh-youtube-video');
define('BLOCK_RDG_PICKS_VS_MULTI', 'rdg-picks-vs-multi');
define('BLOCK_RDG_AV_PICKS_STICKY', 'rdg-av-picks-sticky');

define('BLOCK_RDG_TYPE_LATEST', 'latest');
define('BLOCK_RDG_TYPE_SPECIFIC', 'specific');
define('BLOCK_RDG_TYPE_EXTERNAL', 'external');

// Source Data Const
define('SOURCE_DATA_MANUAL', 'manual');
define('SOURCE_DATA_API', 'api');

// Default Handicapper Package
define('HANDICAPPER_PACKAGE_DEFAULT', 'Expert Handicapper');

// API DATE TYPE
define('API_DATE_TYPE_YESTERDAY', 'yesterday');
define('API_DATE_TYPE_NOW', 'now');
define('API_DATE_TYPE_TOMORROW', 'tomorrow');
define('API_DATE_TYPE_RANGE', 'range');

// REDIS
define('REDIS_GROUP_BLOCKS', 'blocks');
define('REDIS_TIMEOUT', 3600);

// RDG CACHE CONFIGURATION
// Time threshold (in seconds) before cache expiration to trigger regeneration
// Default: 300 seconds (5 minutes before expiration)
if (!defined('RDG_BLOCK_CACHE_CLEAR_TIME')) {
    define('RDG_BLOCK_CACHE_CLEAR_TIME', 300);
}

// Maximum number of failed regeneration attempts before pausing
// Default: 5 attempts
if (!defined('RDG_BLOCK_CACHE_FAILED_RETRY')) {
    define('RDG_BLOCK_CACHE_FAILED_RETRY', 5);
}

// Delay (in seconds) before retrying after reaching max failed attempts
// Default: 1800 seconds (30 minutes)
if (!defined('RDG_BLOCK_CACHE_FAILED_RETRY_DELAY')) {
    define('RDG_BLOCK_CACHE_FAILED_RETRY_DELAY', 1800);
}

# RDG PLUGIN REVIEWS LIST
define('RDG_BLOCKS_REVIEWS', 'pph-review,sportsbook-review');

/**
 * Load the main class for the core functionality
 */
require_once RDGBLOCKS_PLUGIN_DIR.'core/class-rdg-blocks.php';

/**
 * Load the mase class for the blocks functionality
 */
require_once RDGBLOCKS_PLUGIN_BLOCKS_DIR."rdg-blocks-base.php";
require_once RDGBLOCKS_PLUGIN_BLOCKS_DIR."rdg-blocks-api-request.php";

/**
 * The main function to load the only instance
 * of our master class.
 *
 * @author  RDGCorp
 * @since   1.0.0
 * @return  object|Rdg_Blocks
 */
function RDGBLOCKS() {
    $rdgb = Rdg_Blocks::instance();
    $rdg_base_style = $rdgb->helpers->webpack('rdg_base_style.css');
    add_action('plugins_loaded', 'acf_check_dependency', 10);

    add_action('init', function () use ($rdg_base_style) {
        wp_enqueue_style('rdg_base_style', $rdg_base_style, [], true);
        $jquery_load = (isset(get_field('rdg_resource_jquery_group', 'option')['jquery_versions'])) ? get_field('rdg_resource_jquery_group', 'option')['jquery_versions'] : 'none';

        if ($jquery_load != 'none') {
            $path = 'core/includes/assets/js/jquery/';
            $jquery_dir = RDGBLOCKS_PLUGIN_DIR.$path;
            $jquery_uri = RDGBLOCKS_PLUGIN_URL.$path;

            if (file_exists($jquery_dir.$jquery_load)) {
                wp_enqueue_script('rdgblocks-'.$jquery_load, $jquery_uri.$jquery_load, [], RDGBLOCKS_VERSION, false);
            } else {
                error_log(print_r([
                    'message' => 'The requested jquery file does not exist.',
                    'jquery_load' => $jquery_load,
                    'jquery_dir' => $jquery_dir,
                    'jquery_uri' => $jquery_uri,
                ], true));
            }
        }

        // wp_enqueue_script('rdgblocks-bootstrap-custom', RDGBLOCKS_PLUGIN_URL.'core/includes/assets/js/bootstrap_custom.js', [], RDGBLOCKS_VERSION, false);
        // wp_enqueue_script('rdgblocks-backend-scripts', RDGBLOCKS_PLUGIN_URL.'core/includes/assets/js/backend-scripts.js', [], RDGBLOCKS_VERSION, false);

        if (is_admin()) {
            wp_enqueue_script( 'rdgblocks-backend-scripts', RDGBLOCKS_PLUGIN_URL . 'core/includes/assets/js/backend-scripts.js', [], RDGBLOCKS_VERSION, false );
        }
    });

    add_action('init', function() {
        remove_filter('acf_the_content', 'wpautop');
    });

    add_action('edit_post', function($post_id) use ($rdgb) {
        if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) return;

        if ($rdgb->helpers->initRedis()) {
            $rdgb->helpers->setRedisGroup(REDIS_GROUP_BLOCKS);
            $key = 'save_posts:'.$post_id;
            $save = $rdgb->helpers->getRedis($key);

            if ($save) {
                return;
            }

            $rdgb->helpers->setRedis($key, true, 7);
        }

        $post = get_post($post_id);
        $post_content = $post->post_content;
        $post_type = $post->post_type;
        $blocks = $rdgb->settings->getBlocks();
        $blocks_caching = $rdgb->helpers->getBlocksCaching($blocks, $post_content);

        $blocks_list = [];
        $page = $post_type.':'.$post_id;

        $cache = new Rdg_Blocks_Cache();
        $connect = $cache->getRedisConnect();

        if (!$connect) {
            error_log(sprintf(
                'RDG Blocks / edit_post: Redis connection failed for post %d. Cache will not be created.',
                $post_id
            ));
            return;
        }
        $cache_blocks = $cache->getCacheList();

        if (count($blocks_caching) > 0) {
            foreach ($blocks_caching as $block) {
                $block_name = $block['name'];
                $items = $block['items'];
                $block_custom_id = $block['custom_id'];
                
                // Include date range in cache key for rdg-picks-vs-multi to ensure unique cache entries
                $date_suffix = '';
                if ($block_name === BLOCK_RDG_PICKS_VS_MULTI && isset($block['api_params']['date']) && is_array($block['api_params']['date'])) {
                    $date_params = $block['api_params']['date'];
                    if (!empty($date_params['start']) || !empty($date_params['end'])) {
                        $date_suffix = ':' . md5(($date_params['start'] ?? '') . '|' . ($date_params['end'] ?? ''));
                    }
                }
                
                $cache_name = $rdgb->helpers->getBlocksCacheName($block_name, $post_type, $post_id, $block_custom_id) . $date_suffix;
                
                $cache_refresh = 1;
                $interval_field = (isset($block['interval_field']) && !empty($block['interval_field'])) ? $block['interval_field'] : null;

                if (!empty($interval_field) && !empty(get_field($interval_field, 'option'))) {
                    $cache_refresh = get_field($interval_field, 'option');
                }

                $blocks_list[] = $cache_name;

                # If the block exists in Redis, delete it to force regeneration
                if (in_array($cache_name, $cache_blocks)) {
                    $cache->delCacheBlock($cache_name);
                    error_log(sprintf(
                        'RDG Blocks / edit_post: Deleted cache %s to force regeneration',
                        $cache_name
                    ));
                }

                try {
                    $current_block = $rdgb->settings->getBlock($block_name);
                    $api_attributes = $current_block->getApiAttributes($items, $block['api_params']);
                    
                    // CRITICAL FIX: Check if getApiAttributes returned null (missing required fields)
                    if (is_null($api_attributes)) {
                        error_log(sprintf(
                            'RDG Blocks / edit_post: getApiAttributes returned null for block %s (post %d). Required fields (league/sport) may be missing.',
                            $block_name,
                            $post_id
                        ));
                        $rdgb->helpers->getApiError('api_attributes_null', [
                            'block_name' => $block_name,
                            'post_id' => $post_id,
                            'api_params' => $block['api_params'],
                            'message' => 'getApiAttributes returned null - required fields (league/sport) may be missing'
                        ]);
                        continue;
                    }
                    
                    $data = [
                        'api_attributes' => $api_attributes,
                        'api_response' => null,
                        'items' => 0,
                    ];

                    # Add the block to the cache list
                    $saved = $cache->addCacheList($cache_name, $cache_refresh, $data);
                    if (!$saved) {
                        error_log(sprintf(
                            'RDG Blocks / edit_post: Failed to save cache for block %s (post %d). Redis operation may have failed.',
                            $block_name,
                            $post_id
                        ));
                        $rdgb->helpers->getApiError('cache_save_error', [
                            'block_name' => $block_name,
                            'code' => 'cache_save_error',
                            'api_attributes' => $api_attributes,
                            'post_id' => $post_id
                        ]);

                        continue;
                    }

                    error_log(sprintf(
                        'RDG Blocks / edit_post: Successfully created cache entry for block %s (post %d)',
                        $block_name,
                        $post_id
                    ));
                    $rdgb->helpers->getApiError(200, ['block_name' => $block_name]);
                } catch (Exception $exception) {
                    error_log(sprintf(
                        'RDG Blocks / edit_post: Exception while creating cache for block %s (post %d): %s',
                        $block_name,
                        $post_id,
                        $exception->getMessage()
                    ));
                    $rdgb->helpers->getApiError('', [
                        'block_name' => $block_name,
                        'post_id' => $post_id,
                        'api_attributes' => isset($api_attributes) ? $api_attributes : null,
                        'exception' => [
                            'file' => $exception->getFile(),
                            'line' => $exception->getLine(),
                            'message' => $exception->getMessage(),
                        ],
                    ]);
                }
            }
        }

        // CRITICAL FIX: Only clear old cache if new blocks were detected
        // If $blocks_caching is empty (parsing error, autosave, etc.), DO NOT clear existing cache
        // This prevents cache loss when WordPress saves posts without proper block parsing
        if (count($blocks_caching) > 0) {
            error_log(sprintf(
                'RDG Blocks / edit_post: Clearing old cache for page %s with %d new blocks detected',
                $page,
                count($blocks_list)
            ));
            $cache->clearCacheBlock($blocks_list, $page);
        } else {
            error_log(sprintf(
                'RDG Blocks / edit_post: No blocks detected for page %s - Preserving existing cache (possible parsing error or autosave)',
                $page
            ));
        }
    });

    add_filter('acf/pre_save_block', function($attributes) use ($rdgb) {
        global $post;

        if (!isset($attributes['data']['custom_id']) || empty($attributes['data']['custom_id'])) {
            $attributes['data']['custom_id'] = 'block-'.uniqid();
        }

        if (!empty($post->ID)) {
            $attributes['data']['post_id'] = $post->ID;
        }

        return $attributes;
    });

    return $rdgb;
}

$rdgb = RDGBLOCKS();

function acf_check_dependency() {
    if (!function_exists('is_plugin_active')) {
        require_once ABSPATH . 'wp-admin/includes/plugin.php';
    }
    
    if (!is_plugin_active('advanced-custom-fields-pro/acf.php') && !is_plugin_active('advanced-custom-fields/acf.php')) {
        
        deactivate_plugins(plugin_basename(__FILE__));
            
        wp_die(
            '<p>Advanced Custom Fields Pro is required for RGDBLOCKS to function. <br /><b>RGDBLOCKS has been deactivated.</b></p> 
            <a href="' . esc_url(admin_url('plugins.php')) . '" onclick="location.reload(); return false;">Go back and reload the Plugins page</a>',
            'Activation Error'
        );
    }
}

function rdgblocksIsBedrock() {
    if (strpos(str_replace('/', '\\', wp_upload_dir()['basedir']), 'web\app') !== false) {
        return true;
    }

    return false;
}

function rdgblocksGetUploadPathSuffix() {
    $suffix = (rdgblocksIsBedrock()) ? 'app' : 'wp-content';

    return sprintf('/%1$s/uploads/%2$s/images/', $suffix, RDGBLOCKS_NAME_SLUG);
}
