<?php
/**
 * Blocked IP Scheduler - Manages automatic hourly sync from API
 *
 * @package VMPFence
 * @since 2.1.0
 * @since 2.1.2 Added critical checks for class existence
 */

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

/**
 * VMPFence Blocked IP Scheduler Class
 * 
 * Handles scheduling and management of automatic IP blocklist syncing from API.
 * Isolated from other cron jobs to ensure no conflicts.
 *
 * @since 2.1.0
 */
class VMPFence_Blocked_IP_Scheduler {

    /**
     * Cron hook name for hourly sync
     */
    const CRON_HOOK = 'vmpfence_hourly_blocked_ip_sync';

    /**
     * Config key for enable/disable state
     */
    const CONFIG_KEY = 'realtime_ip_blocklist_enabled';

    /**
     * Initialize the scheduler
     * Sets up WordPress action hooks for cron management
     *
     * @since 2.1.0
     * @return void
     */
    public static function init() {
        // Hook to handle the actual sync when cron runs
        add_action(self::CRON_HOOK, array(__CLASS__, 'run_scheduled_sync'));
        
        // Hook to ensure cron state matches config on plugin load
        add_action('plugins_loaded', array(__CLASS__, 'ensure_cron_state'), 20);
    }

    /**
     * Ensure cron job state matches the configuration setting
     * Called on plugin load to sync cron with enable/disable state
     *
     * @since 2.1.0
     * @return void
     */
    public static function ensure_cron_state() {
        $enabled = self::is_enabled();
        $is_scheduled = self::is_scheduled();

        if ($enabled && !$is_scheduled) {
            // Should be enabled but isn't - schedule it
            self::schedule_sync();
        } elseif (!$enabled && $is_scheduled) {
            // Should be disabled but isn't - unschedule it
            self::unschedule_sync();
        }
    }

    /**
     * Check if real-time IP blocklist sync is enabled
     *
     * @since 2.1.0
     * @return bool True if enabled, false otherwise
     */
    public static function is_enabled() {
        return (bool) VMPFence_Config::get(self::CONFIG_KEY, false);
    }

    /**
     * Check if cron job is currently scheduled
     *
     * @since 2.1.0
     * @return bool True if scheduled, false otherwise
     */
    public static function is_scheduled() {
        return (bool) wp_next_scheduled(self::CRON_HOOK);
    }

    /**
     * Schedule the hourly sync cron job
     *
     * @since 2.1.0
     * @return bool True on success, false on failure
     */
    public static function schedule_sync() {
        // Don't schedule if already scheduled
        if (self::is_scheduled()) {
            return true;
        }

        // Schedule to run hourly starting now
        $result = wp_schedule_event(time(), 'hourly', self::CRON_HOOK);

        if ($result !== false) {
            if (class_exists('VMPFence_Secure_Logger')) {
                VMPFence_Secure_Logger::log('info', 'Scheduled hourly blocked IP sync', array(
                    'next_run' => date('Y-m-d H:i:s', wp_next_scheduled(self::CRON_HOOK))
                ));
            }
            return true;
        }

        return false;
    }

    /**
     * Unschedule the hourly sync cron job
     *
     * @since 2.1.0
     * @return bool True on success
     */
    public static function unschedule_sync() {
        $timestamp = wp_next_scheduled(self::CRON_HOOK);
        
        if ($timestamp) {
            wp_unschedule_event($timestamp, self::CRON_HOOK);
            if (class_exists('VMPFence_Secure_Logger')) {
                VMPFence_Secure_Logger::log('info', 'Unscheduled hourly blocked IP sync');
            }
        }
        
        // Also clear any orphaned hooks
        wp_clear_scheduled_hook(self::CRON_HOOK);
        
        return true;
    }

    /**
     * Enable real-time IP blocklist sync
     * Updates config and schedules the cron job
     *
     * @since 2.1.0
     * @return bool True on success, false on failure
     */
    public static function enable() {
        // Set config
        if (!VMPFence_Config::set(self::CONFIG_KEY, true)) {
            return false;
        }

        // Schedule the cron
        return self::schedule_sync();
    }

    /**
     * Disable real-time IP blocklist sync
     * Updates config and unschedules the cron job
     *
     * @since 2.1.0
     * @return bool True on success
     */
    public static function disable() {
        // Set config
        VMPFence_Config::set(self::CONFIG_KEY, false);

        // Unschedule the cron
        return self::unschedule_sync();
    }

