<?php

// Action Scheduler is loaded in Agile_Ticketing.php before this file is included
// Do not require it here to avoid conflicts with WooCommerce's bundled version

// Ensure WordPress admin functions are loaded (needed for Action Scheduler background processing)
if (!function_exists('download_url') || !function_exists('media_handle_sideload')) {
    require_once ABSPATH . 'wp-admin/includes/file.php';
    require_once ABSPATH . 'wp-admin/includes/image.php';
    require_once ABSPATH . 'wp-admin/includes/media.php';
}

class agile_tix_post_creator
{
    /**
     * Takes a single showing event and creates a tab containing the following showing specific info
     *
     */

    static function agile_create_showing_tab_content($showing)
    {

        //$executionTime = new ExecutionTime('agile_create_showing_tab_content');

        //$executionTime->start();

        $date = $showing['DisplayDate'] ?? '';

        $BuyLink = $showing['LegacyPurchaseLink'] ?? '';

        //$InfoLink = $showing['InfoLink'] ?? '';

        $Venue = $showing['Venue'] ?? '';

        $tabContent = '<div id="' . $showing['EventID'] . '" class="tabcontent">';


        if (!empty($date)) {
            $format_date = date('F j, Y g:i A', strtotime($date));
            $tabContent .= '<b><p style="font-size: 18px;">' . $format_date . '</p></b>';
        }

        if (!empty($BuyLink)) {
            $tabContent .= '<a href=' . $BuyLink . '>Buy Tickets</a><br>';
        }

        if (!empty($Venue)) {

            $name = $Venue['Name'] ?? '';

            $Address1 = $Venue['Address1'] ?? '';

            $Address2 = $Venue['Address2'] ?? '';

            $City = $Venue['City'] ?? '';

            $State = $Venue['State'] ?? '';

            $Zip = $Venue['Zip'] ?? '';

            $tabContent .= '<p>' . $name . ' ' . $Address1 . ' ' . $Address2 . ' ' . $City . ' ' . $State . ' ' . $Zip . '</p>';

        }

        $tabContent .= '</div>';

        //$executionTime->end();

        //agile_tix::agile_tix_log_event($executionTime);

        return $tabContent;
    }


    static function add_image_to_media_library_from_uri($image_url)
    {

        //agile_tix::agile_tix_log_event("add_image_to_media_library_from_uri begin");
        //$executionTime = new ExecutionTime('add_image_to_media_library_from_uri');
        //$executionTime->start();

        if (empty($image_url)) {
            return; //new WP_Error('invalid_url', 'The URL is invalid.');
        }

        $exists = agile_tix_post_creator::check_image_exists_in_media_library($image_url);

        //$validatorExists = json_encode($exists);

        //$downURLExists = function_exists("download_url");

        //agile_tix::agile_tix_log_event("add_image_to_media_library_from_uri flag# 1 - " .$exists . " - " . $downURLExists);

        if ($exists == false && function_exists("download_url") && function_exists("media_handle_sideload")) {

            //agile_tix::agile_tix_log_event("add_image_to_media_library_from_uri flag# 1.5");

            $tmp = download_url($image_url);

            if (is_wp_error($tmp)) {
                 agile_tix::agile_tix_log_event("add_image_to_media_library_from_uri" . $tmp->get_error_message() . " - " . $image_url);
                return false;
            }

            // Prepare the file array for media_handle_sideload

            $file_array = array(
                'name' => basename($image_url),
                'tmp_name' => $tmp,
            );

            //agile_tix::agile_tix_log_event("add_image_to_media_library_from_uri flag# 1.7");

            // Upload the image to the media library
            // Double-check function exists before calling (safety check for Action Scheduler context)
            if (!function_exists('media_handle_sideload')) {
                require_once ABSPATH . 'wp-admin/includes/media.php';
            }

            $attachment_id = media_handle_sideload($file_array, 0); // 0 as the parent ID (media library without a specific post)

            //agile_tix::agile_tix_log_event("add_image_to_media_library_from_uri flag# 2");

            if (is_wp_error($attachment_id)) {
                @unlink($file_array['tmp_name']);
                return $attachment_id;
            }

            $attachment_url = wp_get_attachment_url($attachment_id);

            //agile_tix::agile_tix_log_event("add_image_to_media_library_from_uri flag# 3");

            //add the files hash to its meta data so we can more quickly query against it to avoid saving duplicates

            //$image_hash = $image_url;

            //mb_convert_encoding($file_path, 'UTF-8', mb_detect_encoding($file_path, 'UTF-8, ISO-8859-1, ISO-8859-15', true))

            update_post_meta($attachment_id, 'ATS_image_URL', $image_url);

            //$executionTime->end();

            //agile_tix::agile_tix_log_event($executionTime);

            //agile_tix::agile_tix_log_event("add_image_to_media_library_from_uri end exists");

            return array('attachment_id' => $attachment_id, 'url' => $attachment_url);

        } else {
            //$executionTime->end();

            //agile_tix::agile_tix_log_event($executionTime);

            //agile_tix::agile_tix_log_event("add_image_to_media_library_from_uri end else");

            return $exists;//if $exists isnt false, its the img URL
        }

    }


    static function check_image_exists_in_media_library($image_URL)
    {
        global $wpdb;
        // Query the database to check for the file name in the media library
        $query = $wpdb->prepare(
            "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = 'ATS_image_URL' AND meta_value = %s LIMIT 1",
            $image_URL
        );



        $post_id = $wpdb->get_var($query);


        if ($post_id != null) {
            $attachment_url = wp_get_attachment_url($post_id);
            return array('attachment_id' => $post_id, 'url' => $attachment_url);
        }

        return false; // No duplicate found
    }


    static function agile_create_showing_tab_content_showslist($showing)
    {

        //$executionTime = new ExecutionTime('agile_create_showing_tab_content_showslist');

        //$executionTime->start();

        $date = $showing['DisplayDate'] ?? '';

        $Venue = $showing['Venue'] ?? '';

        $LegacyPurchaseLink = $showing['LegacyPurchaseLink'] ?? '';

        $tabContent = '';

        $tabContent .= '<div id="' . $showing['ID'] . '"> '; //class="tabcontent">


        if (!empty($date)) {
            $format_date = date('F j, g:i A', strtotime($date));
            $tabContent .= '<b><p class="agile-tab-subheader" style="font-size: 18px;">' . $format_date . '</p></b>';
        }



        if (!empty($LegacyPurchaseLink)) {
            $tabContent .= '<a class="agileLink" href=' . $LegacyPurchaseLink . '>Buy Tickets</a><br>';
        }

        $tabContent .= '</div>';

        //$executionTime->end();

        //agile_tix::agile_tix_log_event($executionTime);

        return $tabContent;
    }


    static function ats_universal_refresh_showsList($deepRefresh = false)
    {
        //agile_tix::agile_tix_log_event("ats_universal_refresh_showsList start");

        $startTime = microtime(true);

        update_option('agile_field_utility_last_post_scheduled_start', current_time('timestamp'));
        update_option('agile_field_utility_update_status', 'Scheduled');

    
        // Reset counters for chunked processing

        update_option('agile_field_utility_last_post_count_created', 0);

        update_option('agile_field_utility_last_post_count_updated', 0);

        update_option('agile_field_utility_last_post_count_deleated', 0);

        define('WP_IMPORTING', true);
    
        // Content manipulation settings

        $commentStat = get_option('agile_field_comment_status') ?? 'closed';

        $postStat = get_option('agile_field_post_status') ?? 'publish';

        $autoCull = get_option('agile_field_auto_cull') ?? 1;

        $themeType = get_option('agile_field_config_integration_type') ?? 'none';
    
        $transient = agile_tix_data_fetcher::fetch_agile_data();
    
        // Error handling for fetch data
        if (gettype($transient) == "string" && str_contains($transient, "Error")) {
            //agile_tix::agile_tix_log_event("ats_universal_refresh_showsList: fetch_agile_data returned error string: " . $transient);
            update_option('agile_field_utility_update_status', 'Failed');
            return false;
        }

        // Fetch coming soon feed early if enabled (for event ID comparison)
        $comingSoonData = null;
        $comingSoonEventIds = array();
        $useComingSoon = get_option('agile_field_use_coming_soon_feed');
        // agile_tix::agile_tix_log_event("Coming Soon Feed: useComingSoon option = " . ($useComingSoon ? 'true' : 'false'));
        if ($useComingSoon) {
            // agile_tix::agile_tix_log_event("Coming Soon Feed: Fetching coming soon feed data...");
            $comingSoonDataRaw = agile_tix_data_fetcher::fetch_agile_data('coming_soon');
            // agile_tix::agile_tix_log_event("Coming Soon Feed: Fetch result type = " . gettype($comingSoonDataRaw));
            
            // Handle different response types
            if (is_string($comingSoonDataRaw)) {
                // String response indicates an error
                agile_tix::agile_tix_log_event("Coming Soon Feed: Fetch failed or returned error: " . $comingSoonDataRaw);
                $comingSoonData = null;
            } elseif (is_array($comingSoonDataRaw)) {
                // Valid array response - handle empty feeds (missing ArrayOfShows is normal)
                if (!isset($comingSoonDataRaw['ArrayOfShows'])) {
                    // Empty feed - create empty ArrayOfShows array for consistency
                    $comingSoonDataRaw['ArrayOfShows'] = array();
                    // agile_tix::agile_tix_log_event("Coming Soon Feed: Empty feed detected (no ArrayOfShows), treating as valid with 0 events");
                }
                
                $comingSoonData = $comingSoonDataRaw; // Store the data (may have empty ArrayOfShows)
                $totalComingSoonEvents = count($comingSoonData['ArrayOfShows']);
                // agile_tix::agile_tix_log_event("Coming Soon Feed: Found $totalComingSoonEvents total events in feed");
                
                // Create event ID map for comparison (only events with ComingSoonDate)
                foreach ($comingSoonData['ArrayOfShows'] as $comingSoonEvent) {
                    if (isset($comingSoonEvent['ComingSoonDate']) && isset($comingSoonEvent['ID'])) {
                        $comingSoonEventIds[$comingSoonEvent['ID']] = $comingSoonEvent;
                    }
                }
                $eventsWithComingSoonDate = is_array($comingSoonEventIds) ? count($comingSoonEventIds) : 0;
                // agile_tix::agile_tix_log_event("Coming Soon Feed: $eventsWithComingSoonDate events have ComingSoonDate field");
            } else {
                // Unexpected data type
                agile_tix::agile_tix_log_event("Coming Soon Feed: Unexpected data type: " . gettype($comingSoonDataRaw));
                $comingSoonData = null;
            }
        }

        // Determine post type using the shared function
        $postType = agile_tix_post_type::get_configured_post_type();
        
        if (empty($postType)) {
            //agile_tix::agile_tix_log_event("ats_universal_refresh_showsList: no post type configured (themeType = {$themeType}), aborting refresh");
            update_option('agile_field_utility_update_status', 'Failed');
            return false;
        }


        $args = array(
            'post_type' => $postType,
            'posts_per_page' => -1,
            'meta_query' => array(
                array(
                    'key' => 'ATS_EventID',
                    'value' => '',
                    'compare' => '!=',
                ),
            ),
        );


    
        $event_ids = [];
        $main_feed_event_ids_only = []; // Separate list for main feed only (excludes coming soon posts)

        $query = new WP_Query($args);
    
        if ($query->have_posts()) {

            while ($query->have_posts()) {

                $query->the_post();

                $event_id = get_post_meta(get_the_ID(), 'ATS_EventID', true);

                if (!empty($event_id)) {

                    $event_ids[$event_id] = get_the_ID();
                    
                    // Only include in main_feed_event_ids if this post does NOT have ComingSoonDate
                    // This ensures coming soon posts are not incorrectly treated as main feed posts
                    $has_coming_soon_date = get_post_meta(get_the_ID(), 'ATS_ComingSoonDate', true);
                    if (empty($has_coming_soon_date)) {
                        $main_feed_event_ids_only[] = $event_id;
                    }

                }

            }

            wp_reset_postdata();

            wp_reset_query();

        }



        $events = array();

        if (array_key_exists('ArrayOfShows', $transient)) {
            $events = $transient['ArrayOfShows'];
        }



        // Store original events for cleanup purposes
        $original_events = $events;
        
        // Filter events to only include those that need updates or are new
        $filter_result = agile_tix_post_creator::agile_filter_events_for_refresh($events, $event_ids, $deepRefresh);
        $events = $filter_result['filtered_events'];
        $processed_event_ids = $filter_result['processed_event_ids'];

        // Store processing context for chunks

        $processing_context = array(
            'deepRefresh' => $deepRefresh,
            'commentStat' => $commentStat,
            'postStat' => $postStat,
            'themeType' => $themeType,
            'postType' => $postType,
            'event_ids' => $event_ids,
            'processed_event_ids' => $processed_event_ids,
            'autoCull' => $autoCull,
            'startTime' => $startTime,
            'total_events' => count($events),
            'events' => $original_events,
            'comingSoonEventIds' => $comingSoonEventIds,
            'comingSoonData' => $comingSoonData,
            'useComingSoon' => $useComingSoon,
            'main_feed_event_ids' => $main_feed_event_ids_only // Store main feed event IDs only (excludes coming soon posts)
        );
        
        $comingSoonEventIdsCount = is_array($comingSoonEventIds) ? count($comingSoonEventIds) : 0;
        $comingSoonDataType = gettype($comingSoonData);
        // agile_tix::agile_tix_log_event("Main Feed Processing: Storing context - useComingSoon = " . ($useComingSoon ? 'true' : 'false') . ", comingSoonEventIds count = $comingSoonEventIdsCount, comingSoonData type = $comingSoonDataType");
        // agile_tix::agile_tix_log_event("Main Feed Processing: DEBUG - Total event_ids count = $totalEventIdsCount, main_feed_event_ids_only count = $mainFeedEventIdsCount (coming soon posts excluded)");


    
        // Store context temporarily

        update_option('agile_processing_context', $processing_context);





        $chunksize = get_option("agile_chunk_size") ?? 10;

        $chunksize = (int) $chunksize;

        if ($chunksize <= 0) { //incase the user put something weird in the input
            $chunksize = 10;
        }



        $chunks = array_chunk($events, $chunksize);

        $total_chunks = count($chunks);

        // Store chunk tracking
        update_option('agile_total_chunks', $total_chunks);
        update_option('agile_processed_chunks', 0);

        //agile_tix::agile_tix_log_event("ats_universal_refresh_showsList prechunking");


        // Schedule each chunk

        foreach ($chunks as $index => $chunk) {

            // Store chunk data in options table with unique key

            $chunk_key = "agile_chunk_data_" . $index . "_" . uniqid() . "_" . time();

            update_option($chunk_key, $chunk, false); // false = don't autoload
    
            $action_id = as_schedule_single_action(
                time() + ($index * 6), // 6-second intervals between chunks
                'agile_process_events_batch',
                array(
                    'chunk_key' => $chunk_key, // Pass the key instead of data
                    'chunk_index' => $index,
                    'is_final_chunk' => ($index === $total_chunks - 1)
                ),
                'agile_events_processing'
            );


    
            if ($action_id) {
                //agile_tix::agile_tix_log_event("Successfully scheduled chunk $index with ID: $action_id");
            } else {
                agile_tix::agile_tix_log_event("Failed to schedule chunk $index");
                // Clean up the stored chunk data if scheduling failed
                delete_option($chunk_key);
            }

        }



        // If no events to process, handle cleanup immediately

        if (empty($events)) {
            // agile_tix::agile_tix_log_event("ats_universal_refresh_showsList no events to process");
            agile_tix_post_creator::agile_finalize_processing($processing_context);
        }

        return true;
    }



