<?php
/**
 * Simple Cleanup Module
 *
 * Provides basic database cleanup functionality for the free plugin.
 * Cleans up old records from plugin tables.
 *
 * @package     WPUltimateSecurity\UltimateSecurity\Modules\Maintenance
 * @since       2.1.0
 */

declare(strict_types=1);

namespace WPUltimateSecurity\UltimateSecurity\Modules\Maintenance;

use WPUltimateSecurity\UltimateSecurity\Modules\Base\AbstractModule;
use WPUltimateSecurity\UltimateSecurity\Support\Helpers\Utils;

/**
 * Simple Cleanup Module
 *
 * Provides database cleanup for:
 * - URL Guard request logs
 * - Test mode simulations
 * - Audit logs
 *
 * @since 2.1.0
 */
class SimpleCleanup extends AbstractModule
{
    /**
     * Module version
     */
    protected const VERSION = '2.1.0';

    /**
     * Tables that can be cleaned up
     */
    private const CLEANABLE_TABLES = [
        'url_guard_requestslog' => [
            'name' => 'URL Guard Request Logs',
            'date_column' => 'created_at',
            'default_retention_days' => 30,
        ],
        'testmode_simulations' => [
            'name' => 'Test Mode Simulations',
            'date_column' => 'created_at',
            'default_retention_days' => 30,
        ],
        'audit_logs' => [
            'name' => 'Audit Logs',
            'date_column' => 'created_at',
            'default_retention_days' => 30,
        ],
    ];

    /**
     * Get unique module identifier.
     *
     * @return string
     */
    public static function getId(): string
    {
        return 'simple_cleanup';
    }

    /**
     * Get human-readable module name.
     *
     * @return string
     */
    public static function getName(): string
    {
        return __('Database Cleanup', 'ultimate-security');
    }

    /**
     * Get module domain.
     *
     * @return string
     */
    public static function getDomain(): string
    {
        return 'maintenance';
    }

    /**
     * Check if module is enabled.
     *
     * @return bool
     */
    public static function isEnabled(): bool
    {
        return true; // Always enabled for maintenance
    }

    /**
     * Boot the module - register REST API routes.
     *
     * @return void
     */
    public static function boot(): void
    {
        add_action('rest_api_init', [self::class, 'register_rest_routes']);

        // Schedule weekly cleanup
        if (!wp_next_scheduled('ultimate_security_weekly_cleanup')) {
            wp_schedule_event(time(), 'weekly', 'ultimate_security_weekly_cleanup');
        }
        add_action('ultimate_security_weekly_cleanup', [self::class, 'run_scheduled_cleanup']);
    }

    /**
     * Register REST API routes.
     *
     * @return void
     */
    public static function register_rest_routes(): void
    {
        register_rest_route('ultimate-security/v1', '/simple-cleanup/stats', [
            'methods' => 'GET',
            'callback' => [self::class, 'get_stats_endpoint'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ]);

        register_rest_route('ultimate-security/v1', '/simple-cleanup/delete', [
            'methods' => 'POST',
            'callback' => [self::class, 'delete_endpoint'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
            'args' => [
                'table' => [
                    'required' => true,
                    'sanitize_callback' => 'sanitize_key',
                ],
                'days' => [
                    'default' => 30,
                    'sanitize_callback' => 'absint',
                ],
            ],
        ]);

        register_rest_route('ultimate-security/v1', '/simple-cleanup/delete-all', [
            'methods' => 'POST',
            'callback' => [self::class, 'delete_all_endpoint'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
            'args' => [
                'days' => [
                    'default' => 30,
                    'sanitize_callback' => 'absint',
                ],
            ],
        ]);
    }

    /**
     * Get table statistics.
     *
     * @return array<string, array{name: string, total: int, size: string, oldest: string|null}>
     */
    public static function get_table_stats(): array
    {
        global $wpdb;
        $stats = [];

        foreach (self::CLEANABLE_TABLES as $table_key => $table_info) {
            $table_name = $wpdb->prefix . 'ultimate_security_' . $table_key;

            // Check if table exists
            $table_exists = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name));
            if (!$table_exists) {
                continue;
            }

            // Get total count
            $total = (int) $wpdb->get_var("SELECT COUNT(*) FROM `{$table_name}`"); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared

            // Get table size
            $size_result = $wpdb->get_row($wpdb->prepare(
                "SELECT
                    ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024, 2) as size_kb
                FROM information_schema.TABLES
                WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s",
                DB_NAME,
                $table_name
            ));
            $size_kb = $size_result ? (float) $size_result->size_kb : 0;

            // Format size
            if ($size_kb >= 1024) {
                $size = round($size_kb / 1024, 2) . ' MB';
            } else {
                $size = $size_kb . ' KB';
            }

            // Get oldest record
            $date_column = $table_info['date_column'];
            $oldest = $wpdb->get_var("SELECT MIN(`{$date_column}`) FROM `{$table_name}`"); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared

            $stats[$table_key] = [
                'name' => $table_info['name'],
                'total' => $total,
                'size' => $size,
                'oldest' => $oldest,
                'default_retention_days' => $table_info['default_retention_days'],
            ];
        }

        return $stats;
    }

