<?php
/**
 * VmpFence SIEM Sync Manager
 *
 * Orchestrates all SIEM sync modules. Called every 5 minutes by WP-Cron
 * via the 'vmpfence_siem_sync' hook.
 *
 * Responsibilities:
 * - Ensures site UUID is valid before syncing
 * - Loads and instantiates all registered sync modules
 * - Runs each module's sync() method in sequence
 * - Stores last sync results in wp_options for diagnostics
 *
 * @package    VMPFence
 * @subpackage Includes
 * @since      2.2.4
 */

if (!defined('ABSPATH')) {
    exit;
}

class VmpFence_Sync_Manager {

    /**
     * Registered sync module instances
     * @var VmpFence_Base_Sync[]
     */
    private $modules = array();

    /**
     * Constructor — registers all sync modules.
     *
     * @since 2.2.4
     */
    public function __construct() {
        $this->register_modules();
    }

    /**
     * Register all available sync modules.
     * Each module file is loaded and instantiated if the class exists.
     *
     * @since 2.2.4
     * @return void
     */
    private function register_modules() {
        $sync_dir = VMPFENCE_PLUGIN_DIR . 'includes/sync/';

        $module_files = array(
            'class-audit-log-sync.php'      => 'VmpFence_Audit_Log_Sync',
            'class-file-changes-sync.php'   => 'VmpFence_File_Changes_Sync',
            'class-waf-failures-sync.php'   => 'VmpFence_WAF_Failures_Sync',
            'class-country-block-sync.php'  => 'VmpFence_Country_Block_Sync',
            'class-bot-crawler-sync.php'    => 'VmpFence_Bot_Crawler_Sync',
            'class-custom-patterns-sync.php' => 'VmpFence_Custom_Patterns_Sync',
        );

        foreach ($module_files as $file => $class) {
            $path = $sync_dir . $file;
            if (file_exists($path)) {
                require_once $path;
                if (class_exists($class)) {
                    $this->modules[$class] = new $class();
                }
            }
        }
    }

