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

/**
 * AUTO IMPORT – Robust cron scheduling + repair
 *
 * This version ensures custom cron schedules are registered as early as possible
 * and attempts to repair/reschedule any existing invalid events (invalid_schedule).
 *
 * Replace the existing includes/core/auto-import.php with this file.
 * After deploying:
 *  - Visit Tools » Cron Events (WP Crontrol) or check wp_next_scheduled for newssync_import_every_* hooks
 *  - If you had previous "invalid_schedule" warnings, they should stop after this file runs.
 */

/* ---------------------------
 * Helpers required early
 * Try new names first (`newssync-*.php`) then fallback to legacy names.
 * ---------------------------
 */
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Local variable, not global
$helpers_dir = __DIR__ . '/helpers/';

// items helper (prefer new name)
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Local variable, not global
$items_new = $helpers_dir . 'newssync-items.php';
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Local variable, not global
$items_old = $helpers_dir . 'items.php';
if ( file_exists( $items_new ) ) {
    require_once $items_new;
} elseif ( file_exists( $items_old ) ) {
    require_once $items_old;
} else {
    if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Critical file missing error, debug only
        error_log( 'newssync: missing items helper (' . $items_new . ' or ' . $items_old . ')' );
    }
}

// save-posts helper (prefer new name)
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Local variable, not global
$save_new = $helpers_dir . 'newssync-save-posts.php';
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Local variable, not global
$save_old = $helpers_dir . 'save-posts.php';
if ( file_exists( $save_new ) ) {
    require_once $save_new;
} elseif ( file_exists( $save_old ) ) {
    require_once $save_old;
} else {
    if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Critical file missing error, debug only
        error_log( 'newssync: missing save-posts helper (' . $save_new . ' or ' . $save_old . ')' );
    }
}

/* ---------------------------
 * Register custom cron schedules immediately (important)
 * - We add the filter now so WP always knows about the schedules when rescheduling events.
 * ---------------------------
 */
add_filter( 'cron_schedules', 'newssync_add_custom_cron_schedules' );
function newssync_add_custom_cron_schedules( $schedules ) {
    // Avoid clobbering if already present
    if ( empty( $schedules['newssync_custom_1h'] ) ) {
        $schedules['newssync_custom_1h'] = [
            'interval' => HOUR_IN_SECONDS,
            'display'  => __('Every 1 Hour', 'rss-newssync'),
        ];
    }
    if ( empty( $schedules['newssync_custom_6h'] ) ) {
        $schedules['newssync_custom_6h'] = [
            'interval' => 6 * HOUR_IN_SECONDS,
            'display'  => __('Every 6 Hours', 'rss-newssync'),
        ];
    }
    if ( empty( $schedules['newssync_custom_24h'] ) ) {
        $schedules['newssync_custom_24h'] = [
            'interval' => 24 * HOUR_IN_SECONDS,
            'display'  => __('Every 24 Hours', 'rss-newssync'),
        ];
    }
    return $schedules;
}

/* ---------------------------
 * Repair existing scheduled events if they reference a missing schedule
 * ---------------------------
 */
add_action( 'init', 'newssync_repair_import_schedules', 5 );
function newssync_repair_import_schedules() {
    // Ensure schedules are available
    $schedules = wp_get_schedules();

    // Map hooks -> expected recurrence slug
    $map = [
        'newssync_import_every_1h'  => 'newssync_custom_1h',
        'newssync_import_every_6h'  => 'newssync_custom_6h',
        'newssync_import_every_24h' => 'newssync_custom_24h',
    ];

    foreach ( $map as $hook => $recurrence_slug ) {
        // If there is a next scheduled timestamp for this hook
        $next = wp_next_scheduled( $hook );
        if ( $next ) {
            // If the recurrence this hook originally used is missing, clear hook so we can reschedule cleanly
            if ( ! isset( $schedules[ $recurrence_slug ] ) ) {
                // Log for visibility if debug enabled
                if ( function_exists('newssync_is_debug_mode') && newssync_is_debug_mode() ) {
                    //error_log( "newssync_repair_import_schedules: Clearing scheduled hook {$hook} because recurrence {$recurrence_slug} missing." );
                }
                wp_clear_scheduled_hook( $hook );
            }
        }
    }
}

/* ---------------------------
 * Schedule import cron based on cache duration
 * - This runs on init (priority 10) after repair (priority 5)
 * ---------------------------
 */