    public function agile_handle_events_batch($chunk_key, $chunk_index, $is_final_chunk)
    {

        //agile_tix::agile_tix_log_event("Args received - chunk_key: $chunk_key, chunk_index: $chunk_index, is_final_chunk: " . ($is_final_chunk ? 'true' : 'false'));

        //agile_tix::agile_tix_log_event("agile_handle_events_batch start");

        //agile_tix::agile_tix_log_event("Args received: " . print_r($args, true));



        // Set active timestamp and status when processing actually begins
        $current_timestamp = current_time('timestamp');
        
        // Set total processing start time only on first chunk (never reset)
        if ($chunk_index === 0) {
            update_option('agile_field_utility_total_processing_start', $current_timestamp);
        }
        
        // Set chunk start time (resets on each chunk)
        update_option('agile_field_utility_last_post_update_start', $current_timestamp);
        update_option('agile_field_utility_update_status', 'Active');


        // Retrieve processing context

        $context = get_option('agile_processing_context');

        if (!$context) {

            //agile_tix::agile_tix_log_event('Batch Handler: Processing context not found for chunk ' . $chunk_index);

            return;

        }



        $deepRefresh = $context['deepRefresh'];
        $commentStat = $context['commentStat'];
        $postStat = $context['postStat'];
        $themeType = $context['themeType'];
        $event_ids = $context['event_ids'];
        $processed_event_ids = $context['processed_event_ids'] ?? [];
        $isComingSoonFeed = $context['isComingSoonFeed'] ?? false;
        // Only enrich with coming soon data if processing main feed
        $comingSoonEventIds = ($isComingSoonFeed) ? array() : ($context['comingSoonEventIds'] ?? array());
        
        // Retrieve chunk data
        $chunk = get_option($chunk_key);
        
        $chunkCount = is_array($chunk) ? count($chunk) : 0;
        agile_tix::agile_tix_log_event("Batch Handler: Processing chunk $chunk_index - isComingSoonFeed = " . ($isComingSoonFeed ? 'true' : 'false') . ", is_final_chunk = " . ($is_final_chunk ? 'true' : 'false') . ", events in chunk = $chunkCount");

        //agile_tix::agile_tix_log_event('Processing context deepRefresh ' . $chunk_index);

        //agile_tix::agile_tix_log_event('Processing context commentStat ' . $commentStat);

        //agile_tix::agile_tix_log_event('Processing context postStat ' . $postStat);

        //agile_tix::agile_tix_log_event('Processing context themeType ' . $themeType);

        //agile_tix::agile_tix_log_event('Processing context event_ids ' . $event_ids);

        // Get user functions if needed

        $functions = [];

        if ($themeType === 'custom') {
            $functions = agile_tix_custom_support::agile_collect_user_functions();
            if ($functions === false) {
                agile_tix::agile_tix_log_event("Batch Handler: agile_collect_user_functions returned false for chunk {$chunk_index}; custom code may be invalid or empty");
                $functions = [];
            }
        }



        // Performance optimizations for this chunk

        wp_suspend_cache_invalidation(true);

        wp_defer_term_counting(true);

        wp_defer_comment_counting(true);

        global $wpdb;

        $wpdb->query('SET autocommit = 0;');



        if (!$chunk || !is_array($chunk)) {
            agile_tix::agile_tix_log_event("Batch Handler: chunk data missing or invalid for key {$chunk_key} (type: " . gettype($chunk) . ")");
            return;
        }

        $chunk_created = 0;
        $chunk_updated = 0;
        
        $chunkCount = is_array($chunk) ? count($chunk) : 0;
        // agile_tix::agile_tix_log_event("Batch Handler: Processing chunk with $chunkCount events (chunk_key: $chunk_key)");


        foreach ($chunk as $event) {
            $eventID = $event['ID'] ?? 'NO_ID';
            $eventName = $event['Name'] ?? 'NO_NAME';
            $hasComingSoonDate = isset($event['ComingSoonDate']) ? 'true' : 'false';
            
            // if ($isComingSoonFeed) {
            //     agile_tix::agile_tix_log_event("Batch Handler (Coming Soon): Processing event $eventID ($eventName) - ComingSoonDate = $hasComingSoonDate");
            // }

            $postID = $event_ids[$event['ID']] ?? 0;

            $isNewEvent = ($postID == 0);
            
            // if ($isComingSoonFeed) {
            //     agile_tix::agile_tix_log_event("Batch Handler (Coming Soon): Event $eventID - isNewEvent = " . ($isNewEvent ? 'true' : 'false') . ", postID = $postID");
            // }
        
            $comingSoonEventData = null;
            if (isset($comingSoonEventIds[$event['ID']])) {
                $comingSoonEventData = $comingSoonEventIds[$event['ID']];
            }
        
            // Remove processed event from event_ids for final cleanup
            // Only remove if this event was actually processed (not skipped)
            if (!$isNewEvent && !isset($processed_event_ids[$event['ID']])) {
                unset($event_ids[$event['ID']]);
            }

            if (!$deepRefresh && !$isNewEvent) {

                $modDate = get_post_meta($postID, 'ATS_ModifiedDate', true);
                $lastModified = $modDate != '' ? $modDate : false;
                $firstEndDate = get_post_meta($postID, 'ATS_firstEndDate', true);
                
                $isComingSoonEvent = isset($event['ComingSoonDate']) && (!isset($event['CurrentShowings']) || empty($event['CurrentShowings']));
                
                // For coming soon events, skip firstIsExpired check (they don't have showings/end dates)
                if ($isComingSoonEvent) {
                    $firstIsExpired = false; // Coming soon events are never "expired" based on showings
                } else {
                    // Add 8 hour wiggle to match filter function logic (covers timezones from LA to NY)
                    $firstDate_timestamp = strtotime($firstEndDate);
                    if ($firstDate_timestamp !== false) {
                        $firstDate_timestamp = $firstDate_timestamp + (8 * 60 * 60);
                    }
                    $current_timestamp = current_time('timestamp');
                    $firstIsExpired = ($firstDate_timestamp !== false && $firstDate_timestamp < $current_timestamp);
                }

                // if ($firstIsExpired && !$isComingSoonEvent) {
                //     agile_tix::agile_tix_log_event("firstIsExpired == true, eventid : " . $event['ID'] . " postid : " . $postID . " firstDate_timestamp : " . ($firstDate_timestamp ?? 'false') . " current_timestamp : " . $current_timestamp);
                // }

                $lastShowings = get_post_meta($postID, 'ATS_showingIDs', true);
                // Ensure lastShowings is an array for proper comparison
                if (!is_array($lastShowings)) {
                    $lastShowings = empty($lastShowings) ? [] : (is_string($lastShowings) ? unserialize($lastShowings) : [$lastShowings]);
                    if (!is_array($lastShowings)) {
                        $lastShowings = [];
                    }
                }

                $currentShowings = [];

                if (isset($event['CurrentShowings']) && is_array($event['CurrentShowings'])) {
                    foreach ($event['CurrentShowings'] as $showing) {
                        array_push($currentShowings, $showing['ID']);
                    }
                }

                // Normalize arrays for comparison (sort and ensure same types)
                sort($lastShowings);
                sort($currentShowings);
                $lastShowings = array_map('strval', $lastShowings);
                $currentShowings = array_map('strval', $currentShowings);
                
                $showings_match = ($lastShowings === $currentShowings);
                $current_most_recent = agile_tix_post_creator::agile_get_most_recent_lastUpdate($event);
                $dates_match = ($lastModified != false && $lastModified == $current_most_recent);
                
                // Always log when a post is NOT being skipped (to identify problematic posts)
                // if (!($showings_match && !$firstIsExpired && $dates_match)) {
                //     $eventName = isset($event['Name']) ? $event['Name'] : 'NO_NAME';
                //     $skip_reasons = array();
                //     
                //     if (!$showings_match) {
                //         $skip_reasons[] = "showings mismatch";
                //     }
                //     if ($firstIsExpired) {
                //         $skip_reasons[] = "first showing expired";
                //     }
                //     if (!$dates_match) {
                //         $skip_reasons[] = "dates mismatch";
                //     }
                //     
                //     $reason_str = !empty($skip_reasons) ? implode(', ', $skip_reasons) : 'unknown';
                //     
                //     agile_tix::agile_tix_log_event("Batch Handler: Event {$event['ID']} ({$eventName}) - Post ID {$postID} NOT SKIPPED - Reason: $reason_str");
                //     agile_tix::agile_tix_log_event("Batch Handler: Event {$event['ID']} - Details: showings_match=" . ($showings_match ? 'true' : 'false') . 
                //         ", firstIsExpired=" . ($firstIsExpired ? 'true' : 'false') . 
                //         ", dates_match=" . ($dates_match ? 'true' : 'false'));
                //     agile_tix::agile_tix_log_event("Batch Handler: Event {$event['ID']} - Date comparison: stored_date='$lastModified' vs current_date='$current_most_recent'");
                //     agile_tix::agile_tix_log_event("Batch Handler: Event {$event['ID']} - Showings comparison: lastShowings=[" . implode(', ', $lastShowings) . "] vs currentShowings=[" . implode(', ', $currentShowings) . "]");
                //     
                //     if ($isComingSoonEvent) {
                //         agile_tix::agile_tix_log_event("Batch Handler: Event {$event['ID']} - Is coming soon event (firstIsExpired check skipped)");
                //     } else {
                //         $firstEndDateDisplay = !empty($firstEndDate) ? $firstEndDate : 'EMPTY';
                //         $firstDateTimestampDisplay = isset($firstDate_timestamp) && $firstDate_timestamp !== false ? date('Y-m-d H:i:s', $firstDate_timestamp) : 'INVALID';
                //         $currentTimestampDisplay = date('Y-m-d H:i:s', $current_timestamp);
                //         agile_tix::agile_tix_log_event("Batch Handler: Event {$event['ID']} - Expiration check: firstEndDate='$firstEndDateDisplay', firstDate_timestamp='$firstDateTimestampDisplay', current_timestamp='$currentTimestampDisplay'");
                //     }
                // }

                if ($showings_match && !$firstIsExpired && $dates_match) {
                    continue;
                }

            }



            //agile_tix::agile_tix_log_event("agile_handle_events_batch themeType" . $themeType);
            // if ($isComingSoonFeed) {
            //     agile_tix::agile_tix_log_event("Batch Handler (Coming Soon): Creating/updating post for event $eventID using themeType = $themeType");
            // }
            
            // Validate themeType - if empty or null, default to 'none'
            if (empty($themeType)) {
                agile_tix::agile_tix_log_event("Batch Handler: themeType is empty, defaulting to 'none' for event $eventID");
                $themeType = 'none';
            }
            
            switch ($themeType) {

                case 'none':
                    agile_tix_post_creator::agile_post_creator($event, $commentStat, $postStat, $isNewEvent, $postID, $comingSoonEventData);
                    // if ($isComingSoonFeed) {
                    //     agile_tix::agile_tix_log_event("Batch Handler (Coming Soon): Called agile_post_creator for event $eventID");
                    // }
                    break;

                case 'event_champ':
                    agile_tix_event_champ_integrate::agile_eventChamp_post_creator($event, $commentStat, $postStat, $isNewEvent, $postID, $comingSoonEventData);
                    break;

                case 'custom':
                    agile_tix_custom_support::agile_user_custom_post_creator($event, $commentStat, $postStat, $isNewEvent, $postID, $functions, $comingSoonEventData);
                    break;

                case 'amy_movie':
                    agile_tix_amy_movie_integrate::agile_amy_movie_post_creator($event, $commentStat, $postStat, $isNewEvent, $postID, $comingSoonEventData);
                    break;

                default:
                    agile_tix::agile_tix_log_event("Batch Handler: ERROR - Unexpected themeType '$themeType' for event $eventID, defaulting to 'none'");
                    // Instead of failing, default to 'none' to allow processing to continue
                    agile_tix_post_creator::agile_post_creator($event, $commentStat, $postStat, $isNewEvent, $postID, $comingSoonEventData);
                    break;

            }



            if ($isNewEvent) {
                $chunk_created++;
            } else {
                $chunk_updated++;
            }

        }


        // Restore performance settings for this chunk
        wp_suspend_cache_invalidation(false);
        wp_defer_term_counting(false);
        wp_defer_comment_counting(false);
        $wpdb->query('SET autocommit = 1;');
        $wpdb->query('COMMIT;');


        // Update counters
        $total_created = get_option('agile_field_utility_last_post_count_created', 0) + $chunk_created;
        $total_updated = get_option('agile_field_utility_last_post_count_updated', 0) + $chunk_updated;
        update_option('agile_field_utility_last_post_count_created', $total_created);
        update_option('agile_field_utility_last_post_count_updated', $total_updated);

        // Update processed chunks counter
        $processed_chunks = get_option('agile_processed_chunks', 0) + 1;
        update_option('agile_processed_chunks', $processed_chunks);



        // Update remaining event_ids in context for cleanup
        $context['event_ids'] = $event_ids;
        update_option('agile_processing_context', $context);
        agile_tix::agile_tix_log_event("Batch Processing: Updated context, isComingSoonFeed = " . (isset($context['isComingSoonFeed']) && $context['isComingSoonFeed'] ? 'true' : 'false'));


        //error_log("Agile Tix: Processed chunk {$chunk_index} - {$chunk_created} created, {$chunk_updated} updated");



        if ($chunk_created >= 0 && $chunk_updated >= 0) { // Processing completed successfully
            delete_option($chunk_key);
            //agile_tix::agile_tix_log_event("Successfully processed and cleaned up chunk: $chunk_key");
        }


        // If this is the final chunk, handle cleanup
        if ($is_final_chunk) {
            $scheduled_time = time() + 20;
            $scheduled_time_str = date('Y-m-d H:i:s', $scheduled_time);
            agile_tix::agile_tix_log_event("Final Chunk: is_final_chunk = true, scheduling finalization in 20 seconds");
            agile_tix::agile_tix_log_event("Final Chunk: DEBUG - Current time: " . current_time('mysql'));
            agile_tix::agile_tix_log_event("Final Chunk: DEBUG - Scheduled for: $scheduled_time_str (timestamp: $scheduled_time)");
            agile_tix::agile_tix_log_event("Final Chunk: isComingSoonFeed = " . ($isComingSoonFeed ? 'true' : 'false'));
            if ($isComingSoonFeed) {
                agile_tix::agile_tix_log_event("Final Chunk: DEBUG - This is coming soon feed, finalization will run culling");
            }
            $finalActionID = as_schedule_single_action(
                $scheduled_time,
                'agile_finalize_processing',
                array(), // Empty args - let the finalizer get context from options
                'agile_events_processing'
            );
            agile_tix::agile_tix_log_event("Final Chunk: Scheduled finalization action with ID: " . ($finalActionID ?: 'FAILED'));
            // agile_tix::agile_tix_log_event("Final Chunk: Scheduled finalization action with ID: " . ($finalActionID ?: 'FAILED'));

            if (!$finalActionID) {
                global $wpdb;
                agile_tix::agile_tix_log_event("DB Error scheduling finalizer: " . $wpdb->last_error);
                
                // Fallback: Try to schedule with longer delay if initial scheduling fails
                // But only if we're sure this is truly the last chunk
                $total_chunks = get_option('agile_total_chunks', 0);
                $processed_chunks = get_option('agile_processed_chunks', 0);
                
                if ($processed_chunks >= $total_chunks) {
                    agile_tix::agile_tix_log_event("Scheduling finalizer failed, attempting with longer delay");
                    // Schedule with a longer delay as fallback
                    $finalActionID = as_schedule_single_action(
                        time() + 60, // Even longer delay as fallback
                        'agile_finalize_processing',
                        array(),
                        'agile_events_processing'
                    );
                }
            } else {
                // agile_tix::agile_tix_log_event("Finalizer scheduled with ID: $finalActionID");
            }
        }
    }



