<?php

/**
 * Sentinel File Monitor Class
 *
 * Monitors critical files for unauthorized changes.
 * Designed for easy expansion to Sentinel+ features.
 */

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

class Sentinel_File_Monitor
{

    /**
     * Critical files to monitor (free version)
     */
    private static $critical_files = array(
        'wp-config.php',
        '.htaccess'
    );

    /**
     * Initialize file monitoring
     */
    public static function init()
    {
        // Add admin action for manual testing
        add_action('wp_ajax_sentinel_test_file_check', array(__CLASS__, 'manual_file_check'));

        // PREMIUM: Add AJAX handler for diff viewer
        if (sentinel_is_premium()) {
            add_action('wp_ajax_sentinel_get_file_diff', array(__CLASS__, 'ajax_get_file_diff'));
        }

        // Only initialize if file monitoring is enabled
        $settings = get_option('sentinel_log_management', array());
        if (empty($settings['file_monitoring_enabled'])) {
            return;
        }

        // Validate Sentinel+ features
        $settings = self::validate_premium_settings($settings);

        // Schedule file check based on frequency
        $frequency = $settings['file_monitoring_frequency'] ?? 'daily';
        if (!wp_next_scheduled('sentinel_check_files')) {
            wp_schedule_event(time(), $frequency, 'sentinel_check_files');
        }

        // Hook into the scheduled event
        add_action('sentinel_check_files', array(__CLASS__, 'check_critical_files'));

        // Add real-time monitoring hooks if enabled
        if (sentinel_is_premium() && !empty($settings['realtime_monitoring'])) {
            add_action('init', array(__CLASS__, 'setup_realtime_monitoring'));
        }
    }

    /**
     * Check critical files for changes
     */
    public static function check_critical_files()
    {
        // Get fresh settings for each check
        $settings = get_option('sentinel_log_management', array());

        // Check core critical files
        foreach (self::$critical_files as $file) {
            self::check_single_file($file);
        }

        // Check theme files if premium and enabled
        if (sentinel_is_premium() && !empty($settings['monitor_theme_files'])) {
            $theme_files = self::get_active_theme_files();
            foreach ($theme_files as $theme_file) {
                self::check_single_file($theme_file, true);
            }
        }

        // Check plugin files if premium and enabled
        if (sentinel_is_premium() && !empty($settings['monitor_plugin_files'])) {
            $plugin_files = self::get_critical_plugin_files();
            foreach ($plugin_files as $plugin_file) {
                self::check_single_file($plugin_file, true);
            }
        }

        // Check custom files if premium and enabled
        if (sentinel_is_premium() && !empty($settings['monitor_custom_files'])) {
            $custom_paths = self::parse_custom_file_paths($settings['custom_file_paths'] ?? '');
            foreach ($custom_paths as $custom_path) {
                self::check_single_file($custom_path, true); // true = custom file
            }
        }
    }