    /**
     * Run the scheduled sync (called by WordPress cron)
     * This is the actual function that executes when the cron runs
     *
     * @since 2.1.0
     * @since 2.1.2 Added check for MODEL class existence
     * @since 2.2.2 Added critical check for table existence before sync
     * @return void
     */
    public static function run_scheduled_sync() {
        // Double-check that sync is still enabled
        if (!self::is_enabled()) {
            if (class_exists('VMPFence_Secure_Logger')) {
                VMPFence_Secure_Logger::log('warning', 'Blocked IP sync ran but feature is disabled - unscheduling');
            }
            self::unschedule_sync();
            return;
        }

        // Check if the MODEL class exists (database operations)
        if (!class_exists('VMPFence_Blocked_IP')) {
            if (class_exists('VMPFence_Secure_Logger')) {
                VMPFence_Secure_Logger::log('error', 'Blocked IP model class not found');
            }
            return;
        }

        // CRITICAL: Check if table exists before attempting sync
        // Prevents DB errors if cron runs after deactivation/table deletion
        global $wpdb;
        $table_name = $wpdb->prefix . VMPFence_Constants::TABLE_BLOCKED_IPS;
        $table_exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table_name));
        
        if ($table_exists !== $table_name) {
            if (class_exists('VMPFence_Secure_Logger')) {
                VMPFence_Secure_Logger::log('warning', 'Blocked IP sync aborted - table does not exist', [
                    'table' => $table_name,
                    'likely_cause' => 'Plugin deactivated or tables deleted'
                ]);
            }
            // Unschedule the cron since table is missing
            self::unschedule_sync();
            return;
        }

        if (class_exists('VMPFence_Secure_Logger')) {
            VMPFence_Secure_Logger::log('info', 'Starting scheduled blocked IP sync');
        }

        // Run the sync using MODEL class (inserts to database)
        $result = VMPFence_Blocked_IP::sync_from_api();

        // Save last sync time if successful
        if (empty($result['errors'])) {
            VMPFence_Config::set('last_blocked_ip_sync_time', time());
        }

        // Log results
        if (class_exists('VMPFence_Secure_Logger')) {
            if (empty($result['errors'])) {
                VMPFence_Secure_Logger::log('info', 'Scheduled blocked IP sync completed', array(
                    'total' => $result['total'],
                    'new' => $result['new'],
                    'updated' => $result['updated']
                ));
            } else {
                VMPFence_Secure_Logger::log('error', 'Scheduled blocked IP sync failed', array(
                    'errors' => $result['errors']
                ));
            }
        }
    }

    /**
     * Get next scheduled sync time
     *
     * @since 2.1.0
     * @return int|false Unix timestamp of next scheduled run, or false if not scheduled
     */
    public static function get_next_sync_time() {
        return wp_next_scheduled(self::CRON_HOOK);
    }

    /**
     * Get time until next sync in human-readable format
     *
     * @since 2.1.0
     * @return string Human-readable time until next sync, or "Not scheduled" if disabled
     */
    public static function get_next_sync_human() {
        $timestamp = self::get_next_sync_time();
        
        if (!$timestamp) {
            return 'Not scheduled';
        }

        $time_diff = $timestamp - time();
        
        if ($time_diff < 0) {
            return 'Overdue (running soon)';
        }
        
        if ($time_diff < 60) {
            return 'Less than 1 minute';
        }
        
        if ($time_diff < 3600) {
            $minutes = ceil($time_diff / 60);
            return $minutes . ' minute' . ($minutes > 1 ? 's' : '');
        }
        
        $hours = floor($time_diff / 3600);
        $minutes = floor(($time_diff % 3600) / 60);
        
        $result = $hours . ' hour' . ($hours > 1 ? 's' : '');
        if ($minutes > 0) {
            $result .= ' ' . $minutes . ' minute' . ($minutes > 1 ? 's' : '');
        }
        
        return $result;
    }

    /**
     * Manual trigger for sync (bypasses schedule)
     * Useful for testing or immediate sync needs
     *
     * @since 2.1.0
     * @since 2.1.2 Added check for MODEL class existence
     * @return array Result from sync_from_api()
     */
    public static function trigger_manual_sync() {
        if (!class_exists('VMPFence_Blocked_IP')) {
            return array(
                'success' => false,
                'total' => 0,
                'new' => 0,
                'updated' => 0,
                'errors' => array('VMPFence_Blocked_IP model class not found')
            );
        }

        if (class_exists('VMPFence_Secure_Logger')) {
            VMPFence_Secure_Logger::log('info', 'Manual blocked IP sync triggered');
        }
        return VMPFence_Blocked_IP::sync_from_api();
    }

    /**
     * Get scheduler status information
     *
     * @since 2.1.0
     * @return array Status information
     */
    public static function get_status() {
        return array(
            'enabled' => self::is_enabled(),
            'scheduled' => self::is_scheduled(),
            'next_run' => self::get_next_sync_time(),
            'next_run_human' => self::get_next_sync_human(),
            'cron_hook' => self::CRON_HOOK
        );
    }

    /**
     * Cleanup method - removes all cron jobs
     * Should be called on plugin deactivation/uninstall
     *
     * @since 2.1.0
     * @return void
     */
    public static function cleanup() {
        wp_clear_scheduled_hook(self::CRON_HOOK);
        if (class_exists('VMPFence_Secure_Logger')) {
            VMPFence_Secure_Logger::log('info', 'Cleaned up blocked IP scheduler cron jobs');
        }
    }
}