    public static function agile_finalize_processing($context_arg = null)
    {
        agile_tix::agile_tix_log_event("=== FINALIZATION START ===");
        agile_tix::agile_tix_log_event("Finalization: Called with context_arg type = " . gettype($context_arg));

        $context = get_option('agile_processing_context');

        if (!$context) {
            agile_tix::agile_tix_log_event('Finalization: ERROR - Processing context not found for finalization');
            return;
        }
        
        agile_tix::agile_tix_log_event("Finalization: Context retrieved, isComingSoonFeed = " . (isset($context['isComingSoonFeed']) && $context['isComingSoonFeed'] ? 'true' : 'false'));
        agile_tix::agile_tix_log_event("Finalization: Context keys = " . implode(', ', array_keys($context)));
        
        $isComingSoonFeed = isset($context['isComingSoonFeed']) ? $context['isComingSoonFeed'] : false;
        // agile_tix::agile_tix_log_event("Finalization: isComingSoonFeed = " . ($isComingSoonFeed ? 'true' : 'false'));

        // Verify all chunks have been processed before finalizing
        $total_chunks = get_option('agile_total_chunks', 0);
        $processed_chunks = get_option('agile_processed_chunks', 0);
        
        if ($total_chunks > 0 && $processed_chunks < $total_chunks) {
            // agile_tix::agile_tix_log_event(
            //     "Agile Tix: Finalizer called prematurely. Processed: $processed_chunks, Total: $total_chunks. Rescheduling..."
            // );
            
            // Reschedule for later if not all chunks are done
            as_schedule_single_action(
                time() + 30,
                'agile_finalize_processing',
                array(),
                'agile_events_processing'
            );
            return;
        }

        $autoCull = $context['autoCull'];
        $event_ids = $context['event_ids'];
        $processed_event_ids = $context['processed_event_ids'] ?? [];
        $startTime = $context['startTime'];
        $postDeleted = 0;
        
        // agile_tix::agile_tix_log_event("Finalization: autoCull = $autoCull");

        if ($autoCull == 1) {
            $isComingSoonFeed = $context['isComingSoonFeed'] ?? false;
            
            agile_tix::agile_tix_log_event("Finalization: Auto-cull enabled, isComingSoonFeed = " . ($isComingSoonFeed ? 'true' : 'false'));
            agile_tix::agile_tix_log_event("Finalization: autoCull value = " . $autoCull);
            
            if ($isComingSoonFeed) {
                // For coming soon feed cleanup, only delete posts that:
                // 1. Have ComingSoonDate (to identify coming soon posts)
                // 2. Are not in the current coming soon feed
                // Note: We don't delete main feed posts even if they have ComingSoonDate
                agile_tix::agile_tix_log_event("=== Auto-Cull (Coming Soon): Starting cleanup for coming soon feed ===");
                agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): DEBUG - Current timestamp: " . current_time('mysql'));
                $postType = isset($context['postType']) ? $context['postType'] : 'post';
                agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): DEBUG - Post type being queried: " . $postType);
                // Get ALL event IDs from the current coming soon feed response FIRST
                // This is the authoritative list for culling - if an event ID is not here, delete the post
                $current_feed_event_ids = isset($context['all_coming_soon_feed_event_ids']) && is_array($context['all_coming_soon_feed_event_ids']) 
                    ? $context['all_coming_soon_feed_event_ids'] 
                    : [];
                
                // Ensure it's always an array
                if (!is_array($current_feed_event_ids)) {
                    $current_feed_event_ids = [];
                }
                
                agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Event IDs in current feed: " . (empty($current_feed_event_ids) ? 'NONE' : implode(', ', $current_feed_event_ids)));
                agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Total event IDs in feed: " . count($current_feed_event_ids));
                
                // Query for posts with ComingSoonDate (primary query)
                $all_existing_posts = get_posts([
                    'post_type' => $postType,
                    'posts_per_page' => -1,
                    'meta_query' => [
                        [
                            'key' => 'ATS_EventID',
                            'value' => '',
                            'compare' => '!=',
                        ],
                        [
                            'key' => 'ATS_ComingSoonDate',
                            'compare' => 'EXISTS',
                        ],
                    ],
                ]);
                
                // Also query for posts that might have lost ComingSoonDate but were previously coming soon
                // Check if there are any posts with event IDs that were in previous coming soon feeds
                // but are not in the current feed and not in the main feed
                $posts_without_coming_soon_date = array();
                if (!empty($current_feed_event_ids)) {
                    // Get all posts with event IDs (we'll filter by event ID later)
                    $all_posts_by_event = get_posts([
                        'post_type' => $postType,
                        'posts_per_page' => -1,
                        'meta_query' => [
                            [
                                'key' => 'ATS_EventID',
                                'value' => '',
                                'compare' => '!=',
                            ],
                        ],
                    ]);
                    
                    // Check each post to see if it has an event ID that was previously coming soon
                    // but is no longer in the current feed
                    foreach ($all_posts_by_event as $post) {
                        $post_event_id = get_post_meta($post->ID, 'ATS_EventID', true);
                        $post_event_id_str = (string)$post_event_id;
                        $has_coming_soon_date = get_post_meta($post->ID, 'ATS_ComingSoonDate', true);
                        
                        // If this post doesn't have ComingSoonDate but we want to check if it should be deleted
                        // We'll handle this in the main culling loop by checking against current_feed_event_ids
                        // For now, just collect posts without ComingSoonDate that might need checking
                        if (empty($has_coming_soon_date) && !empty($post_event_id_str)) {
                            // Store for potential deletion check (only if not in main feed)
                            $posts_without_coming_soon_date[] = $post;
                        }
                    }
                }
                
                $existingPostsCount = is_array($all_existing_posts) ? count($all_existing_posts) : 0;
                $postsWithoutMetaCount = is_array($posts_without_coming_soon_date) ? count($posts_without_coming_soon_date) : 0;
                agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Found $existingPostsCount existing posts with ComingSoonDate");
                agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Found $postsWithoutMetaCount posts without ComingSoonDate to check");
                
                // Log all existing coming soon posts
                foreach ($all_existing_posts as $post) {
                    $post_event_id = get_post_meta($post->ID, 'ATS_EventID', true);
                    $coming_soon_date = get_post_meta($post->ID, 'ATS_ComingSoonDate', true);
                    agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Existing post ID {$post->ID}, Event ID: $post_event_id, ComingSoonDate: $coming_soon_date");
                }
                
                $main_feed_event_ids_stored = isset($context['main_feed_event_ids']) ? $context['main_feed_event_ids'] : array();
                $main_feed_event_ids = array_map('strval', $main_feed_event_ids_stored);
                
                // Merge posts with and without ComingSoonDate for comprehensive culling
                // This catches posts that lost their ComingSoonDate meta when transitioning to "now showing"
                $all_posts_to_check = $all_existing_posts;
                foreach ($posts_without_coming_soon_date as $post) {
                    $post_event_id = get_post_meta($post->ID, 'ATS_EventID', true);
                    $post_event_id_str = (string)$post_event_id;
                    
                    // Only include if:
                    // 1. The event ID is not in the current coming soon feed (should be deleted)
                    // 2. The event ID is not in the main feed (not a main feed post)
                    if (!empty($post_event_id_str) && 
                        !in_array($post_event_id_str, $current_feed_event_ids, true) &&
                        !in_array($post_event_id_str, $main_feed_event_ids, true)) {
                        // This post might have been a coming soon post that lost its meta
                        // Add it to the list for culling check
                        $all_posts_to_check[] = $post;
                        // agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Including post ID {$post->ID} (event ID $post_event_id_str) without ComingSoonDate for culling check");
                    }
                }
                
                // Only protect posts that were actually processed/created in this run
                // This includes events from filtered_events (newly created/updated) and
                // events from processed_event_ids that are ALSO in the current feed
                $just_processed_event_ids = array();
                if (isset($context['filtered_events']) && is_array($context['filtered_events'])) {
                    foreach ($context['filtered_events'] as $event) {
                        if (isset($event['ID'])) {
                            $just_processed_event_ids[] = (string)$event['ID'];
                        }
                    }
                }
                // Only add processed_event_ids that are in the current feed
                // This protects posts that were just updated (not just existing ones)
                if (isset($context['processed_event_ids']) && is_array($context['processed_event_ids']) && is_array($current_feed_event_ids)) {
                    foreach ($context['processed_event_ids'] as $event_id => $post_id) {
                        $event_id_str = (string)$event_id;
                        // Only protect if it's in the current feed (was actually processed this run)
                        if (in_array($event_id_str, $current_feed_event_ids, true)) {
                            $just_processed_event_ids[] = $event_id_str;
                        }
                    }
                }
                $just_processed_event_ids = array_unique($just_processed_event_ids);
                $protected_ids_str = empty($just_processed_event_ids) ? 'NONE' : implode(', ', $just_processed_event_ids);
                agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Protecting " . count($just_processed_event_ids) . " just-processed event IDs: " . $protected_ids_str);
                
                // First, detect and handle duplicate posts (multiple posts with same event ID)
                $event_id_to_posts = array();
                foreach ($all_posts_to_check as $post) {
                    $post_event_id = get_post_meta($post->ID, 'ATS_EventID', true);
                    $post_event_id_str = (string)$post_event_id;
                    if (!empty($post_event_id_str)) {
                        if (!isset($event_id_to_posts[$post_event_id_str])) {
                            $event_id_to_posts[$post_event_id_str] = array();
                        }
                        $event_id_to_posts[$post_event_id_str][] = $post;
                    }
                }
                
                // Remove duplicates: for each event ID with multiple posts, keep one and delete the rest
                $duplicates_deleted = 0;
                foreach ($event_id_to_posts as $event_id_str => $posts_with_same_id) {
                    if (count($posts_with_same_id) > 1) {
                        agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Found " . count($posts_with_same_id) . " duplicate posts for event ID $event_id_str");
                        
                        // Determine which post to keep

                        $post_to_keep = null;
                        $posts_to_delete = array();
                        
                        // First, try to find a post that was just processed
                        if (isset($context['processed_event_ids']) && is_array($context['processed_event_ids'])) {
                            foreach ($context['processed_event_ids'] as $proc_event_id => $proc_post_id) {
                                if ((string)$proc_event_id === $event_id_str) {
                                    // Found a processed post for this event ID - find it in our list
                                    foreach ($posts_with_same_id as $post) {
                                        if ($post->ID == $proc_post_id) {
                                            $post_to_keep = $post;
                                            break 2; // Break out of both loops
                                        }
                                    }
                                }
                            }
                        }
                        
                        // If no processed post found, keep the most recently modified one
                        if ($post_to_keep === null) {
                            foreach ($posts_with_same_id as $post) {
                                if ($post_to_keep === null) {
                                    $post_to_keep = $post;
                                } else {
                                    // Compare modification dates - keep the most recent
                                    $keep_date = strtotime($post_to_keep->post_modified);
                                    $this_date = strtotime($post->post_modified);
                                    if ($this_date > $keep_date) {
                                        $posts_to_delete[] = $post_to_keep;
                                        $post_to_keep = $post;
                                    } else {
                                        $posts_to_delete[] = $post;
                                    }
                                }
                            }
                        } else {
                            // We found a processed post, mark all others for deletion
                            foreach ($posts_with_same_id as $post) {
                                if ($post->ID !== $post_to_keep->ID) {
                                    $posts_to_delete[] = $post;
                                }
                            }
                        }
                        
                        // Delete all duplicate posts except the one we're keeping
                        if ($post_to_keep !== null) {
                            agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Keeping post ID {$post_to_keep->ID} for event ID $event_id_str, deleting " . count($posts_to_delete) . " duplicates");
                            foreach ($posts_to_delete as $duplicate_post) {
                                agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): DELETING duplicate post ID {$duplicate_post->ID} (event ID $event_id_str)");
                                $mediaID = get_post_meta($duplicate_post->ID, 'ATS_MediaLib_Img_ID', true);
                                if (!empty($mediaID) && is_numeric($mediaID) && $mediaID > 0) {
                                    wp_delete_post((int)$mediaID, true);
                                }
                                wp_delete_post($duplicate_post->ID, true);
                                $duplicates_deleted++;
                                $postDeleted++;
                                
                                // Remove from all_posts_to_check array so it's not processed again
                                $all_posts_to_check = array_filter($all_posts_to_check, function($p) use ($duplicate_post) {
                                    return $p->ID !== $duplicate_post->ID;
                                });
                                $all_posts_to_check = array_values($all_posts_to_check); // Re-index
                            }
                        }
                    }
                }
                