    /**
     * Run all sync modules in sequence.
     *
     * Ensures the site has a valid UUID before proceeding.
     * Each module's result is captured individually so one failure
     * does not block the others.
     *
     * @since 2.2.4
     * @return array Associative array of module_name => result
     */
    public function sync_all(): array {
        // Concurrency lock — prevent overlapping cron runs from double-syncing
        if (get_transient('vmpfence_siem_sync_lock')) {
            return array('_status' => 'skipped', '_reason' => 'Another sync is already running');
        }
        set_transient('vmpfence_siem_sync_lock', true, 300); // 5-min max TTL (matches cron interval)

        // Ensure site UUID exists before syncing
        if (class_exists('VmpFence_Installation')) {
            $uuid = VmpFence_Installation::get_installation_uuid();
            if (empty($uuid) || strpos($uuid, 'temp-') === 0) {
                // Try to get a real UUID from the server
                $uuid = VmpFence_Installation::get_installation_uuid(true);
                if (empty($uuid) || strpos($uuid, 'temp-') === 0) {
                    if (class_exists('VMPFence_Secure_Logger')) {
                        VMPFence_Secure_Logger::log('info', 'SIEM sync skipped: No valid site UUID yet');
                    }
                    delete_transient('vmpfence_siem_sync_lock');
                    return array('_status' => 'skipped', '_reason' => 'No valid site UUID');
                }
            }
        }

        $results = array();
        $total_synced = 0;
        $start_time = microtime(true);

        // === PHASE 1: Push data sync modules OUT (Steps 5-6 — existing 6 modules) ===
        foreach ($this->modules as $name => $module) {
            try {
                $result = $module->sync();
                $results[$name] = $result;
                if (!empty($result['synced'])) {
                    $total_synced += (int) $result['synced'];
                }
            } catch (\Exception $e) {
                $results[$name] = array(
                    'success' => false,
                    'error'   => $e->getMessage(),
                );
                if (class_exists('VMPFence_Secure_Logger')) {
                    VMPFence_Secure_Logger::log('error', 'SIEM sync module exception: ' . $name, array(
                        'error' => $e->getMessage(),
                    ));
                }
            }
        }

        // === PHASE 2: Push settings snapshot (v2.2.4 — scan/options bidirectional) ===
        try {
            if (class_exists('VmpFence_Sync_Settings')) {
                $results['settings'] = VmpFence_Sync_Settings::sync();
            }
        } catch (\Exception $e) {
            $results['settings'] = array('success' => false, 'error' => $e->getMessage());
            if (class_exists('VMPFence_Secure_Logger')) {
                VMPFence_Secure_Logger::log('error', 'SIEM settings sync exception', array(
                    'error' => $e->getMessage(),
                ));
            }
        }

        // === PHASE 3: Push scan progress if scan is running (v2.2.4) ===
        try {
            $scan_progress = get_option('vmpfence_scan_progress', array());
            if (!empty($scan_progress) && ($scan_progress['status'] ?? 'idle') !== 'idle') {
                if (class_exists('VmpFence_Scan_Sync')) {
                    $scan_sync = new VmpFence_Scan_Sync();
                    $scan_sync->maybe_push_progress();
                }
            }
        } catch (\Exception $e) {
            if (class_exists('VMPFence_Secure_Logger')) {
                VMPFence_Secure_Logger::log('error', 'SIEM scan progress push exception', array(
                    'error' => $e->getMessage(),
                ));
            }
        }

        // === PHASE 3B: Retry pending scan-results push (v2.2.5) ===
        // If a previous scan completed but push_scan_results() failed, retry now.
        if (get_option('vmpfence_scan_results_pending_push', false)) {
            try {
                if (class_exists('VmpFence_Scan_Sync')) {
                    $scan_sync_retry = new VmpFence_Scan_Sync();
                    $push_ok = $scan_sync_retry->push_scan_results();
                    if ($push_ok) {
                        delete_option('vmpfence_scan_results_pending_push');
                        if (class_exists('VMPFence_Secure_Logger')) {
                            VMPFence_Secure_Logger::log('info', 'SIEM scan results retry push succeeded');
                        }
                    } else {
                        // FIX-5 (v6.6): API returned WP_Error — keep flag for next retry
                        if (class_exists('VMPFence_Secure_Logger')) {
                            VMPFence_Secure_Logger::log('warning', 'SIEM scan results retry push failed (API error) — will retry again');
                        }
                    }
                }
            } catch (\Exception $e) {
                // Keep the flag — will retry next cron cycle
                if (class_exists('VMPFence_Secure_Logger')) {
                    VMPFence_Secure_Logger::log('warning', 'SIEM scan results retry push failed — will retry again', array(
                        'error' => $e->getMessage(),
                    ));
                }
            }
        }

        // === PHASE 4: Poll and execute commands from SIEM portal (v2.2.4) ===
        $command_results = array();
        try {
            if (class_exists('VmpFence_Command_Executor')) {
                $executor = new VmpFence_Command_Executor();
                $command_results = $executor->poll_and_execute();
            }
        } catch (\Exception $e) {
            $command_results = array('success' => false, 'error' => $e->getMessage());
            if (class_exists('VMPFence_Secure_Logger')) {
                VMPFence_Secure_Logger::log('error', 'SIEM command executor exception', array(
                    'error' => $e->getMessage(),
                ));
            }
        }

        $elapsed = round(microtime(true) - $start_time, 2);

        // Store last sync results for diagnostics
        update_option('vmpfence_siem_last_sync', array(
            'time'         => current_time('timestamp'),
            'time_iso'     => current_time('c'),
            'elapsed_sec'  => $elapsed,
            'total_synced' => $total_synced,
            'results'      => $results,
            'commands'     => $command_results,
        ));

        if ($total_synced > 0 && class_exists('VMPFence_Secure_Logger')) {
            VMPFence_Secure_Logger::log('info', "SIEM sync completed: {$total_synced} records synced in {$elapsed}s");
        }

        // Release concurrency lock
        delete_transient('vmpfence_siem_sync_lock');

        return $results;
    }

    /**
     * Get summary of unsynced records across all modules.
     * Useful for diagnostics and admin status display.
     *
     * @since 2.2.4
     * @return array Module name => unsynced count
     */
    public function get_unsynced_summary(): array {
        $summary = array();
        foreach ($this->modules as $name => $module) {
            $summary[$name] = $module->get_unsynced_count();
        }
        return $summary;
    }

    /**
     * Get the last sync results stored in wp_options.
     *
     * @since 2.2.4
     * @return array|false Last sync data or false if never synced
     */
    public static function get_last_sync_results() {
        return get_option('vmpfence_siem_last_sync', false);
    }
}
