<?php

/**
 * Sentinel Cleanup Class
 * 
 * Handles log cleanup and maintenance tasks.
 */

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

class Sentinel_Cleanup
{

    public function __construct()
    {
        // Constructor
    }

    /**
     * Initialize cleanup hooks
     */
    public static function init()
    {
        add_action('sentinel_cleanup_logs', array(__CLASS__, 'cleanup_old_logs'));

        // Migration: if an existing install had only sentinel_optimize_tables and neither
        // optimize hook is scheduled, schedule sentinel_optimize_database so optimization
        // is not silently lost after the legacy hook is removed.
        if (!wp_next_scheduled('sentinel_optimize_database') && !wp_next_scheduled('sentinel_optimize_tables')) {
            wp_schedule_event(time(), 'weekly', 'sentinel_optimize_database');
        }

        // Clear legacy sentinel_optimize_tables if it is still scheduled from a prior version.
        if (wp_next_scheduled('sentinel_optimize_tables')) {
            wp_clear_scheduled_hook('sentinel_optimize_tables');
        }
    }

    /**
     * Clean up old log entries (default: 30 days)
     * 
     * @param int $days_to_keep Number of days to keep logs (default: 30)
     * @return int Number of deleted records
     */
    public static function cleanup_old_logs($days_to_keep = 30)
    {
        global $wpdb;

        $table = $wpdb->prefix . 'sentinel_logs';

        // Delete logs older than specified days
        $deleted = $wpdb->query(
            $wpdb->prepare(
                "DELETE FROM $table WHERE created_at < DATE_SUB(NOW(), INTERVAL %d DAY)",
                $days_to_keep
            )
        );

        // Log the cleanup action
        if ($deleted > 0) {
            sentinel_log_event('logs_cleaned', array(
                'deleted_count' => $deleted,
                'days_kept' => $days_to_keep,
                'cleanup_date' => current_time('mysql')
            ));
        }

        return $deleted;
    }

    /**
     * Archive old logs to a separate table
     * 
     * @param int $days_to_archive Number of days old to archive (default: 90)
     * @return int Number of archived records
     */
    public static function archive_logs($days_to_archive = 90)
    {
        global $wpdb;

        $logs_table = $wpdb->prefix . 'sentinel_logs';
        $archive_table = $wpdb->prefix . 'sentinel_logs_archive';

        // Note: Archive table should be created by migration, not here

        // Move old logs to archive table
        $archived = $wpdb->query(
            $wpdb->prepare(
                "INSERT INTO $archive_table 
                 SELECT * FROM $logs_table 
                 WHERE created_at < DATE_SUB(NOW(), INTERVAL %d DAY)",
                $days_to_archive
            )
        );

        // Delete archived logs from main table
        if ($archived > 0) {
            $wpdb->query(
                $wpdb->prepare(
                    "DELETE FROM $logs_table 
                     WHERE created_at < DATE_SUB(NOW(), INTERVAL %d DAY)",
                    $days_to_archive
                )
            );
        }

        return $archived;
    }



    /**
     * Optimize database tables
     */
    public static function optimize_tables()
    {
        global $wpdb;

        $tables = array(
            $wpdb->prefix . 'sentinel_logs',
            $wpdb->prefix . 'sentinel_logs_archive'
        );

        $optimized = 0;
        foreach ($tables as $table) {
            if ($wpdb->get_var("SHOW TABLES LIKE '$table'") == $table) {
                $result = $wpdb->query("OPTIMIZE TABLE $table");
                if ($result !== false) {
                    $optimized++;
                }
            }
        }

        // Log the optimization
        if ($optimized > 0) {
            sentinel_log_event('tables_optimized', array(
                'tables_optimized' => $optimized,
                'optimization_date' => current_time('mysql')
            ));
        }

        return $optimized;
    }