    /**
     * Delete old records from a specific table.
     *
     * @param string $table_key Table key (e.g., 'url_guard_requestslog')
     * @param int $days Delete records older than this many days
     * @return int Number of deleted rows
     */
    public static function delete_old_records(string $table_key, int $days): int
    {
        global $wpdb;

        if (!isset(self::CLEANABLE_TABLES[$table_key])) {
            return 0;
        }

        $table_info = self::CLEANABLE_TABLES[$table_key];
        $table_name = $wpdb->prefix . 'ultimate_security_' . $table_key;
        $date_column = $table_info['date_column'];

        // Check if table exists
        $table_exists = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name));
        if (!$table_exists) {
            return 0;
        }

        $cutoff_date = date('Y-m-d H:i:s', strtotime("-{$days} days"));

        $deleted = $wpdb->query($wpdb->prepare(
            "DELETE FROM `{$table_name}` WHERE `{$date_column}` < %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            $cutoff_date
        ));

        return $deleted !== false ? (int) $deleted : 0;
    }

    /**
     * Delete old records from all tables.
     *
     * @param int $days Delete records older than this many days
     * @return array<string, int> Deleted counts per table
     */
    public static function delete_all_old_records(int $days): array
    {
        $results = [];

        foreach (array_keys(self::CLEANABLE_TABLES) as $table_key) {
            $results[$table_key] = self::delete_old_records($table_key, $days);
        }

        return $results;
    }

    /**
     * Run scheduled cleanup.
     *
     * @return void
     */
    public static function run_scheduled_cleanup(): void
    {
        $options = Utils::ultimate_security_get_option();
        $retention_days = isset($options['maintenance']['cleanup']['retention_days'])
            ? absint($options['maintenance']['cleanup']['retention_days'])
            : 30;

        if ($retention_days < 7) {
            $retention_days = 7; // Minimum 7 days retention
        }

        self::delete_all_old_records($retention_days);
    }

    /**
     * REST endpoint: Get table statistics.
     *
     * @param \WP_REST_Request $request Request object.
     * @return \WP_REST_Response
     */
    public static function get_stats_endpoint(\WP_REST_Request $request): \WP_REST_Response
    {
        $stats = self::get_table_stats();

        return new \WP_REST_Response([
            'success' => true,
            'data' => [
                'tables' => $stats,
                'total_size' => self::get_total_size($stats),
            ],
        ], 200);
    }

    /**
     * REST endpoint: Delete old records from a specific table.
     *
     * @param \WP_REST_Request $request Request object.
     * @return \WP_REST_Response
     */
    public static function delete_endpoint(\WP_REST_Request $request): \WP_REST_Response
    {
        $table = $request->get_param('table');
        $days = $request->get_param('days');

        if (!isset(self::CLEANABLE_TABLES[$table])) {
            return new \WP_REST_Response([
                'success' => false,
                'message' => __('Invalid table specified.', 'ultimate-security'),
            ], 400);
        }

        $deleted = self::delete_old_records($table, $days);

        return new \WP_REST_Response([
            'success' => true,
            'message' => sprintf(
                /* translators: 1: Number of records deleted, 2: Table name, 3: Number of days */
                __('Deleted %1$d records from %2$s older than %3$d days.', 'ultimate-security'),
                $deleted,
                self::CLEANABLE_TABLES[$table]['name'],
                $days
            ),
            'deleted' => $deleted,
        ], 200);
    }

    /**
     * REST endpoint: Delete old records from all tables.
     *
     * @param \WP_REST_Request $request Request object.
     * @return \WP_REST_Response
     */
    public static function delete_all_endpoint(\WP_REST_Request $request): \WP_REST_Response
    {
        $days = $request->get_param('days');
        $results = self::delete_all_old_records($days);

        $total_deleted = array_sum($results);

        return new \WP_REST_Response([
            'success' => true,
            'message' => sprintf(
                /* translators: 1: Number of records deleted, 2: Number of days */
                __('Deleted %1$d total records older than %2$d days.', 'ultimate-security'),
                $total_deleted,
                $days
            ),
            'deleted' => $results,
            'total_deleted' => $total_deleted,
        ], 200);
    }

    /**
     * Calculate total size from stats.
     *
     * @param array $stats Table statistics.
     * @return string Formatted total size.
     */
    private static function get_total_size(array $stats): string
    {
        $total_kb = 0;

        foreach ($stats as $table_stat) {
            $size = $table_stat['size'];
            if (strpos($size, 'MB') !== false) {
                $total_kb += (float) str_replace(' MB', '', $size) * 1024;
            } else {
                $total_kb += (float) str_replace(' KB', '', $size);
            }
        }

        if ($total_kb >= 1024) {
            return round($total_kb / 1024, 2) . ' MB';
        }

        return round($total_kb, 2) . ' KB';
    }
}