add_action( 'init', 'newssync_schedule_import_cron', 10 );
function newssync_schedule_import_cron() {
    // Only schedule if saving/importing is enabled
    $newssync_save_as_posts_opt = get_option( 'newssync_save_as_posts', '' );
    $save_enabled = ( (string)$newssync_save_as_posts_opt === '1' || (int)$newssync_save_as_posts_opt === 1 );
    if ( ! $save_enabled ) {
        return;
    }

    // Ensure our custom schedules are present (defensive)
    add_filter( 'cron_schedules', 'newssync_add_custom_cron_schedules' );

    // Derive interval and normalize to 1, 6 or 24 hours
    $interval = (int) newssync_get_cache_duration();
    if ( $interval <= 0 ) $interval = 6 * HOUR_IN_SECONDS; // fallback

    $hours = max(1, (int) floor( $interval / HOUR_IN_SECONDS ));
    if ( $hours >= 24 ) $hours = 24;
    elseif ( $hours >= 6 ) $hours = 6;
    elseif ( $hours >= 1 ) $hours = 1;
    else $hours = 6;

    $cron_hook = 'newssync_import_every_' . $hours . 'h';
    $recurrence = 'newssync_custom_' . $hours . 'h';

    // If recurrence not registered for some reason, fallback to built-in schedules
    $schedules = wp_get_schedules();
    if ( ! isset( $schedules[ $recurrence ] ) ) {
        // Defensive attempt: register custom schedules and re-fetch
        add_filter( 'cron_schedules', 'newssync_add_custom_cron_schedules' );
        $schedules = wp_get_schedules();
    }

    // Final fallback mapping if still missing
    if ( ! isset( $schedules[ $recurrence ] ) ) {
        if ( $hours === 1 ) {
            $recurrence = 'hourly';
        } elseif ( $hours === 24 ) {
            $recurrence = 'daily';
        } else {
            // No built-in 6h; best fallback is 'twicedaily' (12h) or 'hourly' — choose twicedaily if available
            $recurrence = isset( $schedules['twicedaily'] ) ? 'twicedaily' : 'hourly';
        }
    }

    // Schedule if not already scheduled
    if ( ! wp_next_scheduled( $cron_hook ) ) {
        wp_schedule_event( time(), $recurrence, $cron_hook );
        if ( function_exists('newssync_is_debug_mode') && newssync_is_debug_mode() ) {
            //error_log( "newssync_schedule_import_cron: scheduled {$cron_hook} with recurrence {$recurrence}" );
        }
    }
}

/* ---------------------------
 * Import runner (same logic as before)
 * ---------------------------
 */
function newssync_do_full_import() {
    $lock_key = 'newssync_import_running_lock';
    if ( get_transient( $lock_key ) ) {
        if ( function_exists('newssync_is_debug_mode') && newssync_is_debug_mode() ) {
            //error_log( 'newssync_do_full_import: already running.' );
        }
        return;
    }
    set_transient( $lock_key, true, 5 * MINUTE_IN_SECONDS );

    $newssync_save_as_posts_opt = get_option( 'newssync_save_as_posts', '' );
    $newssync_save_as_posts = ( (string)$newssync_save_as_posts_opt === '1' || (string)$newssync_save_as_posts_opt === 'yes' || (int)$newssync_save_as_posts_opt === 1 );

    if ( ! $newssync_save_as_posts ) {
        delete_transient( $lock_key );
        return;
    }

    $fresh_items = function_exists('newssync_get_feed_items_raw') ? newssync_get_feed_items_raw([]) : [];
    if ( ! is_array( $fresh_items ) || empty( $fresh_items ) ) {
        delete_transient( $lock_key );
        return;
    }

    $per_feed = [];
    $total_imported = 0;

    // Respect configured max items per import; default to 15 for this distribution.
    $max_items = (int) get_option( 'newssync_max_import_items', 15 );
    $max_items = max( 0, $max_items );

    foreach ( $fresh_items as $item ) {
        if ( $max_items > 0 && $total_imported >= $max_items ) break;

        $link = $item['link'] ?? '';
        if ( empty( $link ) ) continue;

        // Attempt fast lookup via item-map table (if available). Fallback to postmeta query when missing.
        $guid = sanitize_text_field( (string) ( $item['guid'] ?? $item['id'] ?? $link ) );
        $found_post_id = null;
        // Try fast indexed lookup first (when table exists)
        if ( function_exists( 'newssync_find_post_id_by_guid' ) && function_exists( 'newssync_table_exists' ) && newssync_table_exists() ) {
            $found_post_id = newssync_find_post_id_by_guid( $guid );
        }
        if ( $found_post_id ) {
            // Already exists according to item-map
            continue;
        }

        // Fallback: check by original URL using optimized helper function
        if ( function_exists( 'newssync_find_post_id_by_original_url' ) ) {
            $existing_post_id = newssync_find_post_id_by_original_url( $link );
            if ( $existing_post_id ) {
                continue; // Post already exists
            }
        }

        if ( function_exists( 'newssync_check_duplicate_similarity' ) && newssync_check_duplicate_similarity( $item ) ) {
            continue;
        }

        $fid = $item['feed_id'] ?? '';
        $per_feed[$fid] = ($per_feed[$fid] ?? 0) + 1;

        // Enforce configured per-feed cap
        if ( $per_feed[$fid] > newssync_get_max_per_feed( ['category' => $item['category'] ?? '', 'limit' => 3] ) ) {
            continue;
        }

        if ( function_exists( 'newssync_create_post_from_item' ) ) {
            $post_id = newssync_create_post_from_item( $item );
        } else {
            $post_id = false;
        }

        if ( $post_id ) {
            $total_imported++;
        }
    }

    delete_transient( $lock_key );

    if ( function_exists( 'newssync_is_debug_mode' ) && newssync_is_debug_mode() ) {
        //error_log( "newssync_do_full_import: imported {$total_imported} items." );
    }

    return $total_imported;
}

/* ---------------------------
 * AJAX endpoint for manual force import
 * ---------------------------
 */
add_action( 'wp_ajax_newssync_force_import', 'newssync_ajax_force_import' );
function newssync_ajax_force_import() {
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_send_json_error( [ 'message' => esc_html__( 'Forbidden', 'rss-newssync' ) ], 403 );
    }

    check_ajax_referer( 'newssync_force_import' );

    $imported = newssync_do_full_import();

    /* translators: %d: number of posts successfully imported by the force import action. */
    $format = esc_html__( 'Import complete. Posts imported: %d', 'rss-newssync' );
    $message = sprintf( $format, (int) $imported );

    wp_send_json_success( [ 'message' => $message ] );
}