    /**
     * Get database statistics
     * 
     * @return array Database statistics
     */
    public static function get_database_stats()
    {
        global $wpdb;

        $logs_table = $wpdb->prefix . 'sentinel_logs';
        $archive_table = $wpdb->prefix . 'sentinel_logs_archive';

        $stats = array(
            'logs_count' => 0,
            'archive_count' => 0,
            'logs_size' => 0,
            'archive_size' => 0,
            'total_size' => 0
        );

        // Get logs table stats
        if ($wpdb->get_var("SHOW TABLES LIKE '$logs_table'") == $logs_table) {
            $stats['logs_count'] = $wpdb->get_var("SELECT COUNT(*) FROM $logs_table");
            $size_result = $wpdb->get_row("SELECT 
                ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb 
                FROM information_schema.tables 
                WHERE table_schema = DATABASE() AND table_name = '$logs_table'");
            $stats['logs_size'] = $size_result ? $size_result->size_mb : 0;
        }

        // Get archive table stats
        if ($wpdb->get_var("SHOW TABLES LIKE '$archive_table'") == $archive_table) {
            $stats['archive_count'] = $wpdb->get_var("SELECT COUNT(*) FROM $archive_table");
            $size_result = $wpdb->get_row("SELECT 
                ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb 
                FROM information_schema.tables 
                WHERE table_schema = DATABASE() AND table_name = '$archive_table'");
            $stats['archive_size'] = $size_result ? $size_result->size_mb : 0;
        }

        $stats['total_size'] = $stats['logs_size'] + $stats['archive_size'];

        return $stats;
    }

    /**
     * Manual cleanup trigger for admin interface
     * 
     * @param int $days_to_keep Number of days to keep
     * @return array Result information
     */
    public static function manual_cleanup($days_to_keep = 30)
    {
        $deleted = self::cleanup_old_logs($days_to_keep);
        $optimized = self::optimize_tables();

        return array(
            'deleted_logs' => $deleted,
            'optimized_tables' => $optimized,
            'days_kept' => $days_to_keep,
            'timestamp' => current_time('mysql')
        );
    }

    /**
     * Anonymize logs older than the configured threshold in both main and archive tables.
     * Should be called daily via cron for compliance.
     *
     * The interval is always fetched from plugin settings ('anonymize_schedule').
     */
    public static function anonymize_old_logs($force_all = false)
    {
        global $wpdb;
        $settings = get_option('sentinel_log_management', array());
        $anonymize_days = !empty($settings['anonymize_schedule']) && is_numeric($settings['anonymize_schedule']) ? intval($settings['anonymize_schedule']) : 30;
        $tables = [
            $wpdb->prefix . 'sentinel_logs',
            $wpdb->prefix . 'sentinel_logs_archive'
        ];
        if ($force_all) {
            $cutoff = '2100-01-01 00:00:00';
            error_log('[Sentinel] Anonymizer: Running in FORCE ALL mode (manual trigger)');
        } else {
            $cutoff = date('Y-m-d H:i:s', time() - ($anonymize_days * DAY_IN_SECONDS));
            error_log("[Sentinel] Anonymizer: Running in INTERVAL mode, cutoff: $cutoff");
        }
        $summary = array();
        foreach ($tables as $table) {
            $logs = $wpdb->get_results($wpdb->prepare(
                "SELECT * FROM $table WHERE created_at < %s",
                $cutoff
            ));
            $found = count($logs);
            $anonymized = 0;
            error_log("[Sentinel] Anonymizer: Found $found logs in $table older than $cutoff");
            foreach ($logs as $log) {
                if (strpos($log->ip_address, '.xxx.xxx') !== false) continue;
                $anonymized_ip = $log->ip_address;
                if (!empty($anonymized_ip) && filter_var($anonymized_ip, FILTER_VALIDATE_IP)) {
                    $parts = explode('.', $anonymized_ip);
                    if (count($parts) === 4) {
                        $anonymized_ip = $parts[0] . '.' . $parts[1] . '.xxx.xxx';
                    }
                }
                $anonymized_data = $log->data;
                if (!empty($anonymized_data)) {
                    $data_arr = json_decode($anonymized_data, true);
                    if (is_array($data_arr)) {
                        if (isset($data_arr['email']) && is_string($data_arr['email'])) {
                            $email = $data_arr['email'];
                            $at = strpos($email, '@');
                            if ($at !== false && $at > 0) {
                                $user = substr($email, 0, 1) . 'xxx';
                                $domain = substr($email, $at + 1);
                                $dot = strpos($domain, '.');
                                if ($dot !== false && $dot > 0) {
                                    $domain_part = substr($domain, 0, 1) . 'xxxx';
                                    $tld = substr($domain, $dot);
                                    $data_arr['email'] = $user . '@' . $domain_part . $tld;
                                } else {
                                    $data_arr['email'] = $user . '@xxxx';
                                }
                            } else {
                                $data_arr['email'] = 'xxx';
                            }
                        }
                        if (isset($data_arr['username']) && is_string($data_arr['username'])) {
                            $uname = $data_arr['username'];
                            $data_arr['username'] = substr($uname, 0, 1) . 'xxx';
                        }
                        $anonymized_data = json_encode($data_arr);
                    }
                }
                $anonymized_user_agent = $log->user_agent;
                $updated = $wpdb->update(
                    $table,
                    [
                        'ip_address' => $anonymized_ip,
                        'data' => $anonymized_data
                    ],
                    ['id' => $log->id],
                    ['%s', '%s'],
                    ['%d']
                );
                if ($updated !== false) {
                    $anonymized++;
                }
            }
            error_log("[Sentinel] Anonymizer: Anonymized $anonymized logs in $table");
            $summary[$table] = array('found' => $found, 'anonymized' => $anonymized);
        }

        // Log the anonymization event if any logs were anonymized
        $total_anonymized = array_sum(array_column($summary, 'anonymized'));
        if ($total_anonymized > 0) {
            if (function_exists('sentinel_log_event')) {
                sentinel_log_event('user_data_anonymized', array(
                    'anonymized_count' => $total_anonymized,
                    'tables_processed' => array_keys($summary),
                    'force_all' => $force_all,
                    'anonymization_date' => current_time('mysql')
                ));
                error_log("[Sentinel] Logged anonymization event: $total_anonymized logs anonymized");
            }
        }

        return $summary;
    }

    /**
     * Schedule cron jobs for log cleanup
     */
    public function schedule_cleanup()
    {
        $settings = get_option('sentinel_log_management', array());

        if (!empty($settings['cleanup_enabled'])) {
            $schedule = !empty($settings['cleanup_schedule']) ? $settings['cleanup_schedule'] : 'daily';

            if (!wp_next_scheduled('sentinel_cleanup_logs')) {
                wp_schedule_event(time(), $schedule, 'sentinel_cleanup_logs');
            }
        }

        if (!empty($settings['db_optimization_enabled'])) {
            $schedule = !empty($settings['db_optimization_schedule']) ? $settings['db_optimization_schedule'] : 'weekly';

            if (!wp_next_scheduled('sentinel_optimize_database')) {
                wp_schedule_event(time(), $schedule, 'sentinel_optimize_database');
            }
        }
    }

    /**
     * Unschedule cron jobs for log cleanup
     */
    public function unschedule_cleanup()
    {
        wp_clear_scheduled_hook('sentinel_cleanup_logs');
        wp_clear_scheduled_hook('sentinel_optimize_database');
    }

    /**
     * Archive old logs from the main table to the archive table based on age/count.
     * If $manual_override is true, archive all logs.
     * Returns the number of archived logs.
     */
    public function cleanup_logs($manual_override = false)
    {
        global $wpdb;
        $main_table = $wpdb->prefix . 'sentinel_logs';
        $archive_table = $wpdb->prefix . 'sentinel_logs_archive';
        $archived_count = 0;
        $settings = get_option('sentinel_log_management', array());

        if ($manual_override) {
            $logs_to_archive = $wpdb->get_results("SELECT * FROM $main_table ORDER BY created_at ASC");
            error_log('[Sentinel Cleanup] Manual override: Found ' . count($logs_to_archive) . ' logs to archive.');
        } else {
            $age_days = !empty($settings['cleanup_age_days']) ? $settings['cleanup_age_days'] : 90;
            $max_entries = !empty($settings['cleanup_max_entries']) ? $settings['cleanup_max_entries'] : 10000;
            $cutoff_date = date('Y-m-d H:i:s', strtotime("-{$age_days} days"));
            $old_logs = $wpdb->get_results($wpdb->prepare(
                "SELECT * FROM $main_table WHERE created_at < %s ORDER BY created_at ASC",
                $cutoff_date
            ));
            $total_logs = $wpdb->get_var("SELECT COUNT(*) FROM $main_table");
            $count_logs = array();
            if ($total_logs > $max_entries) {
                $excess_count = $total_logs - $max_entries;
                $count_logs = $wpdb->get_results($wpdb->prepare(
                    "SELECT * FROM $main_table ORDER BY created_at ASC LIMIT %d",
                    $excess_count
                ));
            }
            $logs_to_archive = array();
            foreach ($old_logs as $log) {
                $logs_to_archive[$log->id] = $log;
            }
            foreach ($count_logs as $log) {
                $logs_to_archive[$log->id] = $log;
            }
            error_log('[Sentinel Cleanup] Auto mode: Found ' . count($logs_to_archive) . ' logs to archive.');
        }
        if (!empty($logs_to_archive)) {
            foreach ($logs_to_archive as $log) {
                $result = $wpdb->insert(
                    $archive_table,
                    array(
                        'event_key' => $log->event_key,
                        'category' => $log->category,
                        'priority' => $log->priority,
                        'user_id' => $log->user_id,
                        'ip_address' => $log->ip_address,
                        'user_agent' => $log->user_agent,
                        'url' => $log->url,
                        'data' => $log->data,
                        'created_at' => $log->created_at,
                        'archived_at' => current_time('mysql')
                    ),
                    array('%s', '%s', '%s', '%d', '%s', '%s', '%s', '%s', '%s', '%s')
                );
                if ($result) {
                    $wpdb->delete($main_table, array('id' => $log->id), array('%d'));
                    $archived_count++;
                    error_log('[Sentinel Cleanup] Archived log ID ' . $log->id . ' successfully.');
                } else {
                    error_log('[Sentinel Cleanup] Failed to archive log ID ' . $log->id . '. $wpdb->last_error: ' . $wpdb->last_error);
                }
            }
        } else {
            error_log('[Sentinel Cleanup] No logs to archive.');
        }
        // Clean up old archived logs
        if (method_exists($this, 'cleanup_archived_logs')) {
            $this->cleanup_archived_logs();
        }
        error_log('[Sentinel Cleanup] Total archived logs: ' . $archived_count);
        return $archived_count;
    }

    /**
     * Clean up old archived logs based on retention settings
     */
    private function cleanup_archived_logs()
    {
        $settings = get_option('sentinel_log_management', array());
        $retention_type = !empty($settings['archive_retention_type']) ? $settings['archive_retention_type'] : '1year';

        if ($retention_type === 'forever') {
            return;
        }

        global $wpdb;
        $archive_table = $wpdb->prefix . 'sentinel_logs_archive';

        // Calculate retention days
        $retention_days = 365; // Default 1 year

        switch ($retention_type) {
            case '6months':
                $retention_days = 180;
                break;
            case '1year':
                $retention_days = 365;
                break;
            case '2years':
                $retention_days = 730;
                break;
            case 'custom':
                $retention_days = !empty($settings['archive_retention_days']) ? $settings['archive_retention_days'] : 365;
                break;
        }

        // Delete old archived logs
        $cutoff_date = date('Y-m-d H:i:s', strtotime("-{$retention_days} days"));
        $deleted_count = $wpdb->query($wpdb->prepare(
            "DELETE FROM $archive_table WHERE archived_at < %s",
            $cutoff_date
        ));

        if ($deleted_count > 0) {
            error_log("Sentinel: Permanently deleted {$deleted_count} archived logs older than {$retention_days} days");
        }

        return $deleted_count;
    }

    /**
     * Optimize database tables
     */
    public function optimize_database()
    {
        global $wpdb;
        $main_table = $wpdb->prefix . 'sentinel_logs';
        $archive_table = $wpdb->prefix . 'sentinel_logs_archive';

        $results = array();

        // Get table sizes before optimization
        $main_size_before = $wpdb->get_var("SELECT ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = '$main_table'");
        $archive_size_before = $wpdb->get_var("SELECT ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = '$archive_table'");

        // Optimize main table
        $main_result = $wpdb->query("OPTIMIZE TABLE $main_table");
        $results['main_table'] = $main_result !== false ? 'Success' : 'Failed';

        // Optimize archive table
        $archive_result = $wpdb->query("OPTIMIZE TABLE $archive_table");
        $results['archive_table'] = $archive_result !== false ? 'Success' : 'Failed';

        // Update table statistics
        $wpdb->query("ANALYZE TABLE $main_table");
        $wpdb->query("ANALYZE TABLE $archive_table");

        // Get table sizes after optimization
        $main_size_after = $wpdb->get_var("SELECT ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = '$main_table'");
        $archive_size_after = $wpdb->get_var("SELECT ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = '$archive_table'");

        $results['main_size_before'] = $main_size_before ?: 0;
        $results['main_size_after'] = $main_size_after ?: 0;
        $results['archive_size_before'] = $archive_size_before ?: 0;
        $results['archive_size_after'] = $archive_size_after ?: 0;
        $results['space_saved'] = ($main_size_before + $archive_size_before) - ($main_size_after + $archive_size_after);

        error_log("Sentinel: Database optimization completed - Space saved: " . $results['space_saved'] . " MB");

        return $results;
    }

    /**
     * Handle manual cleanup action
     */
    public function handle_manual_cleanup()
    {
        if (
            isset($_GET['action']) && $_GET['action'] === 'cleanup_now' &&
            isset($_GET['page']) && $_GET['page'] === 'sentinel-settings'
        ) {

            if (!current_user_can('manage_options')) {
                wp_die('Insufficient permissions');
            }

            $archived_count = $this->cleanup_logs(true);

            wp_redirect(add_query_arg(array(
                'page' => 'sentinel-settings',
                'message' => 'cleanup_success',
                'count' => $archived_count
            ), admin_url('admin.php')));
            exit;
        }
    }

    /**
     * Handle manual optimization action
     */
    public function handle_manual_optimization()
    {
        if (
            isset($_GET['action']) && $_GET['action'] === 'optimize_now' &&
            isset($_GET['page']) && $_GET['page'] === 'sentinel-settings'
        ) {

            if (!current_user_can('manage_options')) {
                wp_die('Insufficient permissions');
            }

            $this->optimize_database();

            wp_redirect(add_query_arg(array(
                'page' => 'sentinel-settings',
                'message' => 'optimize_success'
            ), admin_url('admin.php')));
            exit;
        }
    }

    /**
     * Display admin notices for manual actions
     */
    public function display_admin_notices()
    {
        if (isset($_GET['message']) && isset($_GET['page']) && $_GET['page'] === 'sentinel-settings') {
            switch ($_GET['message']) {
                case 'cleanup_success':
                    $count = isset($_GET['count']) ? intval($_GET['count']) : 0;
                    echo '<div class="notice notice-success is-dismissible"><p>✅ Cleanup completed successfully! Archived ' . $count . ' logs.</p></div>';
                    break;
                case 'optimize_success':
                    $main_table = isset($_GET['main_table']) ? sanitize_text_field($_GET['main_table']) : 'Unknown';
                    $archive_table = isset($_GET['archive_table']) ? sanitize_text_field($_GET['archive_table']) : 'Unknown';
                    $space_saved = isset($_GET['space_saved']) ? floatval($_GET['space_saved']) : 0;

                    $message = "⚡ Database optimization completed successfully!<br>";
                    $message .= "<strong>Main Table:</strong> {$main_table} | ";
                    $message .= "<strong>Archive Table:</strong> {$archive_table}<br>";
                    $message .= "<strong>Space Saved:</strong> " . number_format($space_saved, 2) . " MB";

                    echo '<div class="notice notice-success is-dismissible"><p>' . $message . '</p></div>';
                    break;
            }
        }
    }
}
