<?php
/**
 * Malware Signature Scheduler - Manages automatic hourly sync from API
 *
 * @package VMPFence
 * @since 2.1.2
 */

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

/**
 * VMPFence Malware Signature Scheduler Class
 * 
 * Handles scheduling and management of automatic malware signature syncing from API.
 * Ensures malware signatures are always up-to-date for optimal protection.
 *
 * @since 2.1.2
 */
class VMPFence_Signature_Scheduler {

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

    /**
     * Initialize the scheduler
     * Sets up WordPress action hooks for cron management
     *
     * @since 2.1.2
     * @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 is scheduled on plugin load
        add_action('plugins_loaded', array(__CLASS__, 'ensure_cron_state'), 20);
    }

    /**
     * Ensure cron job is scheduled
     * Called on plugin load to ensure signature sync is always active
     *
     * @since 2.1.2
     * @return void
     */
    public static function ensure_cron_state() {
        // Signature sync is always enabled (core security feature)
        if (!self::is_scheduled()) {
            self::schedule_sync();
        }
    }

    /**
     * Check if cron job is currently scheduled
     *
     * @since 2.1.2
     * @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.2
     * @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 malware signature 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.2
     * @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 malware signature sync');
            }
        }
        
        // Also clear any orphaned hooks
        wp_clear_scheduled_hook(self::CRON_HOOK);
        
        return true;
    }

    /**
     * Run the scheduled sync (called by WordPress cron)
     * This is the actual function that executes when the cron runs
     *
     * @since 2.1.2
     * @since 2.2.4 -- Added memory limit increase for cron context
     * @return void
     */
    public static function run_scheduled_sync() {
        // Safety net: bump memory limit for cron-based signature sync
        // The streamed writer keeps peak usage under ~10 MB, but this guards against
        // edge cases (e.g., very large individual signatures, WordPress overhead)
        @ini_set('memory_limit', '512M');

        // Check if the sync class exists
        if (!class_exists('VMPFence_Signature_Sync')) {
            if (class_exists('VMPFence_Secure_Logger')) {
                VMPFence_Secure_Logger::log('error', 'Signature Sync class not found');
            }
            return;
        }

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

        // Run the sync
        $result = VMPFence_Signature_Sync::sync_from_api();

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

        // Log results
        if (class_exists('VMPFence_Secure_Logger')) {
            if ($result['success']) {
                VMPFence_Secure_Logger::log('info', 'Scheduled malware signature sync completed', array(
                    'imported' => $result['imported'],
                    'total_available' => isset($result['total_available']) ? $result['total_available'] : 0,
                    'version' => isset($result['version']) ? $result['version'] : 'unknown'
                ));
            } else {
                VMPFence_Secure_Logger::log('error', 'Scheduled malware signature sync failed', array(
                    'errors' => isset($result['errors']) ? $result['errors'] : array('Unknown error')
                ));
            }
        }
    }

    /**
     * Get next scheduled sync time
     *
     * @since 2.1.2
     * @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.2
     * @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.2
     * @return array Result from sync_from_api()
     */
    public static function trigger_manual_sync() {
        if (!class_exists('VMPFence_Signature_Sync')) {
            return array(
                'success' => false,
                'total' => 0,
                'error' => 'VMPFence_Signature_Sync class not found'
            );
        }

        if (class_exists('VMPFence_Secure_Logger')) {
            VMPFence_Secure_Logger::log('info', 'Manual malware signature sync triggered');
        }
        return VMPFence_Signature_Sync::sync_from_api();
    }

    /**
     * Get scheduler status information
     *
     * @since 2.1.2
     * @return array Status information
     */
    public static function get_status() {
        return array(
            'enabled' => true, // Always 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.2
     * @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 malware signature scheduler cron jobs');
        }
    }
}