                if ($duplicates_deleted > 0) {
                    agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Removed $duplicates_deleted duplicate posts");
                }
                
                foreach ($all_posts_to_check as $post) {
                    $post_event_id = get_post_meta($post->ID, 'ATS_EventID', true);
                    $post_event_id_str = (string)$post_event_id;
                    
                    // Skip if this is a main feed post (has event ID in main feed list)
                    if (in_array($post_event_id_str, $main_feed_event_ids, true)) {
                        agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): SKIPPING post ID {$post->ID} (event ID $post_event_id_str) - is a main feed post");
                        continue;
                    }
                    
                    agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Checking post ID {$post->ID}, Event ID: $post_event_id_str");
                    
                    // Skip if this post was just processed in this run
                    if (in_array($post_event_id_str, $just_processed_event_ids, true)) {
                        agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): KEEPING post ID {$post->ID} (event ID $post_event_id_str) - was just processed");
                        continue;
                    }
                    
                    // Check if this event ID is in the current coming soon feed response
                    // Compare against ALL event IDs from the feed, not just filtered ones
                    $isInFeed = is_array($current_feed_event_ids) && in_array($post_event_id_str, $current_feed_event_ids, true);
                    
                    agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Post ID {$post->ID} (event ID $post_event_id_str) - isInFeed: " . ($isInFeed ? 'YES' : 'NO'));
                    
                    // If not in coming soon feed, delete the coming soon post
                    // This handles cases where:
                    // 1. Event transitioned from coming soon to now showing (no longer in coming soon feed)
                    // 2. Event was removed from coming soon feed entirely
                    // Note: Even if the event is now in the main feed (now showing), we still delete
                    // the old coming soon post because the main feed will have its own post
                    if (!$isInFeed) {
                        agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): DELETING post ID {$post->ID} (event ID $post_event_id_str) - not in current coming soon feed");
                        $mediaID = get_post_meta($post->ID, 'ATS_MediaLib_Img_ID', true);
                        
                        if (!empty($mediaID) && is_numeric($mediaID) && $mediaID > 0) {
                            wp_delete_post((int)$mediaID, true);
                        }
                        
                        wp_delete_post($post->ID, true);
                        $postDeleted++;
                    } else {
                        agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): KEEPING post ID {$post->ID} (event ID $post_event_id_str) - found in feed");
                    }
                }
                $total_posts_checked = count($all_posts_to_check);
                agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): ==== CULLING COMPLETE ====");
                agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Total posts checked: " . $total_posts_checked);
                agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Total posts deleted: $postDeleted");
                agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): Posts kept: " . ($total_posts_checked - $postDeleted));
                agile_tix::agile_tix_log_event("Auto-Cull (Coming Soon): ==== END CULLING ====");
            } else {
                // Main feed cleanup
                // IMPORTANT: Exclude coming soon posts from main feed culling
                // Coming soon posts are managed by their own culling logic
                $all_existing_posts = get_posts([
                    'post_type' => $context['postType'],
                    'posts_per_page' => -1,
                    'meta_query' => [
                        [
                            'key' => 'ATS_EventID',
                            'value' => '',
                            'compare' => '!=',
                        ],
                        [
                            'key' => 'ATS_ComingSoonDate',
                            'compare' => 'NOT EXISTS', // Exclude coming soon posts
                        ],
                    ],
                ]);
                
                $existingPostsCount = is_array($all_existing_posts) ? count($all_existing_posts) : 0;
                // agile_tix::agile_tix_log_event("Auto-Cull (Main Feed): Found $existingPostsCount existing main feed posts (coming soon posts excluded)");
                
                $current_feed_event_ids = [];
                
                foreach ($context['events'] ?? [] as $event) {
                    if (isset($event['ID'])) {
                        $event_id_str = (string)$event['ID'];
                        if (!in_array($event_id_str, $current_feed_event_ids, true)) {
                            $current_feed_event_ids[] = $event_id_str;
                        }
                    }
                }
                
                foreach ($context['filtered_events'] ?? [] as $event) {
                    if (isset($event['ID'])) {
                        $event_id_str = (string)$event['ID'];
                        if (!in_array($event_id_str, $current_feed_event_ids, true)) {
                            $current_feed_event_ids[] = $event_id_str;
                        }
                    }
                }
                $processedEventIds = isset($context['processed_event_ids']) && is_array($context['processed_event_ids']) ? $context['processed_event_ids'] : [];
                foreach ($processedEventIds as $event_id => $post_id) {
                    $event_id_str = (string)$event_id;
                    if (!in_array($event_id_str, $current_feed_event_ids, true)) {
                        $current_feed_event_ids[] = $event_id_str;
                    }
                }
                
                // agile_tix::agile_tix_log_event("Auto-Cull (Main Feed): DEBUG - Built current_feed_event_ids from: events=" . count($context['events'] ?? []) . ", filtered_events=" . count($context['filtered_events'] ?? []) . ", processed_event_ids=" . count($processedEventIds) . ", total=" . count($current_feed_event_ids));
                
                $feedEventIdsCount = is_array($current_feed_event_ids) ? count($current_feed_event_ids) : 0;
                // agile_tix::agile_tix_log_event("Auto-Cull (Main Feed): Current feed has $feedEventIdsCount event IDs");
                
                $just_processed_event_ids = array();
                if (isset($context['filtered_events']) && is_array($context['filtered_events'])) {
                    foreach ($context['filtered_events'] as $event) {
                        if (isset($event['ID'])) {
                            $just_processed_event_ids[] = (string)$event['ID'];
                        }
                    }
                }
                if (isset($context['processed_event_ids']) && is_array($context['processed_event_ids'])) {
                    foreach ($context['processed_event_ids'] as $event_id => $post_id) {
                        $just_processed_event_ids[] = (string)$event_id;
                    }
                }
                $just_processed_event_ids = array_unique($just_processed_event_ids);
                // agile_tix::agile_tix_log_event("Auto-Cull (Main Feed): Protecting " . count($just_processed_event_ids) . " just-processed event IDs from deletion");
                
                // Find posts for events that are no longer in the feed
                foreach ($all_existing_posts as $post) {
                    $post_event_id = get_post_meta($post->ID, 'ATS_EventID', true);
                    $post_event_id_str = (string)$post_event_id;
                    
                    // Double-check: Skip if this is a coming soon post (shouldn't happen due to query, but safety check)
                    $has_coming_soon_date = get_post_meta($post->ID, 'ATS_ComingSoonDate', true);
                    if (!empty($has_coming_soon_date)) {
                        // agile_tix::agile_tix_log_event("Auto-Cull (Main Feed): SKIP post ID {$post->ID} (event ID $post_event_id_str) - has ComingSoonDate (should not be in query)");
                        continue;
                    }
                    
                    if (in_array($post_event_id_str, $just_processed_event_ids, true)) {
                        // agile_tix::agile_tix_log_event("Auto-Cull (Main Feed): PROTECTING post ID {$post->ID} (event ID $post_event_id_str) - was just processed");
                        continue;
                    }
                    
                    if (!in_array($post_event_id_str, $current_feed_event_ids, true)) {
                        // agile_tix::agile_tix_log_event("Auto-Cull (Main Feed): Deleting post ID {$post->ID} (event ID $post_event_id_str) - not in current main feed");
                        $mediaID = get_post_meta($post->ID, 'ATS_MediaLib_Img_ID', true);
                        
                        if (!empty($mediaID) && is_numeric($mediaID) && $mediaID > 0) {
                            wp_delete_post((int)$mediaID, true);
                        }
                        
                        wp_delete_post($post->ID, true);
                        $postDeleted++;
                    }
                }
                // agile_tix::agile_tix_log_event("Auto-Cull (Main Feed): Deleted $postDeleted main feed posts");
            }
        }


        // Update final statistics
        update_option('agile_field_utility_last_post_count_deleated', $postDeleted);
    
        // Calculate runtime
        $endTime = microtime(true);
        update_option('agile_field_utility_last_known_runtime', ($endTime - $startTime));
        update_option('agile_field_utility_last_post_update', current_time('timestamp'));


        // Check if coming soon feed needs to be processed (only for main feed, not coming soon feed itself)
        $isComingSoonFeed = $context['isComingSoonFeed'] ?? false;
        
        agile_tix::agile_tix_log_event("Finalization: Context retrieved, isComingSoonFeed = " . ($isComingSoonFeed ? 'true' : 'false'));
        
        // If this is coming soon feed finalization, verify posts exist
        if ($isComingSoonFeed) {
            agile_tix::agile_tix_log_event("=== Coming Soon Feed Finalization ===");
            // agile_tix::agile_tix_log_event("Coming Soon Feed Finalization: Verifying created posts exist");
            $verify_args = array(
                'post_type' => $context['postType'],
                'posts_per_page' => -1,
                'post_status' => 'any', // Check all statuses
                'meta_query' => array(
                    array(
                        'key' => 'ATS_ComingSoonDate',
                        'compare' => 'EXISTS',
                    ),
                ),
            );
            $verify_query = new WP_Query($verify_args);
            $found_posts = array();
            if ($verify_query->have_posts()) {
                while ($verify_query->have_posts()) {
                    $verify_query->the_post();
                    $post_id = get_the_ID();
                    $event_id = get_post_meta($post_id, 'ATS_EventID', true);
                    $coming_soon_date = get_post_meta($post_id, 'ATS_ComingSoonDate', true);
                    $post_status = get_post_status($post_id);
                    $post_title = get_the_title($post_id);
                    $found_posts[] = array(
                        'ID' => $post_id,
                        'Title' => $post_title,
                        'EventID' => $event_id,
                        'Status' => $post_status,
                        'ComingSoonDate' => $coming_soon_date
                    );
                }
                wp_reset_postdata();
                wp_reset_query();
            }
            $found_count = count($found_posts);
            // agile_tix::agile_tix_log_event("Coming Soon Feed Finalization: Found $found_count posts with ComingSoonDate meta");
            // foreach ($found_posts as $post_info) {
            //     agile_tix::agile_tix_log_event("Coming Soon Feed Finalization: Post ID {$post_info['ID']} - '{$post_info['Title']}' (EventID: {$post_info['EventID']}, Status: {$post_info['Status']}, ComingSoonDate: {$post_info['ComingSoonDate']})");
            // }
        }
        
        if (!$isComingSoonFeed) {
            // This is main feed finalization - check if coming soon feed needs processing
            $useComingSoon = $context['useComingSoon'] ?? false;
            $comingSoonData = $context['comingSoonData'] ?? null;
            $comingSoonEventIds = $context['comingSoonEventIds'] ?? array();
            
            // Get variables from context for coming soon feed processing
            $comingSoonPostType = $context['postType'];
            $comingSoonThemeType = $context['themeType'];
            $comingSoonCommentStat = $context['commentStat'];
            $comingSoonPostStat = $context['postStat'];
            $comingSoonDeepRefresh = $context['deepRefresh'];
            $comingSoonAutoCull = $context['autoCull'];
            $comingSoonStartTime = $context['startTime'];
            $main_feed_event_ids_from_context = $context['main_feed_event_ids'] ?? array();
            
            // Clean up temporary options before processing coming soon (to avoid conflicts)
            delete_option('agile_processing_context');
            delete_option('agile_total_chunks');
            delete_option('agile_processed_chunks');
            
            // Process coming soon feed if enabled and data is available
            // agile_tix::agile_tix_log_event("Main Feed Finalization: Checking if coming soon feed should be processed");
            // agile_tix::agile_tix_log_event("Main Feed Finalization: useComingSoon = " . ($useComingSoon ? 'true' : 'false'));
            // agile_tix::agile_tix_log_event("Main Feed Finalization: comingSoonData type = " . gettype($comingSoonData));
            if ($useComingSoon && $comingSoonData && gettype($comingSoonData) != "string" && isset($comingSoonData['ArrayOfShows'])) {
                // agile_tix::agile_tix_log_event("Main Feed Finalization: Triggering coming soon feed processing");
                update_option('agile_field_utility_update_status', 'Processing Coming Soon Feed');
                agile_tix_post_creator::process_coming_soon_feed(
                    $comingSoonData,
                    $comingSoonEventIds,
                    $comingSoonPostType,
                    $comingSoonThemeType,
                    $comingSoonCommentStat,
                    $comingSoonPostStat,
                    $comingSoonDeepRefresh,
                    $comingSoonAutoCull,
                    $comingSoonStartTime,
                    $main_feed_event_ids_from_context
                );
                // Don't clean up context yet - coming soon feed will use it
                // agile_tix::agile_tix_log_event("Main Feed Finalization: Coming soon feed processing initiated, exiting");
                return; // Exit early - coming soon feed will finalize later
            } elseif ($useComingSoon && $comingSoonData && gettype($comingSoonData) != "string" && !isset($comingSoonData['ArrayOfShows'])) {
                agile_tix::agile_tix_log_event("Main Feed Finalization: Coming soon feed data is missing ArrayOfShows key. Data structure may be invalid.");
            }
        }
        
        // Clean up temporary options (for coming soon feed finalization or main feed without coming soon)
        delete_option('agile_processing_context');
        delete_option('agile_total_chunks');
        delete_option('agile_processed_chunks');
        
        // Set status to Idle
        update_option('agile_field_utility_update_status', 'Idle');
        
        //error_log('Agile Tix: Processing completed - ' . $postDeleted . ' posts deleted');
    }

    /**
     * Process coming soon feed events
     * Only processes events that don't exist in main feed
     */
    public static function process_coming_soon_feed($comingSoonData, $comingSoonEventIds, $postType, $themeType, $commentStat, $postStat, $deepRefresh, $autoCull, $startTime, $main_feed_event_ids_from_context = array())
    {
        // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Starting process_coming_soon_feed()");
        // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: postType = $postType, themeType = $themeType");
        
        if (!isset($comingSoonData['ArrayOfShows'])) {
            agile_tix::agile_tix_log_event("Coming Soon Feed Processing: ERROR - ArrayOfShows not found in comingSoonData");
            return;
        }
        
        $totalEventsInFeed = (isset($comingSoonData['ArrayOfShows']) && is_array($comingSoonData['ArrayOfShows'])) ? count($comingSoonData['ArrayOfShows']) : 0;
        // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Total events in feed = $totalEventsInFeed");

        // Use stored main feed event IDs from context instead of querying database
        // Convert to event_id => true mapping for efficient lookup (post_id not needed for filtering)
        $main_feed_event_ids = array();
        if (!empty($main_feed_event_ids_from_context)) {
            foreach ($main_feed_event_ids_from_context as $event_id) {
                $main_feed_event_ids[$event_id] = true; // Use boolean for efficient isset() checks
            }
        }
        $mainFeedCount = is_array($main_feed_event_ids) ? count($main_feed_event_ids) : 0;
        $storedCount = is_array($main_feed_event_ids_from_context) ? count($main_feed_event_ids_from_context) : 0;
        // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Using $storedCount stored main feed event IDs (no database query needed)");

        // First, collect ALL event IDs from the coming soon feed response for culling comparison
        $all_coming_soon_feed_event_ids = array();
        foreach ($comingSoonData['ArrayOfShows'] as $event) {
            if (isset($event['ID'])) {
                $all_coming_soon_feed_event_ids[] = (string)$event['ID'];
            }
        }
        agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Collected " . count($all_coming_soon_feed_event_ids) . " event IDs from feed: " . implode(', ', $all_coming_soon_feed_event_ids));
        
        // Filter coming soon events: must have ComingSoonDate and not exist as a main feed post
        // Check database for existing posts with this event ID (not just the current refresh list)
        $comingSoonEvents = array();
        $skippedNoComingSoonDate = 0;
        $skippedInMainFeed = 0;
        foreach ($comingSoonData['ArrayOfShows'] as $event) {
            $eventID = $event['ID'] ?? 'NO_ID';
            $eventName = $event['Name'] ?? 'NO_NAME';
            
            // Only process events with ComingSoonDate
            if (!isset($event['ComingSoonDate'])) {
                $skippedNoComingSoonDate++;
                // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Skipping event $eventID ($eventName) - no ComingSoonDate field");
                continue;
            }
            
            $existing_post = get_posts(array(
                'post_type' => $postType,
                'posts_per_page' => 1,
                'meta_query' => array(
                    array(
                        'key' => 'ATS_EventID',
                        'value' => (string)$eventID,
                        'compare' => '=',
                    ),
                ),
            ));
            
            if (!empty($existing_post)) {
                $found_post_id = $existing_post[0]->ID;
                $has_coming_soon_date = get_post_meta($found_post_id, 'ATS_ComingSoonDate', true);
                
                if (empty($has_coming_soon_date)) {
                    $skippedInMainFeed++;
                    // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Skipping event $eventID ($eventName) - already exists as main feed post (post ID: $found_post_id)");
                    continue;
                }
            } else {
                $is_in_main_feed_list = isset($main_feed_event_ids[$event['ID']]);
                if ($is_in_main_feed_list) {
                    $skippedInMainFeed++;
                    // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Skipping event $eventID ($eventName) - in main feed list (post may be processing)");
                    continue;
                }
            }
            
            $comingSoonEvents[] = $event;
        }

        $comingSoonEventsCount = is_array($comingSoonEvents) ? count($comingSoonEvents) : 0;
        // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Filtered results - $comingSoonEventsCount events to process, $skippedNoComingSoonDate skipped (no ComingSoonDate), $skippedInMainFeed skipped (in main feed)");

        // Get existing coming soon posts (exclude those that are in main feed)
        // Note: We need to do this even if $comingSoonEvents is empty, so culling can run to delete posts that fell off the feed
        $coming_soon_event_ids = array();
        $coming_soon_args = array(
            'post_type' => $postType,
            'posts_per_page' => -1,
            'meta_query' => array(
                array(
                    'key' => 'ATS_EventID',
                    'value' => '',
                    'compare' => '!=',
                ),
                array(
                    'key' => 'ATS_ComingSoonDate',
                    'compare' => 'EXISTS',
                ),
            ),
        );

        $coming_soon_query = new WP_Query($coming_soon_args);
        if ($coming_soon_query->have_posts()) {
            while ($coming_soon_query->have_posts()) {
                $coming_soon_query->the_post();
                $event_id = get_post_meta(get_the_ID(), 'ATS_EventID', true);
                if (!empty($event_id)) {
                    // Only include if not in main feed (to avoid treating enriched main feed posts as coming soon posts)
                    if (!isset($main_feed_event_ids[$event_id])) {
                        $coming_soon_event_ids[$event_id] = get_the_ID();
                    }
                }
            }
            wp_reset_postdata();
            wp_reset_query();
        }
        $existingComingSoonCount = is_array($coming_soon_event_ids) ? count($coming_soon_event_ids) : 0;
        // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Found $existingComingSoonCount existing coming soon posts");

        // Filter events that need updates
        // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Filtering events for refresh (deepRefresh = " . ($deepRefresh ? 'true' : 'false') . ")");
        $filter_result = agile_tix_post_creator::agile_filter_events_for_refresh($comingSoonEvents, $coming_soon_event_ids, $deepRefresh);
        $filtered_coming_soon_events = isset($filter_result['filtered_events']) && is_array($filter_result['filtered_events']) ? $filter_result['filtered_events'] : [];
        $processed_coming_soon_event_ids = isset($filter_result['processed_event_ids']) && is_array($filter_result['processed_event_ids']) ? $filter_result['processed_event_ids'] : [];
        $filteredCount = count($filtered_coming_soon_events);
        // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: After refresh filter - $filteredCount events need processing");

        // Store processing context for coming soon feed
        // Store both filtered events (for processing) and all events (for culling)
        $coming_soon_context = array(
            'deepRefresh' => $deepRefresh,
            'commentStat' => $commentStat,
            'postStat' => $postStat,
            'themeType' => $themeType,
            'postType' => $postType,
            'event_ids' => $coming_soon_event_ids,
            'processed_event_ids' => $processed_coming_soon_event_ids,
            'autoCull' => $autoCull,
            'startTime' => $startTime,
            'total_events' => $filteredCount,
            'events' => $comingSoonEvents, // Filtered coming soon events (for processing)
            'filtered_events' => $filtered_coming_soon_events, // Only events that need processing
            'isComingSoonFeed' => true,
            'main_feed_event_ids' => $main_feed_event_ids_from_context, // Store for culling
            'all_coming_soon_feed_event_ids' => $all_coming_soon_feed_event_ids // ALL event IDs from feed response (for culling comparison)
        );

        update_option('agile_processing_context', $coming_soon_context);
        agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Stored context at " . current_time('mysql'));
        agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Context isComingSoonFeed = " . ($coming_soon_context['isComingSoonFeed'] ? 'true' : 'false'));
        agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Context all_coming_soon_feed_event_ids count = " . (isset($coming_soon_context['all_coming_soon_feed_event_ids']) ? count($coming_soon_context['all_coming_soon_feed_event_ids']) : 0));
        // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: DEBUG - Context['events'] count: " . (isset($coming_soon_context['events']) ? count($coming_soon_context['events']) : 0));
        // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: DEBUG - Context['filtered_events'] count: " . (isset($coming_soon_context['filtered_events']) ? count($coming_soon_context['filtered_events']) : 0));
        // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: DEBUG - Context['processed_event_ids'] count: " . (isset($coming_soon_context['processed_event_ids']) ? count($coming_soon_context['processed_event_ids']) : 0));
        // if (isset($coming_soon_context['events']) && is_array($coming_soon_context['events'])) {
        //     $event_ids_in_context = array();
        //     foreach ($coming_soon_context['events'] as $event) {
        //         if (isset($event['ID'])) {
        //             $event_ids_in_context[] = (string)$event['ID'];
        //         }
        //     }
        //     agile_tix::agile_tix_log_event("Coming Soon Feed Processing: DEBUG - Event IDs in context['events']: " . implode(', ', $event_ids_in_context));
        // }

        // Process in chunks
        $chunksize = get_option("agile_chunk_size") ?? 10;
        $chunksize = (int) $chunksize;
        if ($chunksize <= 0) {
            $chunksize = 10;
        }

        $chunks = is_array($filtered_coming_soon_events) ? array_chunk($filtered_coming_soon_events, $chunksize) : [];
        $total_chunks = is_array($chunks) ? count($chunks) : 0;

        // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Chunking $filteredCount events into $total_chunks chunks (chunk size = $chunksize)");

        update_option('agile_total_chunks', $total_chunks);
        update_option('agile_processed_chunks', 0);

        // If there are no events to process, still schedule finalization for culling
        // This ensures posts that fell off the feed get deleted
        if ($total_chunks === 0) {
            $scheduled_time = time() + 1;
            as_schedule_single_action(
                $scheduled_time,
                'agile_finalize_processing',
                array(),
                'agile_events_processing'
            );
            return; // No events to process, but culling will run
        }

        // Schedule each chunk
        $scheduledChunks = 0;
        foreach ($chunks as $index => $chunk) {
            $chunk_key = "agile_chunk_data_" . $index . "_" . uniqid() . "_" . time();
            update_option($chunk_key, $chunk, false);
            $chunkEventCount = is_array($chunk) ? count($chunk) : 0;
            // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Scheduling chunk $index with $chunkEventCount events (chunk_key: $chunk_key)");
    
            $action_id = as_schedule_single_action(
                time() + ($index * 6),
                'agile_process_events_batch',
                array(
                    'chunk_key' => $chunk_key,
                    'chunk_index' => $index,
                    'is_final_chunk' => ($index === $total_chunks - 1)
                ),
                'agile_events_processing'
            );

            if (!$action_id) {
                agile_tix::agile_tix_log_event("Coming Soon Feed Processing: ERROR - Failed to schedule chunk $index");
                delete_option($chunk_key);
            } else {
                $scheduledChunks++;
                // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Successfully scheduled chunk $index (action_id: $action_id)");
            }
        }
        
        // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: Scheduled $scheduledChunks of $total_chunks chunks");

        // If no events to process, handle cleanup immediately
        if (empty($filtered_coming_soon_events)) {
            // agile_tix::agile_tix_log_event("Coming Soon Feed Processing: No events to process, calling finalization immediately");
            agile_tix_post_creator::agile_finalize_processing($coming_soon_context);
        }
    }

    /**

     * Creates a single post of the agile post type

     * @param mixed $event

     * @param string $commentStat (closed or open)

     * @param string $postStat (draft or publish)

     * @param bool $isNewEvent

     * @param int $postID

     */

    static function agile_post_creator($event, $commentStat, $postStat, $isNewEvent, $postID, $comingSoonEventData = null)
    {
        $eventID = $event['ID'] ?? 'NO_ID';
        $eventName = $event['Name'] ?? 'NO_NAME';
        // agile_tix::agile_tix_log_event("Post Creator: FUNCTION ENTERED for event $eventID ($eventName) - isNewEvent: " . ($isNewEvent ? 'true' : 'false') . ", postID: $postID");
        
        //agile_tix::agile_tix_log_event("agile_post_creator run");
        //$executionTime = new ExecutionTime('agile_post_creator content collection');
        //$executionTime->start();

        $thumbnailID = '';

        $EventImage = $event['EventImage'] ?? '';
        // agile_tix::agile_tix_log_event("Post Creator: Event $eventID - Processing thumbnail, EventImage: " . ($EventImage ?: 'empty'));

        if (!empty($EventImage)) {
            $mediaLibImg = agile_tix_post_creator::add_image_to_media_library_from_uri($EventImage);

            if ($mediaLibImg && !is_wp_error($mediaLibImg) && $mediaLibImg && array_key_exists('url', $mediaLibImg) && array_key_exists('attachment_id', $mediaLibImg)) {
                $thumbnailID = $mediaLibImg['attachment_id'];
            }
        }
        
        // agile_tix::agile_tix_log_event("Post Creator: Event $eventID - Thumbnail processing complete, thumbnailID: " . ($thumbnailID ?: 'empty'));

        //agile_tix::agile_tix_log_event("agile_post_creator post event img search");

        //$executionTime->end();

        //agile_tix::agile_tix_log_event($executionTime);

        //$executionTime = new ExecutionTime('agile_post_creator $post_data binding');

        //$executionTime->start();

        // Initialize tabContainer - coming soon events don't have CurrentShowings
        $tabContainer = '';
        $hasCurrentShowings = array_key_exists('CurrentShowings', $event);
        // agile_tix::agile_tix_log_event("Post Creator: Event $eventID - Checking CurrentShowings, exists: " . ($hasCurrentShowings ? 'true' : 'false'));

        if ($hasCurrentShowings) {
            // Group showtimes by date
            $groupedShowings = [];
            $showingIDs = [];

            foreach ($event['CurrentShowings'] as $show) {
                $showingIDs[] = $show['ID'];
                $displayDate = $show['DisplayDate'] ?? '';

                if ($displayDate) {
                    $dateOnly = date('F j, Y', strtotime($displayDate));
                    $groupedShowings[$dateOnly][] = $show;
                }
            }


            if (empty($groupedShowings)) {

                $tabContainer = '';
            } else {


            $tabContainer = '<div class="tab-navigation">';

            $isFirst = true;

            foreach ($groupedShowings as $date => $shows) {

                $tabId = 'tab_' . md5($date);
                $activeClass = $isFirst ? ' active' : '';

                // Use shorter date format for tabs

                $shortDate = date('M j', strtotime($date));

                if (date('Y', strtotime($date)) !== date('Y')) {
                    $shortDate .= ', ' . date('Y', strtotime($date));
                }

                $button_html = '<button class="tab-btn' . $activeClass . '" data-tab-id="' . esc_attr($tabId) . '">' . esc_html($shortDate) . '</button>';
    
                // Allow data-tab-id attribute
                $allowed_html = [
                    'button' => [
                        'class' => true,
                        'data-tab-id' => true,
                    ]
                ];

    
                $tabContainer .= wp_kses($button_html, $allowed_html);
                $isFirst = false;
            }

            $tabContainer .= '</div>';



            // Tab contents
            $tabContainer .= '<div class="ats-tab-contents">';
            $isFirst = true;

            foreach ($groupedShowings as $date => $shows) {

                $tabId = 'tab_' . md5($date);
                $style = $isFirst ? ' style="display:block;"' : '';
                $tabContainer .= '<div id="' . $tabId . '" class="ats-tab-content"' . $style . '>';
                $tabContainer .= '<div class="showings-list">';



                foreach ($shows as $show) {
                    $tabContainer .= agile_tix_post_creator::agile_create_showing_tab_content_showslist($show);
                }

                $tabContainer .= '</div></div>';
                $isFirst = false;
            }

            $tabContainer .= '</div>';
            $tabContainer .= '</div>';
            }
        }
        
        // agile_tix::agile_tix_log_event("Post Creator: Event $eventID - Tab container processing complete, tabContainer length: " . strlen($tabContainer));

        //agile_tix::agile_tix_log_event("pre postdata ");
        // agile_tix::agile_tix_log_event("Post Creator: Event $eventID - About to create post_data array");
        
        // Get the configured post type (respects theme settings)
        $configured_post_type = agile_tix_post_type::get_configured_post_type();
        if (empty($configured_post_type)) {
            $configured_post_type = 'agile_post'; // Fallback to default
        }
        // agile_tix::agile_tix_log_event("Post Creator: Event $eventID - Using configured post type: $configured_post_type");
        
        $post_data = array(

            'ID' => $postID,
            'post_title' => $event['Name'],
            'post_content' => agile_tix_post_creator::agile_create_universal_content_body($event) . $tabContainer . '<div class="hiddenTags">' . $event['CorpOrgName'] . '</div> ',
            'post_status' => $postStat,
            'post_type' => $configured_post_type,
            'page_template' => 'agile-post-template',
            'post_author' => 1,//get_user_by('id', 1)->user_id,
            //we want to use meta instead of tax_input for important data, if the user doesn't have perms to manage taxonomy, the process fails
            'comment_status' => $commentStat,
            /*'meta_input' => array( //meta data
                "ATS_ModifiedDate" => agile_tix_post_creator::agile_get_most_recent_lastUpdate($event) ?? '',
                "ATS_EventID" => $event['ID'] ?? '',
                "ATS_ExternalEventID" => $event['ExternalEventID'] ?? '',
                "ATS_CorpOrgID" => $event['CorpOrgID'] ?? '',
                "ATS_CorpOrgName" => $event['CorpOrgName'] ?? '',
                "ATS_OrgID" => $event['OrgID'] ?? '',
                "ATS_Name" => $event['Name'] ?? '',
                "ATS_Distributor" => $event['Distributor'] ?? '',
                "ATS_ExtraHTML" => $event['ExtraHTML'] ?? '',
                "ATS_DisplayColor" => $event['DisplayColor'] ?? '',
                //"ATS_EventImage" => $event['EventImage'] ?? '',
                //"ATS_EventThumbImage" => $event['EventThumbImage'] ?? '',
                //"ATS_Event_Img_Hash" => (empty($event['EventImage'])) ? '' : $event['EventImage'],//This line causes issues with irregular chars
                "ATS_MediaLib_Img_ID" => $thumbnailID ?? '',
                "ATS_firstEndDate" => $event['CurrentShowings'][0]['EndDate'] ?? '',
                "ATS_showingIDs" => $showingIDs ?? [],
                "ATS_HideFeatImg" => get_option('agile_field_render_carousel') ?? 0
            ),*/

            'meta_input' => agile_tix_post_creator::agile_create_universal_meta_fields($event, $thumbnailID, $comingSoonEventData)

        );


        //$executionTime->end();

        //agile_tix::agile_tix_log_event($executionTime);
        //agile_tix::agile_tix_log_event("post postdata ");
        //$executionTime = new ExecutionTime('agile_post_creator genre parsing');
        //$executionTime->start();


        $genreValues = array();

        if (!empty($event['CustomProperties'])) {
            //parse genre for taxonomy
            $names = array_column($event['CustomProperties'], 'Name');
            $values = array_column($event['CustomProperties'], 'Value');
            $indices = array_keys($names, 'Genre');
            $genreValues = array_map(function ($index) use ($values) {
                return $values[$index];
            }, $indices);
        }

        //$executionTime->end();

        //agile_tix::agile_tix_log_event($executionTime);

        //$executionTime = new ExecutionTime('agile_post_creator post update/insert');

        //$executionTime->start();

        //agile_tix::agile_tix_log_event('agile_post_creator pre kses filter');

        // Temporarily allow SVG elements for post content
        add_filter('wp_kses_allowed_html', 'agile_allow_svg_in_posts', 10, 2);
        //agile_tix::agile_tix_log_event('agile_post_creator post kses filter');

        $eventID = $event['ID'] ?? 'NO_ID';
        $eventName = $event['Name'] ?? 'NO_NAME';
        $hasComingSoonDate = isset($event['ComingSoonDate']) ? 'true' : 'false';
        
        // Log post data details before creation
        $postStatus = $post_data['post_status'] ?? 'NOT SET';
        $postType = $post_data['post_type'] ?? 'NOT SET';
        $hasMetaInput = isset($post_data['meta_input']) ? 'true' : 'false';
        $comingSoonInMeta = isset($post_data['meta_input']['ATS_ComingSoonDate']) ? $post_data['meta_input']['ATS_ComingSoonDate'] : 'NOT IN META';
        // agile_tix::agile_tix_log_event("Post Creator: Pre-creation check for event $eventID - Status: $postStatus, Type: $postType, HasMetaInput: $hasMetaInput, ComingSoonDate in meta: $comingSoonInMeta");
        
        if ($isNewEvent) {
            //insert a new post
            // agile_tix::agile_tix_log_event("Post Creator: Creating NEW post for event $eventID ($eventName) - ComingSoonDate = $hasComingSoonDate, postType = $postType, postStatus = $postStatus");
            $postID = wp_insert_post($post_data);
            if (is_wp_error($postID)) {
                agile_tix::agile_tix_log_event("Post Creator: ERROR creating post for event $eventID - " . $postID->get_error_message());
            } else {
                // agile_tix::agile_tix_log_event("Post Creator: Successfully created post ID $postID for event $eventID ($eventName)");
                // agile_tix::agile_tix_log_event("Post Creator: DEBUG - Post creation timestamp: " . current_time('mysql'));
                // $savedEventID = get_post_meta($postID, 'ATS_EventID', true);
                // agile_tix::agile_tix_log_event("Post Creator: DEBUG - Saved EventID meta: $savedEventID");
                // $savedComingSoonDate = get_post_meta($postID, 'ATS_ComingSoonDate', true);
                // agile_tix::agile_tix_log_event("Post Creator: DEBUG - Saved ComingSoonDate meta: " . ($savedComingSoonDate ?: 'NOT SET'));
                // $savedEventID = get_post_meta($postID, 'ATS_EventID', true);
                // $postStatus = get_post_status($postID);
                // $savedPostType = get_post_type($postID);
                // $postObject = get_post($postID);
                // $postObjectPostType = $postObject ? $postObject->post_type : 'NOT FOUND';
                // agile_tix::agile_tix_log_event("Post Creator: Post $postID verification - Status: $postStatus, Type (get_post_type): $savedPostType, Type (post object): $postObjectPostType, EventID: $savedEventID, ComingSoonDate: " . ($savedComingSoonDate ?: 'NOT SET'));
                // $test_query = new WP_Query(array(
                //     'post_type' => $savedPostType,
                //     'p' => $postID,
                //     'post_status' => 'any',
                // ));
                // $found_in_query = $test_query->have_posts() ? 'YES' : 'NO';
                // agile_tix::agile_tix_log_event("Post Creator: Post $postID query test - Found in WP_Query: $found_in_query");
            }
            //agile_tix::agile_tix_log_event("agile_post_creator wp_insert_post postID" . $postID);
        } else {
            //update an existing post
            // agile_tix::agile_tix_log_event("Post Creator: UPDATING existing post ID $postID for event $eventID ($eventName) - ComingSoonDate = $hasComingSoonDate");
            $postID = wp_update_post($post_data);
            if (is_wp_error($postID)) {
                agile_tix::agile_tix_log_event("Post Creator: ERROR updating post $postID for event $eventID - " . $postID->get_error_message());
            } else {
                // agile_tix::agile_tix_log_event("Post Creator: Successfully updated post ID $postID for event $eventID ($eventName)");
                // Verify meta was saved
                // $savedComingSoonDate = get_post_meta($postID, 'ATS_ComingSoonDate', true);
                // $savedEventID = get_post_meta($postID, 'ATS_EventID', true);
                // $postStatus = get_post_status($postID);
                // agile_tix::agile_tix_log_event("Post Creator: Post $postID verification - Status: $postStatus, EventID: $savedEventID, ComingSoonDate: " . ($savedComingSoonDate ?: 'NOT SET'));
            }
            //agile_tix::agile_tix_log_event("agile_post_creator  wp_update_postpostID" . $postID);
        }

        //agile_tix::agile_tix_log_event('agile_post_creator pre kses filter removal');

        // Remove the SVG filter after post creation
        remove_filter('wp_kses_allowed_html', 'agile_allow_svg_in_posts', 10);
        //agile_tix::agile_tix_log_event('agile_post_creator post kses filter removal');


        //$executionTime->end();
        //agile_tix::agile_tix_log_event($executionTime);

        //$executionTime = new ExecutionTime('agile_post_creator genre & thumbnail stuff');

        //$executionTime->start();

        if ($thumbnailID != '') { //temp removal to test carousel
            set_post_thumbnail($postID, $thumbnailID);
        }

        wp_set_object_terms($postID, $genreValues, 'genre');

        //$executionTime->end();
        //agile_tix::agile_tix_log_event($executionTime);
    }



    function wpse_kses_allowed_html($allowed, $context)
    {

        //agile_tix::agile_tix_log_event($executionTime);
        if ($context != 'post') {
            // agile_tix::agile_tix_log_event("'post' !== context");
            return $allowed;
        }

        $allowed['button']['onclick'] = true;

        return $allowed;
    }



    static function agile_group_custom_properties($data)
    {
        $grouped = [];

        foreach ($data as $property) {

            $group = $property['Group'];

            $name = $property['Name'];


            if (!isset($grouped[$group])) {
                $grouped[$group] = [];
            }


            if (!isset($grouped[$group][$name])) {
                $grouped[$group][$name] = [];
            }

            $grouped[$group][$name][] = $property;

        }
        return $grouped;
    }


    /**
     * A function intended to parse content and user defined content options without styling for any post type
     */
    static function agile_create_universal_content_body($show)
    {
        try {
            $content = '';
            //media content
            $addMedia = $show["AdditionalMedia"] ?? [];
            $mediaCar = agile_tix_post_creator::generateMediaCarousel($addMedia);
            $content .= $mediaCar;
            //text content
            $InfoLink = $show['InfoLink'] ?? '';
            $Duration = $show['Duration'] ?? '';
            $Distributor = $show['Distributor'] ?? '';
            $ShortDescription = $show['ShortDescription'] ?? '';
            $FullDescription = $show['FullDescription'] ?? '';
            $Type = $show['Type'] ?? '';
            $ShortDescriptive1 = $show['ShortDescriptive1'] ?? '';
            $ShortDescriptive2 = $show['ShortDescriptive2'] ?? '';
            $ExtraHTML = $show['ExtraHTML'] ?? '';
            $CustomProperties = agile_tix_amy_movie_integrate::groupCustomProperties($show);
            //agile_tix::agile_tix_log_event('$CustomProperties: ' . json_encode($CustomProperties));
            $LocationDiv = '';
            

            if (isset($show['CurrentShowings']) && !empty($show['CurrentShowings']) && isset($show['CurrentShowings'][0])) {
                if (isset($show['CurrentShowings'][0]['Venue']) && $show['CurrentShowings'][0]['Venue']) {
                    $venue = $show['CurrentShowings'][0]['Venue'] ?? null;
                    $name = $venue['Name'] ?? '';
                    $addressParts = array_filter([
                        $venue['Address1'] ?? '',
                        $venue['Address2'] ?? '',
                        ($venue['City'] ?? '') . ', ' . ($venue['State'] ?? '') . ' ' . ($venue['Zip'] ?? '')
                    ]);

                    $address = implode('<br>', $addressParts);
                    $cleanAddress = implode(', ', $addressParts);
                    $LocationDiv .= '<div class="venue-info" style="display: flex; align-items: flex-start; gap: 10px;"><div><strong>Location:</strong> ' . $name . '<br>' . $address . '</div>';
                    $LocationDiv .= '<div id="ats-location-link-svg-div">';
                    $LocationDiv .= '<a href="#" class="ats-map-link" data-address="' . esc_attr($cleanAddress) . '">';
                    $LocationDiv .= '<svg version="1.0" id="ats-location-link-svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24px" height="24px" viewBox="0 0 64 64" preserveAspectRatio="xMidYMid meet" enable-background="new 0 0 64 64" xml:space="preserve">';
                    $LocationDiv .= '<path fill="#231F20" d="M32,0C18.746,0,8,10.746,8,24c0,5.219,1.711,10.008,4.555,13.93c0.051,0.094,0.059,0.199,0.117,0.289l16,24C29.414,63.332,30.664,64,32,64s2.586-0.668,3.328-1.781l16-24c0.059-0.09,0.066-0.195,0.117-0.289C54.289,34.008,56,29.219,56,24C56,10.746,45.254,0,32,0z M32,32c-4.418,0-8-3.582-8-8s3.582-8,8-8s8,3.582,8,8S36.418,32,32,32z"/>';
                    $LocationDiv .= '</svg>';
                    $LocationDiv .= '</a>';
                    $LocationDiv .= '</div>';
                    $LocationDiv .= '</div>';
                }
            }
            //agile_tix::agile_tix_log_event('Post creator - location html: ' . $LocationDiv);

            // Build content strictly from layout_json order and templates
            $settings = get_option('agile_options_content_settings');
            $layout = [];
            if (is_array($settings) && isset($settings['layout_json'])) {
                $decoded = json_decode($settings['layout_json'], true);
                if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                    $layout = $decoded;
                }
            }

            if (!empty($layout)) {
                foreach ($layout as $block) {
                    //agile_tix::agile_tix_log_event("Template Mapping - block: " . json_encode($block));
                    $type = isset($block['type']) ? $block['type'] : '';
                    $fieldKey = isset($block['field']) ? $block['field'] : '';
                    $template = isset($block['text']) ? $block['text'] : '';

                    if ($type === 'text') {
                        if (!empty(trim($template))) {
                            $content .= '<p>' . esc_html($template) . '</p>';
                        }
                        continue;
                    }

                    if ($type === 'field') {
                        switch ($fieldKey) {
                        case 'agile_field_content_distributor':
                                //agile_tix::agile_tix_log_event("Template Mapping - distributor: $Distributor, $template ");
                                if (!empty($Distributor) && !empty(trim($template))) {

                                    //agile_tix::agile_tix_log_event("Template Mapping - distributor: $Distributor, $template ");
                                    $content .= '<p id="agile_content_distributor"><i>' . str_replace('{distributor}', $Distributor, $template) . '</i></p>';
                            }
                            break;

                        case 'agile_field_content_duration':
                                if (!empty($Duration) && !empty(trim($template))) {
                                    $content .= '<p id="agile_content_duration">' . str_replace('{duration}', $Duration, $template) . '</p>';
                            }
                            break;

                            case 'agile_field_content_infolink':
                                //agile_tix::agile_tix_log_event('Post creator case agile_field_content_infoLink ' . InfoLink . " " . $template);
                                if ($InfoLink && !empty(trim($InfoLink)) && !empty(trim($template))) {
                                    $content .= '<a id="agile_content_infoLink" class="agileLink" href=' . esc_url($InfoLink) . '>' . esc_html($template) . '</a><br>';
                            }
                            break;

                            case 'agile_field_content_short_description':
                                if (!empty($ShortDescription) && !empty(trim($template))) {
                                    $content .= '<p id="agile_content_short_description">' . str_replace('{short description}', $ShortDescription, $template) . '</p>';
                            }
                            break;

                            case 'agile_field_content_full_description':
                                if (!empty($FullDescription) && !empty(trim($template))) {
                                    $content .= '<p id="agile_content_description">' . str_replace('{full description}', $FullDescription, $template) . '</p>';
                            }
                            break;

                            case 'agile_field_content_renderlocation':
                                if (!empty($LocationDiv)) {
                                    // textless field; ignore template and render widget
                                    $content .= $LocationDiv;
                            }
                            break;

                            case 'agile_field_content_rating':
                                // textless field; get Vote Count and Vote Average from CustomProperties
                                $voteAverageValues = agile_tix_post_creator::getCustomPropertyValues($show, 'Vote Average');
                                $voteCountValues = agile_tix_post_creator::getCustomPropertyValues($show, 'Vote Count');
                                
                                if (!empty($voteAverageValues) && !empty($voteCountValues)) {
                                    $voteAverage = floatval($voteAverageValues[0]);
                                    $voteCount = intval($voteCountValues[0]);
                                    
                                    // Round to nearest first decimal place
                                    $roundedAverage = round($voteAverage, 1);
                                    
                                    // Get TMDB SVG URL
                                    $tmdb_svg_url = plugin_dir_url(dirname(__FILE__)) . 'assets/ExternalAssets/tmdbShort.svg';
                                    
                                    // Build rating display HTML
                                    $ratingDiv = '<div class="agile-rating-display" id="agile_content_rating">';
                                    $ratingDiv .= '<div class="agile-rating-stars">';
                                    
                                    // Create 5 stars, filled based on rating (each star = 2 points out of 10)
                                    $starsValue = $roundedAverage / 2; // Convert to 5-star scale
                                    $fullStars = floor($starsValue);
                                    $hasHalfStar = ($starsValue - $fullStars) >= 0.5;
                                    
                                    for ($i = 0; $i < 5; $i++) {
                                        if ($i < $fullStars) {
                                            $ratingDiv .= '<span class="agile-star agile-star-full">★</span>';
                                        } elseif ($i == $fullStars && $hasHalfStar) {
                                            $ratingDiv .= '<span class="agile-star agile-star-half">★</span>';
                                        } else {
                                            $ratingDiv .= '<span class="agile-star agile-star-empty">★</span>';
                                        }
                                    }
                                    
                                    $ratingDiv .= '</div>';
                                    $ratingDiv .= '<div class="agile-rating-text">';
                                    $ratingDiv .= '<span class="agile-rating-score">' . esc_html(number_format($roundedAverage, 1)) . '</span>';
                                    $ratingDiv .= '<span class="agile-rating-max">/10</span>';
                                    $ratingDiv .= '<span class="agile-rating-count">(' . esc_html(number_format($voteCount)) . ' votes)</span>';
                                    $ratingDiv .= '</div>';
                                    $ratingDiv .= '<div class="agile-rating-tmdb">';
                                    $ratingDiv .= '<a href="https://www.themoviedb.org/" target="_blank" rel="noopener noreferrer" class="agile-tmdb-link">';
                                    $ratingDiv .= '<img src="' . esc_url($tmdb_svg_url) . '" alt="TMDB" class="agile-tmdb-logo" />';
                                    $ratingDiv .= '<span class="agile-tmdb-disclaimer">This product uses the TMDB API but is not endorsed or certified by TMDB</span>';
                                    $ratingDiv .= '</a>';
                                    $ratingDiv .= '</div>';
                                    $ratingDiv .= '</div>';
                                    
                                    $content .= $ratingDiv;
                                }
                            break;

                            case 'agile_field_content_type':
                                if (!empty($Type) && !empty(trim($template))) {
                                    $content .= '<p id="agile_content_type">' . str_replace('{type}', $Type, $template) . '</p>';
                                }
                                break;

                            case 'agile_field_content_short_descriptive1':
                                if (!empty($ShortDescriptive1) && !empty(trim($template))) {
                                    $content .= '<p id="agile_content_short_descriptive1">' . str_replace('{short descriptive1}', $ShortDescriptive1, $template) . '</p>';
                                }
                                break;

                            case 'agile_field_content_short_descriptive2':
                                if (!empty($ShortDescriptive2) && !empty(trim($template))) {
                                    $content .= '<p id="agile_content_short_descriptive2">' . str_replace('{short descriptive2}', $ShortDescriptive2, $template) . '</p>';
                                }
                                break;

                            case 'agile_field_content_extra_html':
                                if (!empty($ExtraHTML) && !empty(trim($template))) {
                                    // ExtraHTML may contain HTML, so we need to handle it differently
                                    // Replace the token in the template, then sanitize the result
                                    $renderedContent = str_replace('{extra html}', $ExtraHTML, $template);
                                    $content .= '<div id="agile_content_extra_html">' . wp_kses_post($renderedContent) . '</div>';
                                }
                                break;
                        }
                    }

                    if ($type === 'custom-property') {
                        //agile_tix::agile_tix_log_event("Cust Prop Template Mapping - is custom-property : " . json_encode($block));
                        $propertyName = isset($block['propertyName']) ? trim($block['propertyName']) : '';
                        $template = isset($block['template']) ? $block['template'] : '';

                        if (!empty($propertyName) && !empty(trim($template))) {
                            // Safely get custom property values from the event
                            //agile_tix::agile_tix_log_event("Cust Prop Template Mapping - template : " . $template);
                            $customPropertyValues = agile_tix_post_creator::getCustomPropertyValues($show, $propertyName);
                            //agile_tix::agile_tix_log_event("Cust Prop Template Mapping - customPropertyValues : " . json_encode($customPropertyValues));
                            if (!empty($customPropertyValues)) {
                                // Handle multiple values by joining them
                                $valuesString = implode(', ', $customPropertyValues);

                                // Replace the placeholder in the template
                                $placeholder = '{' . $propertyName . '}';
                                $renderedContent = str_replace($placeholder, $valuesString, $template);

                                $content .= '<p id="agile_content_custom_' . esc_attr($propertyName) . '">' . esc_html($renderedContent) . '</p>';
                            }
                        }
                    }
                }
            }
            return $content;

        } catch (Exception $e) {
            agile_tix::agile_tix_log_event($e->getMessage());
        }
    }

    /**
     * Safely extract custom property values from event data
     * Handles multiple values for the same property name
     */
    static function getCustomPropertyValues($event, $propertyName)
    {
        $values = array();

        try {
            // Check if CustomProperties exists and is an array
            if (isset($event['CustomProperties']) && is_array($event['CustomProperties'])) {
                //agile_tix::agile_tix_log_event('getCustomPropertyValues - Found CustomProperties array with ' . count($event['CustomProperties']) . ' items');
                //agile_tix::agile_tix_log_event('getCustomPropertyValues - Looking for property: "' . $propertyName . '"');

                foreach ($event['CustomProperties'] as $index => $property) {
                    //agile_tix::agile_tix_log_event('getCustomPropertyValues - Property ' . $index . ': ' . json_encode($property));

                    if (
                        is_array($property) &&
                        isset($property['Name']) &&
                        isset($property['Value'])
                    ) {

                        $propName = trim($property['Name']);
                        $searchName = trim($propertyName);

                        // Try exact match first
                        if ($propName === $searchName) {
                            $value = trim($property['Value']);
                            if (!empty($value)) {
                                $values[] = $value;
                                //agile_tix::agile_tix_log_event('getCustomPropertyValues - Found exact match: ' . $value);
                            }
                        }
                        // Try case-insensitive match
                        elseif (strtolower($propName) === strtolower($searchName)) {
                            $value = trim($property['Value']);
                            if (!empty($value)) {
                                $values[] = $value;
                                //agile_tix::agile_tix_log_event('getCustomPropertyValues - Found case-insensitive match: ' . $value);
                            }
                        }
                    }
                }
            } else {
                //agile_tix::agile_tix_log_event('getCustomPropertyValues - No CustomProperties found in event data');
            }
        } catch (Exception $e) {
            // Log error but don't break the post creation
            agile_tix::agile_tix_log_event('Error extracting custom property "' . $propertyName . '": ' . $e->getMessage());
        }

        //agile_tix::agile_tix_log_event('getCustomPropertyValues - Returning ' . count($values) . ' values: ' . json_encode($values));
        return $values;
    }


    static function agile_create_universal_meta_fields($event, $thumbnailID, $comingSoonEventData = null)
    {
        $metainput = array();

        try {
            $showingIDs = [];
            $showTimes = [];

            // Handle CurrentShowings - coming soon events never have CurrentShowings
            if (isset($event["CurrentShowings"]) && is_array($event["CurrentShowings"])) {
                foreach ($event["CurrentShowings"] as $showing) {
                    array_push($showingIDs, $showing["ID"]);
                    array_push($showTimes, array($showing["DisplayDate"] => $showing["LegacyPurchaseLink"]));
                }
            }

            $metainput["ATS_showingIDs"] = $showingIDs ?? [];
            $metainput["ATS_ModifiedDate"] = agile_tix_post_creator::agile_get_most_recent_lastUpdate($event) ?? '';
            $metainput["ATS_EventID"] = $event['ID'] ?? '';
            // Coming soon events might not have CurrentShowings, so check before accessing
            $metainput["ATS_firstEndDate"] = (isset($event['CurrentShowings']) && !empty($event['CurrentShowings']) && isset($event['CurrentShowings'][0]['EndDate'])) 
                ? $event['CurrentShowings'][0]['EndDate'] 
                : '';
            $metainput["ATS_HideFeatImg"] = get_option('agile_field_render_carousel') ?? 0;
            $metainput["ATS_MediaLib_Img_ID"] = $thumbnailID ?? '';
            $metainput['OrgID'] = $event['OrgID'] ?? '';
            $metainput['CorpOrgID'] = $event['CorpOrgID'] ?? '';
            $metainput['ATS_ShowTimes'] = $showTimes ?? [];

            // Add ComingSoonDate if present in event or from coming soon feed enrichment
            if (isset($event['ComingSoonDate'])) {
                $metainput["ATS_ComingSoonDate"] = $event['ComingSoonDate'];
                // agile_tix::agile_tix_log_event("Meta Fields: Added ATS_ComingSoonDate = " . $event['ComingSoonDate'] . " for event " . ($event['ID'] ?? 'NO_ID'));
            } elseif ($comingSoonEventData && isset($comingSoonEventData['ComingSoonDate'])) {
                // Enriching main feed post with coming soon data
                $metainput["ATS_ComingSoonDate"] = $comingSoonEventData['ComingSoonDate'];
                // agile_tix::agile_tix_log_event("Meta Fields: Added ATS_ComingSoonDate from comingSoonEventData = " . $comingSoonEventData['ComingSoonDate'] . " for event " . ($event['ID'] ?? 'NO_ID'));
            }

        } catch (Exception $e) {
            agile_tix::agile_tix_log_event("agile_create_universal_meta_fields Exception: " + $e);
        }

        return $metainput;
    }





    /**
     * Ingests a single show containing an array of zero or more showings
     *
     * Returns the highest LastUpdated value as a string
     *
     * This produces the value we assign to ATS_ModifiedDate so we can quickly check against the entire show to see if any show or showing has been updated
     */
    static function agile_get_most_recent_lastUpdate($data)
    {
        if (!$data) {
            agile_tix::agile_tix_log_event("agile_get_most_recent_lastUpdate !data");
            return null;
        }

        //$name = $data['Name'] ?? "Name missing";

        //agile_tix::agile_tix_log_event("agile_get_most_recent_lastUpdate $name");

        // Start with the parent show's ModifiedDate

        $latestDate = strtotime($data['ModifiedDate']);

        //agile_tix::agile_tix_log_event("agile_get_most_recent_lastUpdate stored latestDate - $latestDate");

        // Check each showing inside CurrentShowings

        if (!empty($data['CurrentShowings'])) {
            foreach ($data['CurrentShowings'] as $showing) {

                $showingDate = strtotime($showing['ModifiedDate']);

                //agile_tix::agile_tix_log_event("agile_get_most_recent_lastUpdate showingDate - $showingDate");

                if ($showingDate > $latestDate) {
                    $latestDate = $showingDate;
                    //agile_tix::agile_tix_log_event("agile_get_most_recent_lastUpdate newer date found - $latestDate");
                }
            }
        }
        //agile_tix::agile_tix_log_event("agile_get_most_recent_lastUpdate loop done");

        // Return the latest date in the original format
        return date('Y-m-d\TH:i:s', $latestDate);
    }


    static function generateMediaCarousel($additionalMedia, $carouselId = null)
    {

        $shouldRender = get_option('agile_field_render_carousel') ?? false;

        $car = "";

        if ($shouldRender && !empty($additionalMedia)) {
            // Generate unique ID if not provided

            $carouselId = $carouselId ?: 'carousel-' . uniqid();

            // Get auto-scroll settings from WordPress options

            $autoScroll = get_option('agile_field_carousel_auto_scroll') ?? false;

            $autoScrollInterval = get_option('agile_field_carousel_auto_scroll_interval') ?? 5000; // Default 5 seconds?

            $pauseOnHover = get_option('agile_field_carousel_pause_on_hover') ?? true;

            $sizeScale = get_option('agile_field_carousel_size') ?? 'auto';

            //consider letting these be option informed vars instead of consts

            $carouselHeight = 'auto';

            switch ($sizeScale) {
                case 'auto':
                    $carouselHeight = 'auto';
                    break;
                case "xsmall":
                    $carouselHeight = '10vh';
                    break;
                case "small":
                    $carouselHeight = '20vh';
                    break;
                case "medium":
                    $carouselHeight = '30vh';
                    break;
                case "large":
                    $carouselHeight = '40vh';
                    break;
                case "xlarge":
                    $carouselHeight = '50vh';
                    break;
                case 'xxlarge':
                    $carouselHeight = '60vh';
                    break;
                case 'xxxlarge':
                    $carouselHeight = '70vh';
                    break;
            }


            $carouselWidth = '100%';

            //$carouselAspectRatio =  get_option('agile_field_carousel_aspect_ratio') ?? '16:9';
            // Build data attributes for JavaScript

            $dataAttrs = "data-carousel-id='{$carouselId}'";

            if ($autoScroll) {
                $dataAttrs .= " data-auto-scroll='true'";
                $dataAttrs .= " data-auto-scroll-interval='{$autoScrollInterval}'";
                $dataAttrs .= " data-pause-on-hover='" . ($pauseOnHover ? 'true' : 'false') . "'";
            }

            // Create inline styles for fixed dimensions

            $containerStyle = "width: {$carouselWidth}; height: {$carouselHeight}; "; //aspect-ratio: {$carouselAspectRatio};
            $car .= "<div class='carousel-container' {$dataAttrs} style='{$containerStyle}'>";
            $car .= "<div class='carousel-wrapper' style='{$containerStyle}'>";
            $car .= "<div class='carousel' style='{$containerStyle}'>";
            $first = true;

            foreach ($additionalMedia as $index => $media) {
                $active = $first ? "active" : "";
                $caption = isset($media["Caption"]) ? esc_html($media["Caption"]) : '';
                $embed = isset($media["MediaEmbed"]) ? $media["MediaEmbed"] : '';
                // Skip empty media

                if (empty($embed)){
                    continue;
                }
                    

                $car .= "<div class='item {$active} wp-post-image wp-block-post-featured-image' data-index='{$index}'>";
                $car .= "<div class='media-wrapper'>";
                $car .= $embed;
                $car .= "</div>";

                if (!empty($caption)) {
                    $car .= "<div class='caption-wrapper'>";
                    $car .= "<p class='caption'>{$caption}</p>";
                    $car .= "</div>";
                }

                $car .= "</div>";
                $first = false;
            }

            $car .= "</div>"; // close the carousel
            $itemCount = count(array_filter($additionalMedia, function ($media) {
                return !empty($media["MediaEmbed"]);
            }));

            if ($itemCount > 1) {

                // Navigation buttons with proper icons
                $car .= "<button class='btn prev' aria-label='Previous slide'>";
                $car .= "<span class='sr-only'></span>";
                $car .= "<svg class='ats-svg-arrow' width='18px' height='18px' viewBox='0 0 1024 1024' class='icon'  version='1.1' xmlns='http://www.w3.org/2000/svg'><path d='M768 903.232l-50.432 56.768L256 512l461.568-448 50.432 56.768L364.928 512z' fill='#000000' /></svg>"; // Left arrow �
                $car .= "</button>";
                $car .= "<button class='btn next' aria-label='Next slide'>";
                $car .= "<span class='sr-only'></span>";
                $car .= "<svg class='ats-svg-arrow' width='18px' height='18px' viewBox='0 0 1024 1024' class='icon'  version='1.1' xmlns='http://www.w3.org/2000/svg'><path d='M256 120.768L306.432 64 768 512l-461.568 448L256 903.232 659.072 512z' fill='#000000' /></svg>"; // Right arrow �
                $car .= "</button>";
                $car .= "<div class='dots' role='tablist' aria-label='Carousel navigation'></div>";
            }

            $car .= "</div>"; // close the carousel-wrapper
            $car .= "</div>"; // close the container
        }
        return $car;
    }


    function agile_increase_concurrent_batches($concurrent_batches)
    {
        $batches = get_option('agile_field_actSched_concurrentBatches') ?? 1;

        //agile_tix::agile_tix_log_event("agile_increase_concurrent_batches run - batches = $batches");

        if ($batches != 1 && is_int($batches)) {
            //agile_tix::agile_tix_log_event("agile_increase_concurrent_batches concurrent batches set to: " . $batches);
            return $batches;
        }

        return $concurrent_batches;
    }

        
    function agile_increase_batch_size($batch_size)
    {
        $size = get_option('agile_field_actSched_batch_size') ?? 25;

        //agile_tix::agile_tix_log_event("agile_increase_batch_size run - size = $size");

        if ($size != 25 && is_int($size)) {
            //agile_tix::agile_tix_log_event("agile_increase_batch_size batch size set to: " . $size);
            return $size;
        }

        return $batch_size; 
    }

    /**
     * Filters events to only include those that need updates or are new
     * 
     * @param array $events Array of events from the API
     * @param array $event_ids Mapping of event IDs to post IDs
     * @param bool $deepRefresh Whether this is a deep refresh (process all events)
     * @return array Array with 'filtered_events' and 'processed_event_ids' keys
     */
    static function agile_filter_events_for_refresh($events, $event_ids, $deepRefresh)
    {

        //agile_tix::agile_tix_log_event("Event filtering events: event_ids: " . json_encode($event_ids) . " , deepRefresh: " . $deepRefresh);
        if ($deepRefresh) {
            //agile_tix::agile_tix_log_event("Deep refresh: processing all " . count($events) . " events");
            return [
                'filtered_events' => $events,
                'processed_event_ids' => $event_ids // All events processed on deep refresh
            ];
        }

        $filtered_events = [];
        $processed_event_ids = []; // Track which events will be processed
        $total_events = count($events);

        // Batch fetch all post meta for existing posts
        $post_ids = array_values($event_ids);
        $meta_data = [];

        foreach ($post_ids as $post_id) {
            $meta_data[$post_id] = [
                'ATS_ModifiedDate' => get_post_meta($post_id, 'ATS_ModifiedDate', true),
                'ATS_firstEndDate' => get_post_meta($post_id, 'ATS_firstEndDate', true),
                'ATS_showingIDs' => get_post_meta($post_id, 'ATS_showingIDs', true),
            ];
        }

        foreach ($events as $event) {
            $postID = $event_ids[$event['ID']] ?? 0;
            $isNewEvent = ($postID == 0);
            //agile_tix::agile_tix_log_event("Deep refresh foreach: postID " . $postID);
            // Always include new events
            if ($isNewEvent) {
                $filtered_events[] = $event;
                continue;
            }

            // Check if existing event needs update
            $meta = $meta_data[$postID] ?? [];
            $lastModified = $meta['ATS_ModifiedDate'] ?? false;
            $firstEndDate = $meta['ATS_firstEndDate'] ?? '';
            $lastShowings = $meta['ATS_showingIDs'] ?? [];
            
            // Check if this is a coming soon event (has ComingSoonDate but no CurrentShowings)
            $isComingSoonEvent = isset($event['ComingSoonDate']) && (!isset($event['CurrentShowings']) || empty($event['CurrentShowings']));

            // For coming soon events, skip firstIsExpired check (they don't have showings/end dates)
            if ($isComingSoonEvent) {
                $firstIsExpired = false; // Coming soon events are never "expired" based on showings
            } else {
                $firstDate_timestamp = strtotime($firstEndDate) + (8 * 60 * 60); // Add 8 wiggle hours to cover timezones from LA to NY
                $current_timestamp = current_time('timestamp');
                $firstIsExpired = ($firstDate_timestamp !== false && $firstDate_timestamp < $current_timestamp);
            }

            $currentShowings = [];
            // Coming soon events never have CurrentShowings
            if (isset($event['CurrentShowings']) && is_array($event['CurrentShowings'])) {
                foreach ($event['CurrentShowings'] as $showing) {
                    $currentShowings[] = $showing['ID'];
                }
            }

            // Skip if no changes detected
            $current_most_recent = agile_tix_post_creator::agile_get_most_recent_lastUpdate($event);
            $showings_match = ($lastShowings == $currentShowings);
            $dates_match = ($lastModified != false && $lastModified == $current_most_recent);
            /*
            agile_tix::agile_tix_log_event("Event {$event['Name']} filtering check: isComingSoon=" . ($isComingSoonEvent ? 'true' : 'false') .
                ", showings_match=" . ($showings_match ? 'true' : 'false') .
                ", firstIsExpired=" . ($firstIsExpired ? 'true' : 'false') .
                ", dates_match=" . ($dates_match ? 'true' : 'false') .
                ", stored_date='$lastModified' vs current_date='$current_most_recent'");
                */
            if ($showings_match && !$firstIsExpired && $dates_match) {
                // Event doesn't need update, but we need to track it as "processed" to avoid deletion
                $processed_event_ids[$event['ID']] = $postID;
                continue;
            }

            // Event needs update
            $filtered_events[] = $event;
        }

        return [
            'filtered_events' => $filtered_events,
            'processed_event_ids' => $processed_event_ids
        ];
    }



}

// Function to allow SVG elements in post content
function agile_allow_svg_in_posts($allowed, $context)
{
    if ($context === 'post') {
        $allowed['svg'] = array(
            'version' => true,
            'id' => true,
            'xmlns' => true,
            'xmlns:xlink' => true,
            'width' => true,
            'height' => true,
            'viewBox' => true,
            'enable-background' => true,
            'xml:space' => true,
        );
        $allowed['path'] = array(
            'fill' => true,
            'd' => true,
        );
        $allowed['a'] = array(
            'href' => true,
            'class' => true,
            'data-address' => true,
        );
    }
    return $allowed;
}