    /**
     * Check if file should be excluded from monitoring
     */
    private static function is_file_excluded($filename)
    {
        $settings = get_option('sentinel_log_management', array());

        // Exclude log files if enabled
        if (!empty($settings['exclude_log_files'])) {
            if (
                preg_match('/\.(log|tmp|cache)$/i', $filename) ||
                strpos($filename, 'debug.log') !== false ||
                strpos($filename, 'error.log') !== false ||
                strpos($filename, 'access.log') !== false
            ) {
                return true;
            }
        }

        // Check custom exclusion patterns
        if (!empty($settings['custom_exclusions'])) {
            $patterns = explode("\n", $settings['custom_exclusions']);
            foreach ($patterns as $pattern) {
                $pattern = trim($pattern);
                if (empty($pattern)) continue;

                // Convert wildcard pattern to regex
                $regex = '/^' . str_replace(['*', '.'], ['.*', '\.'], $pattern) . '$/i';
                if (preg_match($regex, basename($filename))) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Check a single file for changes
     */
    private static function check_single_file($filename, $is_custom = false)
    {
        // Skip excluded files
        if (self::is_file_excluded($filename)) {
            return;
        }

        // Handle different path types
        if ($is_custom) {
            // Custom files can be absolute or relative paths
            $file_path = (strpos($filename, '/') === 0) ? $filename : ABSPATH . $filename;
        } else {
            // Core files are relative to ABSPATH
            $file_path = ABSPATH . $filename;
        }

        // Skip if file doesn't exist
        if (!file_exists($file_path)) {
            if ($is_custom) {
                error_log("[Sentinel] File Monitor: Custom file not found: {$file_path}");
            }
            return;
        }

        // Validate file is readable
        if (!is_readable($file_path)) {
            error_log("[Sentinel] File Monitor: File not readable: {$file_path}");
            return;
        }

        // Get current file info
        $current_hash = md5_file($file_path);
        $current_size = filesize($file_path);
        $current_modified = filemtime($file_path);

        // Get stored hash from options
        $stored_hashes = get_option('sentinel_file_hashes', array());
        $stored_hash = isset($stored_hashes[$filename]) ? $stored_hashes[$filename] : null;

        // If this is first time checking, just store the hash
        if ($stored_hash === null) {
            $stored_hashes[$filename] = array(
                'hash' => $current_hash,
                'size' => $current_size,
                'modified' => $current_modified,
                'first_check' => current_time('mysql')
            );
            update_option('sentinel_file_hashes', $stored_hashes);

            error_log("[Sentinel] File Monitor: First check for {$filename} - hash stored");
            return;
        }

        // Check if file has changed
        if ($current_hash !== $stored_hash['hash']) {
            // Check file size threshold
            $settings = get_option('sentinel_log_management', array());
            $size_change = abs($current_size - $stored_hash['size']);
            $threshold = absint($settings['file_size_threshold'] ?? 10);

            if ($size_change >= $threshold) {
                // File has changed significantly - log the event
                self::log_file_change($filename, $file_path, $stored_hash, array(
                    'hash' => $current_hash,
                    'size' => $current_size,
                    'modified' => $current_modified
                ));
            }

            // Update stored hash
            $stored_hashes[$filename] = array(
                'hash' => $current_hash,
                'size' => $current_size,
                'modified' => $current_modified,
                'last_changed' => current_time('mysql')
            );
            update_option('sentinel_file_hashes', $stored_hashes);
        }
    }

    /**
     * Log file change event
     */
    private static function log_file_change($filename, $file_path, $old_info, $new_info)
    {
        $size_change = $new_info['size'] - $old_info['size'];
        $size_change_text = $size_change > 0 ? "+{$size_change} bytes" : "{$size_change} bytes";

        // Create a more descriptive message
        $change_summary = self::get_change_summary($filename, $size_change);

        $event_data = array(
            'file_name' => $filename,
            'file_path' => $file_path,
            'file_type' => self::get_file_type($filename),
            'change_summary' => $change_summary,
            'old_hash' => $old_info['hash'],
            'new_hash' => $new_info['hash'],
            'old_size' => $old_info['size'],
            'new_size' => $new_info['size'],
            'size_change' => $size_change,
            'size_change_text' => $size_change_text,
            'last_known_modified' => date('Y-m-d H:i:s', $old_info['modified']),
            'current_modified' => date('Y-m-d H:i:s', $new_info['modified']),
            'detection_time' => current_time('mysql'),
            'event_source' => 'file_monitor',
            'automated_detection' => true
        );

        // PREMIUM: Store file baselines and generate diff
        if (sentinel_is_premium()) {
            $diff_data = self::store_baseline_and_generate_diff($filename, $file_path);
            if ($diff_data) {
                $event_data['has_diff'] = true;
                $event_data['diff_summary'] = $diff_data['summary'];
                $event_data['baseline_id'] = $diff_data['baseline_id'];
            }
        }

        $priority = self::get_file_priority($filename);

        // Create more informative log message with custom description
        $custom_description = sprintf(
            '%s was modified (%s) - %s',
            $filename,
            $size_change_text,
            $change_summary
        );

        // Add the custom description to the event data
        $event_data['description'] = $custom_description;
        $event_data['alert_message'] = $custom_description;

        // Log using existing Sentinel infrastructure
        // Use null for user_id to indicate this was a system-detected event, not user-initiated
        if (function_exists('sentinel_log_event')) {
            sentinel_log_event('file_modified', $event_data, null);
        }

        error_log("[Sentinel] File Monitor: {$filename} changed - {$change_summary} ({$size_change_text})");
    }

    /**
     * Get file type for categorization
     */
    private static function get_file_type($filename)
    {
        // Check for theme files
        if (strpos($filename, 'wp-content/themes/') === 0) {
            return 'theme_file';
        }

        // Check for plugin files
        if (strpos($filename, 'wp-content/plugins/') === 0) {
            return 'plugin_file';
        }

        switch ($filename) {
            case 'wp-config.php':
                return 'config_file';
            case '.htaccess':
                return 'server_config';
            default:
                return 'critical_file';
        }
    }

    /**
     * Get priority level for file
     */
    private static function get_file_priority($filename)
    {
        // Check for theme files
        if (strpos($filename, 'wp-content/themes/') === 0) {
            return 'medium';
        }

        // Check for plugin files
        if (strpos($filename, 'wp-content/plugins/') === 0) {
            return 'medium';
        }

        switch ($filename) {
            case 'wp-config.php':
                return 'critical';
            case '.htaccess':
                return 'high';
            default:
                return 'high';
        }
    }

    /**
     * Get active theme files for monitoring (Sentinel+)
     */
    private static function get_active_theme_files()
    {
        $theme_files = array();
        $theme_dir = get_template_directory();

        // Monitor functions.php
        if (file_exists($theme_dir . '/functions.php')) {
            $theme_files[] = str_replace(ABSPATH, '', $theme_dir . '/functions.php');
        }

        // Monitor style.css
        if (file_exists($theme_dir . '/style.css')) {
            $theme_files[] = str_replace(ABSPATH, '', $theme_dir . '/style.css');
        }

        // Monitor child theme if active
        if (get_template_directory() !== get_stylesheet_directory()) {
            $child_theme_dir = get_stylesheet_directory();

            if (file_exists($child_theme_dir . '/functions.php')) {
                $theme_files[] = str_replace(ABSPATH, '', $child_theme_dir . '/functions.php');
            }

            if (file_exists($child_theme_dir . '/style.css')) {
                $theme_files[] = str_replace(ABSPATH, '', $child_theme_dir . '/style.css');
            }
        }

        return $theme_files;
    }

    /**
     * Get critical plugin files for monitoring (Sentinel+)
     */
    private static function get_critical_plugin_files()
    {
        $plugin_files = array();
        $active_plugins = get_option('active_plugins', array());

        foreach ($active_plugins as $plugin) {
            $plugin_path = WP_PLUGIN_DIR . '/' . $plugin;
            if (file_exists($plugin_path)) {
                $plugin_files[] = str_replace(ABSPATH, '', $plugin_path);
            }
        }

        return $plugin_files;
    }

    /**
     * Setup real-time monitoring (Sentinel+)
     */
    public static function setup_realtime_monitoring()
    {
        // Only monitor on admin requests to reduce load
        if (is_admin()) {
            add_action('shutdown', array(__CLASS__, 'check_files_realtime'));
        }

        // Also monitor on specific actions that might modify files
        add_action('activated_plugin', array(__CLASS__, 'check_files_realtime'));
        add_action('deactivated_plugin', array(__CLASS__, 'check_files_realtime'));
        add_action('switch_theme', array(__CLASS__, 'check_files_realtime'));
        add_action('upgrader_process_complete', array(__CLASS__, 'check_files_realtime'));
    }

    /**
     * Real-time file check (resource intensive)
     */
    public static function check_files_realtime()
    {
        // Prevent multiple calls in the same request
        static $already_checked = false;
        if ($already_checked) {
            return;
        }
        $already_checked = true;

        // Only run if real-time monitoring is enabled
        $settings = get_option('sentinel_log_management', array());
        if (!sentinel_is_premium() || empty($settings['realtime_monitoring'])) {
            return;
        }

        // Run the same check as daily monitoring
        error_log('[Sentinel] File Monitor: Real-time check triggered');
        self::check_critical_files();
    }

    /**
     * Get human-readable change summary
     */
    private static function get_change_summary($filename, $size_change)
    {
        $file_descriptions = array(
            'wp-config.php' => 'WordPress configuration file',
            '.htaccess' => 'Server configuration file'
        );

        // Handle theme files
        if (strpos($filename, 'wp-content/themes/') === 0) {
            if (strpos($filename, 'functions.php') !== false) {
                $file_desc = 'Theme functions file';
            } elseif (strpos($filename, 'style.css') !== false) {
                $file_desc = 'Theme stylesheet';
            } else {
                $file_desc = 'Theme file';
            }
        }
        // Handle plugin files
        elseif (strpos($filename, 'wp-content/plugins/') === 0) {
            $file_desc = 'Plugin file';
        }
        // Handle known files
        elseif (isset($file_descriptions[$filename])) {
            $file_desc = $file_descriptions[$filename];
        }
        // Default
        else {
            $file_desc = 'Critical system file';
        }

        if ($size_change > 0) {
            if ($size_change < 100) {
                return $file_desc . ' had minor additions';
            } elseif ($size_change < 1000) {
                return $file_desc . ' had moderate additions';
            } else {
                return $file_desc . ' had significant additions';
            }
        } elseif ($size_change < 0) {
            $abs_change = abs($size_change);
            if ($abs_change < 100) {
                return $file_desc . ' had minor deletions';
            } elseif ($abs_change < 1000) {
                return $file_desc . ' had moderate deletions';
            } else {
                return $file_desc . ' had significant deletions';
            }
        } else {
            return $file_desc . ' was modified (same size - content changed)';
        }
    }

    /**
     * Parse custom file paths from textarea input
     */
    private static function parse_custom_file_paths($input)
    {
        if (empty($input)) {
            return array();
        }

        $lines = explode("\n", $input);
        $valid_paths = array();

        foreach ($lines as $line) {
            $line = trim($line);

            // Skip empty lines and comments
            if (empty($line) || strpos($line, '#') === 0 || strpos($line, '//') === 0) {
                continue;
            }

            // Basic path validation
            if (self::validate_file_path($line)) {
                $valid_paths[] = $line;
            } else {
                error_log("[Sentinel] File Monitor: Invalid custom path ignored: {$line}");
            }
        }

        return $valid_paths;
    }

    /**
     * Validate a file path for monitoring
     */
    private static function validate_file_path($path)
    {
        // Remove any dangerous characters
        if (preg_match('/[<>"|*?]/', $path)) {
            return false;
        }

        // Don't allow parent directory traversal beyond WordPress root
        if (strpos($path, '../') !== false) {
            return false;
        }

        // Ensure path doesn't try to access system files outside WordPress
        $resolved_path = (strpos($path, '/') === 0) ? $path : ABSPATH . $path;

        // Check if path is within allowed directories
        $wp_root = realpath(ABSPATH);
        $resolved_real = realpath(dirname($resolved_path));

        // Allow if path is within WordPress directory or common server paths
        if ($resolved_real && (strpos($resolved_real, $wp_root) === 0)) {
            return true;
        }

        // Allow some common absolute paths for server configs
        $allowed_absolute_patterns = array(
            '/etc/apache2/',
            '/etc/nginx/',
            '/etc/php/',
            '/var/www/',
            '/home/',
            '/usr/local/'
        );

        foreach ($allowed_absolute_patterns as $pattern) {
            if (strpos($resolved_path, $pattern) === 0) {
                return true;
            }
        }

        return false;
    }

    /**
     * Validate custom file paths and return validation results
     */
    public static function validate_custom_file_paths($input)
    {
        if (empty($input)) {
            return array(
                'valid' => array(),
                'invalid' => array(),
                'warnings' => array()
            );
        }

        $lines = explode("\n", $input);
        $results = array(
            'valid' => array(),
            'invalid' => array(),
            'warnings' => array()
        );

        foreach ($lines as $line_num => $line) {
            $line = trim($line);

            // Skip empty lines and comments
            if (empty($line) || strpos($line, '#') === 0 || strpos($line, '//') === 0) {
                continue;
            }

            if (self::validate_file_path($line)) {
                // Check if file exists
                $resolved_path = (strpos($line, '/') === 0) ? $line : ABSPATH . $line;
                if (file_exists($resolved_path)) {
                    $results['valid'][] = $line;
                } else {
                    $results['warnings'][] = array(
                        'line' => $line_num + 1,
                        'path' => $line,
                        'message' => 'File does not exist (will be monitored if created)'
                    );
                    $results['valid'][] = $line; // Still add to valid for monitoring
                }
            } else {
                $results['invalid'][] = array(
                    'line' => $line_num + 1,
                    'path' => $line,
                    'message' => 'Invalid path or security violation'
                );
            }
        }

        return $results;
    }

    /**
     * Get list of monitored files (for settings display)
     */
    public static function get_monitored_files()
    {
        $files = self::$critical_files;
        $settings = get_option('sentinel_log_management', array());

        // Add theme files if premium and enabled
        if (sentinel_is_premium() && !empty($settings['monitor_theme_files'])) {
            $theme_files = self::get_active_theme_files();
            $files = array_merge($files, $theme_files);
        }

        // Add plugin files if premium and enabled
        if (sentinel_is_premium() && !empty($settings['monitor_plugin_files'])) {
            $plugin_files = self::get_critical_plugin_files();
            $files = array_merge($files, $plugin_files);
        }

        // Add custom files if premium and enabled
        if (sentinel_is_premium() && !empty($settings['monitor_custom_files'])) {
            $custom_paths = self::parse_custom_file_paths($settings['custom_file_paths'] ?? '');
            $files = array_merge($files, $custom_paths);
        }

        return $files;
    }

    /**
     * Manual file check for testing (AJAX handler)
     */
    public static function manual_file_check()
    {
        // Check permissions
        if (!current_user_can('manage_options')) {
            wp_die('Unauthorized');
        }

        // Check nonce
        check_ajax_referer('sentinel_test_file_check', 'nonce');

        error_log('[Sentinel] File Monitor: Manual file check triggered');
        self::check_critical_files();

        wp_send_json_success('File check completed. Check debug.log for results.');
    }

    /**
     * Unschedule file monitoring (for deactivation)
     */
    public static function unschedule()
    {
        wp_clear_scheduled_hook('sentinel_check_files');
        error_log('[Sentinel] File Monitor: Unscheduled file checks');
    }

    /**
     * Validate Sentinel+ settings and enforce restrictions
     */
    private static function validate_premium_settings($settings)
    {
        if (!sentinel_is_premium()) {
            // Enforce Sentinel+ restrictions

            // Monitoring frequency: Only daily/weekly allowed for free users
            if (
                isset($settings['file_monitoring_frequency']) &&
                in_array($settings['file_monitoring_frequency'], ['hourly', 'twicedaily'])
            ) {
                $settings['file_monitoring_frequency'] = 'daily';
            }

            // Disable Sentinel+ features
            $settings['monitor_custom_files'] = false;
            $settings['monitor_theme_files'] = false;
            $settings['monitor_plugin_files'] = false;
            $settings['realtime_monitoring'] = false;
            $settings['custom_exclusions'] = '';

            // Reset custom threshold to default
            if (isset($settings['file_size_threshold']) && $settings['file_size_threshold'] != 10) {
                $settings['file_size_threshold'] = 10;
            }
        }

        return $settings;
    }

    /**
     * Sentinel+: Store file baseline and generate diff
     *
     * @param string $filename File name
     * @param string $file_path Full path to file
     * @return array|false Diff data array or false on failure
     */
    private static function store_baseline_and_generate_diff($filename, $file_path)
    {
        // Only proceed if premium and file exists
        if (!sentinel_is_premium() || !file_exists($file_path)) {
            return false;
        }

        // Get current file content
        $current_content = @file_get_contents($file_path);
        if ($current_content === false) {
            return false;
        }

        // Get stored baseline
        $baseline = self::get_file_baseline($filename);

        // If no baseline exists, store current content and return
        if (!$baseline) {
            self::store_file_baseline($filename, $current_content);
            return array(
                'summary' => 'Initial baseline created',
                'baseline_id' => md5($filename . time())
            );
        }

        // Generate diff between baseline and current content
        $diff_result = self::generate_diff($baseline['content'], $current_content, $filename);

        if (!$diff_result) {
            return false;
        }

        // Create baseline ID for this change
        $baseline_id = md5($filename . time());

        // Store the change in baseline history
        self::store_baseline_change($filename, $current_content, $diff_result, $baseline_id);

        return array(
            'summary' => $diff_result['summary'],
            'baseline_id' => $baseline_id
        );
    }

    /**
     * Sentinel+: Get stored file baseline
     *
     * @param string $filename File name
     * @return array|false Baseline data or false if none exists
     */
    private static function get_file_baseline($filename)
    {
        $baselines = get_option('sentinel_file_baselines', array());
        return isset($baselines[$filename]) ? $baselines[$filename] : false;
    }

    /**
     * Sentinel+: Store file baseline (initial or updated)
     *
     * @param string $filename File name
     * @param string $content File content
     * @return bool Success
     */
    private static function store_file_baseline($filename, $content)
    {
        $baselines = get_option('sentinel_file_baselines', array());

        $baselines[$filename] = array(
            'content' => $content,
            'timestamp' => current_time('mysql'),
            'hash' => md5($content),
            'changes' => array()
        );

        return update_option('sentinel_file_baselines', $baselines);
    }

    /**
     * Sentinel+: Store baseline change with diff
     *
     * @param string $filename File name
     * @param string $new_content New file content
     * @param array $diff_result Diff generation result
     * @param string $baseline_id Unique ID for this change
     * @return bool Success
     */
    private static function store_baseline_change($filename, $new_content, $diff_result, $baseline_id)
    {
        $baselines = get_option('sentinel_file_baselines', array());

        if (!isset($baselines[$filename])) {
            return false;
        }

        // Add change to history
        $baselines[$filename]['changes'][] = array(
            'baseline_id' => $baseline_id,
            'detected_at' => current_time('mysql'),
            'diff' => $diff_result['diff'],
            'summary' => $diff_result['summary'],
            'lines_added' => $diff_result['lines_added'],
            'lines_removed' => $diff_result['lines_removed'],
            'lines_modified' => $diff_result['lines_modified']
        );

        // Update baseline content to new content
        $baselines[$filename]['content'] = $new_content;
        $baselines[$filename]['hash'] = md5($new_content);
        $baselines[$filename]['timestamp'] = current_time('mysql');

        // Keep only last 10 changes to prevent database bloat
        if (count($baselines[$filename]['changes']) > 10) {
            $baselines[$filename]['changes'] = array_slice($baselines[$filename]['changes'], -10);
        }

        // Cleanup old baselines periodically
        self::cleanup_old_baselines($baselines);

        return update_option('sentinel_file_baselines', $baselines);
    }

    /**
     * Sentinel+: Generate unified diff between two text contents
     *
     * @param string $old_content Original content
     * @param string $new_content New content
     * @param string $filename File name for context
     * @return array|false Diff result array or false on failure
     */
    private static function generate_diff($old_content, $new_content, $filename)
    {
        // Convert content to arrays of lines
        $old_lines = explode("\n", $old_content);
        $new_lines = explode("\n", $new_content);

        // Simple diff algorithm - count changes
        $lines_added = 0;
        $lines_removed = 0;
        $lines_modified = 0;

        $old_count = count($old_lines);
        $new_count = count($new_lines);

        // Basic change detection
        if ($new_count > $old_count) {
            $lines_added = $new_count - $old_count;
        } elseif ($new_count < $old_count) {
            $lines_removed = $old_count - $new_count;
        }

        // Check for modified lines (simple approach)
        $min_lines = min($old_count, $new_count);
        for ($i = 0; $i < $min_lines; $i++) {
            if (isset($old_lines[$i]) && isset($new_lines[$i]) && $old_lines[$i] !== $new_lines[$i]) {
                $lines_modified++;
            }
        }

        // Generate simple unified diff format
        $diff_lines = array();
        $diff_lines[] = "--- {$filename} (before)";
        $diff_lines[] = "+++ {$filename} (after)";

        // Add context showing first few differences
        $context_shown = 0;
        for ($i = 0; $i < $min_lines && $context_shown < 5; $i++) {
            if (isset($old_lines[$i]) && isset($new_lines[$i]) && $old_lines[$i] !== $new_lines[$i]) {
                $diff_lines[] = "-" . $old_lines[$i];
                $diff_lines[] = "+" . $new_lines[$i];
                $context_shown++;
            }
        }

        // Show added lines
        if ($lines_added > 0) {
            for ($i = $old_count; $i < $new_count && $context_shown < 10; $i++) {
                if (isset($new_lines[$i])) {
                    $diff_lines[] = "+" . $new_lines[$i];
                    $context_shown++;
                }
            }
        }

        // Show removed lines
        if ($lines_removed > 0) {
            for ($i = $new_count; $i < $old_count && $context_shown < 10; $i++) {
                if (isset($old_lines[$i])) {
                    $diff_lines[] = "-" . $old_lines[$i];
                    $context_shown++;
                }
            }
        }

        // Create summary
        $changes = array();
        if ($lines_added > 0) $changes[] = "+{$lines_added} lines";
        if ($lines_removed > 0) $changes[] = "-{$lines_removed} lines";
        if ($lines_modified > 0) $changes[] = "~{$lines_modified} modified";

        $summary = empty($changes) ? 'No changes detected' : implode(', ', $changes);

        return array(
            'diff' => implode("\n", $diff_lines),
            'summary' => $summary,
            'lines_added' => $lines_added,
            'lines_removed' => $lines_removed,
            'lines_modified' => $lines_modified
        );
    }

    /**
     * Sentinel+: Cleanup old baselines to prevent database bloat
     *
     * @param array &$baselines Reference to baselines array
     */
    private static function cleanup_old_baselines(&$baselines)
    {
        // Only cleanup occasionally to avoid performance impact
        if (wp_rand(1, 20) !== 1) {
            return;
        }

        $cutoff_time = strtotime('-30 days');

        foreach ($baselines as $filename => $data) {
            // Remove baselines older than 30 days
            if (isset($data['timestamp'])) {
                $baseline_time = strtotime($data['timestamp']);
                if ($baseline_time < $cutoff_time) {
                    unset($baselines[$filename]);
                }
            }
        }
    }

    /**
     * Sentinel+: Get baseline change data by baseline ID
     *
     * @param string $baseline_id Unique baseline change ID
     * @return array|false Change data or false if not found
     */
    public static function get_baseline_change_data($baseline_id)
    {
        if (!sentinel_is_premium() || empty($baseline_id)) {
            return false;
        }

        $baselines = get_option('sentinel_file_baselines', array());

        // Search through all files and their changes
        foreach ($baselines as $filename => $file_data) {
            if (isset($file_data['changes']) && is_array($file_data['changes'])) {
                foreach ($file_data['changes'] as $change) {
                    if (isset($change['baseline_id']) && $change['baseline_id'] === $baseline_id) {
                        // Return the change data with filename context
                        return array(
                            'filename' => $filename,
                            'change_data' => $change,
                            'current_content' => isset($file_data['content']) ? $file_data['content'] : '',
                            'current_timestamp' => isset($file_data['timestamp']) ? $file_data['timestamp'] : ''
                        );
                    }
                }
            }
        }

        return false;
    }

    /**
     * Sentinel+: AJAX handler for diff viewer requests
     */
    public static function ajax_get_file_diff()
    {
        // Security check
        if (!sentinel_is_premium() || !current_user_can('manage_options')) {
            wp_send_json_error('Access denied');
            return;
        }

        // Validate nonce
        if (!wp_verify_nonce($_POST['nonce'] ?? '', 'sentinel_admin_nonce')) {
            wp_send_json_error('Invalid security token');
            return;
        }

        $baseline_id = sanitize_text_field($_POST['baseline_id'] ?? '');
        if (empty($baseline_id)) {
            wp_send_json_error('Invalid baseline ID');
            return;
        }

        // Get baseline change data
        $change_data = self::get_baseline_change_data($baseline_id);
        if (!$change_data) {
            wp_send_json_error('Baseline data not found');
            return;
        }

        // Prepare response data
        $response = array(
            'filename' => $change_data['filename'],
            'detected_at' => $change_data['change_data']['detected_at'] ?? '',
            'summary' => $change_data['change_data']['summary'] ?? 'No summary available',
            'diff' => $change_data['change_data']['diff'] ?? 'No diff available',
            'lines_added' => $change_data['change_data']['lines_added'] ?? 0,
            'lines_removed' => $change_data['change_data']['lines_removed'] ?? 0,
            'lines_modified' => $change_data['change_data']['lines_modified'] ?? 0
        );

        wp_send_json_success($response);
    }
}
