<?php
if (!defined('ABSPATH')) {
    exit;
}

class BotBlocker_Admin {
    public static function init() {
        add_action('admin_menu', [__CLASS__, 'menu']);
        add_action('admin_enqueue_scripts', [__CLASS__, 'assets']);
        add_action('rest_api_init', [__CLASS__, 'rest']);
        add_action('admin_init', [__CLASS__, 'maybe_handle_logs']);
        add_action('admin_post_bot_blocker_save_rules', [__CLASS__, 'save_rules']);
        add_action('admin_post_bot_blocker_save_lists', [__CLASS__, 'save_lists']);
        add_action('admin_post_bot_blocker_save_settings', [__CLASS__, 'save_settings']);
        add_action('admin_post_bot_blocker_logs', [__CLASS__, 'handle_logs']);

        // Multisite: add a Network Admin menu for network-wide settings.
        if (is_multisite()) {
            add_action('network_admin_menu', [__CLASS__, 'network_menu']);
            add_action('network_admin_edit_bot_blocker_network_settings', [__CLASS__, 'save_network_settings']);
        }
    }

    /**
     * Registers the Network Admin menu page (multisite only).
     */
    public static function network_menu() {
        add_menu_page(
            __('Botcrawl Bot Blocker', 'bot-blocker'),
            __('Bot Blocker', 'bot-blocker'),
            'manage_network_options',
            'bot-blocker-network',
            [__CLASS__, 'render_network_settings'],
            'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjYTdhYWFkIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xMCAxbDcgM3Y1YzAgNC40LTIuNiA3LjgtNyAxMC00LjQtMi4yLTctNS42LTctMTBWNGw3LTN6bS0uOCAzLjhoMS42djEuOEg5LjJWNC44ek01LjUgNi4yaDl2NS44YTEuNCAxLjQgMCAwMS0xLjQgMS40SDYuOUExLjQgMS40IDAgMDE1LjUgMTJWNi4yek03LjMgNy44aDEuNnYxLjZINy4zVjcuOHptMy44IDBoMS42djEuNmgtMS42VjcuOHptLTMgMi4zaDMuOHYxSDguMXYtMXoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==',
            58
        );
    }

    /**
     * Renders the Network Admin settings page.
     */
    public static function render_network_settings() {
        if (!current_user_can('manage_network_options')) {
            wp_die(__('You do not have permission to access this page.', 'bot-blocker'));
        }

        $saved = false;
        if (isset($_GET['updated'])) {
            $saved = true;
        }

        // Network-level options stored in site meta.
        $network_enforcement = (bool) get_site_option('bot_blocker_network_enforcement', true);
        $network_logging     = (bool) get_site_option('bot_blocker_network_logging', true);
        $allow_site_override = (bool) get_site_option('bot_blocker_allow_site_override', true);
        $license_key         = (string) get_site_option('bot_blocker_network_license_key', '');
        ?>
        <div class="wrap bot-blocker-wrap">
            <h1><?php esc_html_e('Botcrawl Bot Blocker - Network Settings', 'bot-blocker'); ?></h1>

            <?php if ($saved) : ?>
            <div class="notice notice-success is-dismissible"><p><?php esc_html_e('Network settings saved.', 'bot-blocker'); ?></p></div>
            <?php endif; ?>

            <form method="post" action="edit.php?action=bot_blocker_network_settings">
                <?php wp_nonce_field('bot_blocker_network_settings_nonce', 'bot_blocker_nonce'); ?>

                <table class="form-table">
                    <tr>
                        <th scope="row"><?php esc_html_e('Network Enforcement', 'bot-blocker'); ?></th>
                        <td>
                            <label>
                                <input type="checkbox" name="network_enforcement" value="1" <?php checked($network_enforcement); ?> />
                                <?php esc_html_e('Enable bot enforcement across all sites in this network', 'bot-blocker'); ?>
                            </label>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><?php esc_html_e('Network Logging', 'bot-blocker'); ?></th>
                        <td>
                            <label>
                                <input type="checkbox" name="network_logging" value="1" <?php checked($network_logging); ?> />
                                <?php esc_html_e('Enable bot event logging across all sites in this network', 'bot-blocker'); ?>
                            </label>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><?php esc_html_e('Allow Per-Site Override', 'bot-blocker'); ?></th>
                        <td>
                            <label>
                                <input type="checkbox" name="allow_site_override" value="1" <?php checked($allow_site_override); ?> />
                                <?php esc_html_e('Allow individual site admins to override network settings', 'bot-blocker'); ?>
                            </label>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><?php esc_html_e('Network License Key', 'bot-blocker'); ?></th>
                        <td>
                            <input type="text" name="network_license_key" value="<?php echo esc_attr($license_key); ?>" class="regular-text" placeholder="SERA-XXXX-XXXX-XXXX-XXXX" />
                            <p class="description"><?php esc_html_e('A single license key covers all sites in this network. Purchase at sera.guru.', 'bot-blocker'); ?></p>
                        </td>
                    </tr>
                </table>

                <?php submit_button(__('Save Network Settings', 'bot-blocker')); ?>
            </form>
        </div>
        <?php
    }

    /**
     * Handles saving of network settings (called via network_admin_edit hook).
     */
    public static function save_network_settings() {
        if (!current_user_can('manage_network_options')) {
            wp_die(__('You do not have permission to perform this action.', 'bot-blocker'));
        }

        check_admin_referer('bot_blocker_network_settings_nonce', 'bot_blocker_nonce');

        update_site_option('bot_blocker_network_enforcement', !empty($_POST['network_enforcement']));
        update_site_option('bot_blocker_network_logging',     !empty($_POST['network_logging']));
        update_site_option('bot_blocker_allow_site_override', !empty($_POST['allow_site_override']));

        $license_key = sanitize_text_field(wp_unslash($_POST['network_license_key'] ?? ''));
        if ($license_key !== '') {
            update_site_option('bot_blocker_network_license_key', $license_key);
            // Propagate the license key to all sites in the network.
            $sites = get_sites(['number' => 500, 'fields' => 'ids']);
            foreach ($sites as $site_id) {
                update_blog_option((int) $site_id, 'sera_bb_license_key', $license_key);
            }
        }

        wp_redirect(network_admin_url('admin.php?page=bot-blocker-network&updated=1'));
        exit;
    }

    public static function menu() {
        add_menu_page(__('Bot Blocker', 'bot-blocker'), __('Bot Blocker', 'bot-blocker'), 'manage_options', 'bot-blocker', [__CLASS__, 'render_monitor'], 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBmaWxsPSIjYTdhYWFkIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xMCAxbDcgM3Y1YzAgNC40LTIuNiA3LjgtNyAxMC00LjQtMi4yLTctNS42LTctMTBWNGw3LTN6bS0uOCAzLjhoMS42djEuOEg5LjJWNC44ek01LjUgNi4yaDl2NS44YTEuNCAxLjQgMCAwMS0xLjQgMS40SDYuOUExLjQgMS40IDAgMDE1LjUgMTJWNi4yek03LjMgNy44aDEuNnYxLjZINy4zVjcuOHptMy44IDBoMS42djEuNmgtMS42VjcuOHptLTMgMi4zaDMuOHYxSDguMXYtMXoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==', 58);
        add_submenu_page('bot-blocker', __('Live Monitor', 'bot-blocker'), __('Live Monitor', 'bot-blocker'), 'manage_options', 'bot-blocker', [__CLASS__, 'render_monitor']);
        add_submenu_page('bot-blocker', __('Rules', 'bot-blocker'), __('Rules', 'bot-blocker'), 'manage_options', 'bot-blocker-rules', [__CLASS__, 'render_rules']);
        add_submenu_page('bot-blocker', __('Lists', 'bot-blocker'), __('Lists', 'bot-blocker'), 'manage_options', 'bot-blocker-lists', [__CLASS__, 'render_lists']);
        add_submenu_page('bot-blocker', __('Logs', 'bot-blocker'), __('Logs', 'bot-blocker'), 'manage_options', 'bot-blocker-logs', [__CLASS__, 'render_logs']);
        add_submenu_page('bot-blocker', __('Settings', 'bot-blocker'), __('Settings', 'bot-blocker'), 'manage_options', 'bot-blocker-settings', [__CLASS__, 'render_settings']);
    }

    public static function assets($hook) {
        if (strpos((string) $hook, 'bot-blocker') === false) {
            return;
        }

        wp_enqueue_style('bot-blocker-admin', BOT_BLOCKER_URL . 'assets/css/admin.css', [], BOT_BLOCKER_VERSION);

        if ($hook !== 'toplevel_page_bot-blocker') {
            return;
        }

        wp_enqueue_script('plotly', BOT_BLOCKER_URL . 'assets/vendor/plotly.min.js', [], BOT_BLOCKER_VERSION, true);
        wp_enqueue_script('bot-blocker-monitor', BOT_BLOCKER_URL . 'assets/js/monitor.js', ['jquery', 'plotly'], BOT_BLOCKER_VERSION, true);
        wp_localize_script('bot-blocker-monitor', 'BotBlockerMonitor', [
            'rest'    => esc_url_raw(rest_url('bot-blocker/v1/monitor')),
            'nonce'   => wp_create_nonce('wp_rest'),
            'refresh' => (int) BotBlocker_Settings::get()['monitor_refresh_seconds'],
        ]);
    }

    public static function rest() {
        register_rest_route('bot-blocker/v1', '/monitor', [
            'methods'             => 'GET',
            'callback'            => [__CLASS__, 'monitor_data'],
            'permission_callback' => static function () {
                return current_user_can('manage_options');
            },
        ]);
    }

    public static function monitor_data($request) {
        $events = BotBlocker_Storage::get_recent_events(5, 500);
        $counts = BotBlocker_Storage::counts(5);
        $map_points = [];
        $feed = [];
        $groups = [];

        foreach ($events as $event) {
            $feed[] = [
                'id'           => (int) $event['id'],
                'bot'          => (string) $event['bot_name'],
                'category'     => (string) $event['category'],
                'action'       => (string) $event['action_taken'],
                'location'     => trim(
                    ($event['city'] !== '' ? $event['city'] : '') .
                    ($event['city'] !== '' && $event['country'] !== '' ? ', ' : '') .
                    ($event['country'] !== '' ? $event['country'] : '')
                ),
                'path'         => (string) $event['path'],
                'time'         => (string) $event['occurred_at'],
                'verification' => (string) $event['verification_state'],
                'lat'          => $event['latitude'],
                'lon'          => $event['longitude'],
                'burst'        => (int) $event['burst_count'],
            ];

            if ($event['latitude'] !== null && $event['longitude'] !== null && $event['latitude'] !== '' && $event['longitude'] !== '') {
                $group_key = md5(($event['bot_name'] ?: 'bot') . '|' . $event['action_taken'] . '|' . round((float) $event['latitude'], 2) . '|' . round((float) $event['longitude'], 2));
                if (!isset($groups[$group_key])) {
                    $groups[$group_key] = [
                        'lat'          => (float) $event['latitude'],
                        'lon'          => (float) $event['longitude'],
                        'bot'          => (string) $event['bot_name'],
                        'category'     => (string) $event['category'],
                        'action'       => (string) $event['action_taken'],
                        'location'     => trim(
                            ($event['city'] !== '' ? $event['city'] : '') .
                            ($event['city'] !== '' && $event['country'] !== '' ? ', ' : '') .
                            ($event['country'] !== '' ? $event['country'] : '')
                        ),
                        'path'         => (string) $event['path'],
                        'verification' => (string) $event['verification_state'],
                        'count'        => 0,
                        'latest'       => (string) $event['occurred_at'],
                    ];
                }
                $groups[$group_key]['count']++;
                if (strtotime($event['occurred_at']) > strtotime($groups[$group_key]['latest'])) {
                    $groups[$group_key]['latest'] = $event['occurred_at'];
                    $groups[$group_key]['path']   = $event['path'];
                }
            }
        }

        foreach ($groups as $group) {
            $map_points[] = $group;
        }

        return rest_ensure_response([
            'counts' => $counts,
            'points' => array_values($map_points),
            'feed'   => array_slice($feed, 0, 60),
        ]);
    }

    public static function render_monitor() {
        $settings = BotBlocker_Settings::get();
        $enforcement = !empty($settings['enforcement_enabled']);
        $logging     = !empty($settings['logging_enabled']);
        ?>
        <div class="wrap bot-blocker-wrap">
            <h1><?php esc_html_e('Live Monitor', 'bot-blocker'); ?></h1>

            <?php if (!$enforcement && !$logging) : ?>
            <div class="bb-notice bb-notice--warn">
                <?php esc_html_e('Both enforcement and logging are disabled. No bot events will be recorded or blocked. Enable them in Settings.', 'bot-blocker'); ?>
            </div>
            <?php elseif (!$enforcement) : ?>
            <div class="bb-notice bb-notice--info">
                <?php esc_html_e('Enforcement is disabled. Bots are being logged but not blocked.', 'bot-blocker'); ?>
            </div>
            <?php endif; ?>

            <div class="bb-monitor-grid">
                <div id="bb-monitor-map">
                    <div class="bb-map-overlay">
                        <div class="bb-overlay-stats">
                            <div class="bb-count" data-key="live"><?php esc_html_e('Live', 'bot-blocker'); ?> <strong>0</strong></div>
                            <div class="bb-count" data-key="blocked"><?php esc_html_e('Blocked', 'bot-blocker'); ?> <strong>0</strong></div>
                            <div class="bb-count" data-key="ai">AI <strong>0</strong></div>
                            <div class="bb-count" data-key="verified"><?php esc_html_e('Verified', 'bot-blocker'); ?> <strong>0</strong></div>
                            <div class="bb-count" data-key="fake"><?php esc_html_e('Fake', 'bot-blocker'); ?> <strong>0</strong></div>
                            <div class="bb-count" data-key="unmapped"><?php esc_html_e('Unmapped', 'bot-blocker'); ?> <strong>0</strong></div>
                        </div>
                        <div class="bb-overlay-legend">
                            <span class="bb-legend-dot" style="background:#ff3b30;"></span><?php esc_html_e('Blocked', 'bot-blocker'); ?>
                            <span class="bb-legend-dot" style="background:#ff8a00;"></span><?php esc_html_e('Fake bot', 'bot-blocker'); ?>
                            <span class="bb-legend-dot" style="background:#ffd60a;"></span><?php esc_html_e('Rate limited', 'bot-blocker'); ?>
                            <span class="bb-legend-dot" style="background:#3b82f6;"></span><?php esc_html_e('Verified', 'bot-blocker'); ?>
                            <span class="bb-legend-dot" style="background:#22c55e;"></span><?php esc_html_e('Allowed / Logged', 'bot-blocker'); ?>
                        </div>
                        <span class="bb-last-updated" id="bb-last-updated"></span>
                    </div>
                </div>
                <div class="bb-feed">
                    <h2><span class="bb-live-dot"></span><?php esc_html_e('Live Feed', 'bot-blocker'); ?></h2>
                    <div id="bb-feed-list">
                        <div class="bb-feed-empty"><?php esc_html_e('No events in the last 5 minutes.', 'bot-blocker'); ?></div>
                    </div>
                </div>
            </div>
        </div>
        <?php
    }

    public static function render_rules() {
        $settings = BotBlocker_Settings::get();

        echo '<div class="wrap"><h1>' . esc_html__('Rules', 'bot-blocker') . '</h1>';
        echo '<p class="description">' . esc_html__('Set the default action for each bot category. These rules apply to all detected bots unless overridden by a manual list entry.', 'bot-blocker') . '</p>';
        echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '"><input type="hidden" name="action" value="bot_blocker_save_rules" />';
        wp_nonce_field('bot_blocker_save_rules');
        echo '<table class="form-table"><tbody>';

        foreach (BotBlocker_Settings::categories() as $key => $label) {
            echo '<tr><th scope="row">' . esc_html($label) . '</th><td><select name="rules[' . esc_attr($key) . ']">';
            foreach (BotBlocker_Settings::actions() as $action_key => $action_label) {
                echo '<option value="' . esc_attr($action_key) . '" ' . selected($settings['rules'][$key] ?? '', $action_key, false) . '>' . esc_html($action_label) . '</option>';
            }
            echo '</select></td></tr>';
        }

        echo '</tbody></table>';
        submit_button(__('Save rules', 'bot-blocker'));
        echo '</form></div>';
    }

    public static function render_lists() {
        $lists = BotBlocker_Settings::get()['lists'];
        $fields = [
            'allow_ips'    => __('Allow IPs', 'bot-blocker'),
            'block_ips'    => __('Block IPs', 'bot-blocker'),
            'allow_agents' => __('Allow agents', 'bot-blocker'),
            'block_agents' => __('Block agents', 'bot-blocker'),
            'allow_paths'  => __('Allow paths', 'bot-blocker'),
            'block_paths'  => __('Block paths', 'bot-blocker'),
        ];

        echo '<div class="wrap"><h1>' . esc_html__('Lists', 'bot-blocker') . '</h1>';
        echo '<p class="description">' . esc_html__('Enter one IP address, CIDR range, user agent substring, or path per line. Allow lists are evaluated before block lists and rules.', 'bot-blocker') . '</p>';
        echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '"><input type="hidden" name="action" value="bot_blocker_save_lists" />';
        wp_nonce_field('bot_blocker_save_lists');
        echo '<table class="form-table"><tbody>';

        foreach ($fields as $key => $label) {
            echo '<tr><th scope="row">' . esc_html($label) . '</th><td><textarea name="lists[' . esc_attr($key) . ']" rows="7" cols="70">' . esc_textarea($lists[$key] ?? '') . '</textarea></td></tr>';
        }

        echo '</tbody></table>';
        submit_button(__('Save lists', 'bot-blocker'));
        echo '</form></div>';
    }

    public static function render_logs() {
        $table = new BotBlocker_Log_Table();
        $table->prepare_items();

        $filter_category = isset($_GET['filter_category']) ? sanitize_text_field(wp_unslash($_GET['filter_category'])) : '';
        $filter_action   = isset($_GET['filter_action']) ? sanitize_text_field(wp_unslash($_GET['filter_action'])) : '';
        $search          = isset($_GET['s']) ? sanitize_text_field(wp_unslash($_GET['s'])) : '';
        $orderby         = isset($_GET['orderby']) ? sanitize_key(wp_unslash($_GET['orderby'])) : '';
        $order           = isset($_GET['order']) ? sanitize_text_field(wp_unslash($_GET['order'])) : '';
        $paged           = isset($_GET['paged']) ? max(1, (int) $_GET['paged']) : 1;

        echo '<div class="wrap"><h1>' . esc_html__('Logs', 'bot-blocker') . '</h1>';

        echo '<form method="get">';
        echo '<input type="hidden" name="page" value="bot-blocker-logs" />';
        $table->search_box(__('Search logs', 'bot-blocker'), 'bot-blocker-logs');
        echo '<p><select name="filter_category"><option value="">' . esc_html__('All categories', 'bot-blocker') . '</option>';
        foreach (BotBlocker_Settings::log_categories() as $key => $label) {
            echo '<option value="' . esc_attr($key) . '" ' . selected($filter_category, $key, false) . '>' . esc_html($label) . '</option>';
        }
        echo '</select> <select name="filter_action"><option value="">' . esc_html__('All actions', 'bot-blocker') . '</option>';
        foreach (BotBlocker_Settings::actions() as $key => $label) {
            echo '<option value="' . esc_attr($key) . '" ' . selected($filter_action, $key, false) . '>' . esc_html($label) . '</option>';
        }
        echo '</select> ';
        submit_button(__('Filter', 'bot-blocker'), 'secondary', 'filter_action_submit', false);
        echo '</p></form>';

        echo '<form method="post" action="' . esc_url(admin_url('admin.php?page=bot-blocker-logs')) . '">';
        wp_nonce_field('bulk-bot-events');
        echo '<input type="hidden" name="bot_blocker_logs_submit" value="1" />';
        echo '<input type="hidden" name="filter_category" value="' . esc_attr($filter_category) . '" />';
        echo '<input type="hidden" name="filter_action" value="' . esc_attr($filter_action) . '" />';
        echo '<input type="hidden" name="s" value="' . esc_attr($search) . '" />';
        echo '<input type="hidden" name="orderby" value="' . esc_attr($orderby) . '" />';
        echo '<input type="hidden" name="order" value="' . esc_attr($order) . '" />';
        echo '<input type="hidden" name="paged" value="' . (int) $paged . '" />';
        echo '<p><button type="submit" name="bulk_action_override" value="delete_all" class="button button-secondary" onclick="return confirm(\'' . esc_js(__('Delete all logs? This cannot be undone.', 'bot-blocker')) . '\');">' . esc_html__('Delete All Logs', 'bot-blocker') . '</button></p>';
        $table->display();
        echo '</form></div>';
    }

    public static function render_settings() {
        $settings = BotBlocker_Settings::get();

        echo '<div class="wrap"><h1>' . esc_html__('Settings', 'bot-blocker') . '</h1><form method="post" action="' . esc_url(admin_url('admin-post.php')) . '"><input type="hidden" name="action" value="bot_blocker_save_settings" />';
        wp_nonce_field('bot_blocker_save_settings');
        echo '<table class="form-table"><tbody>';

        // ── Core ─────────────────────────────────────────────────────────────
        $checkboxes = [
            'enforcement_enabled'      => __('Enable enforcement', 'bot-blocker'),
            'logging_enabled'          => __('Enable logging', 'bot-blocker'),
        ];
        foreach ($checkboxes as $key => $label) {
            echo '<tr><th scope="row">' . esc_html($label) . '</th><td><label><input type="checkbox" name="settings[' . esc_attr($key) . ']" value="1" ' . checked(!empty($settings[$key]), true, false) . ' /> ' . esc_html__('Yes', 'bot-blocker') . '</label></td></tr>';
        }

        // ── Detection ────────────────────────────────────────────────────────
        $detection_checkboxes = [
            'geolocation_enabled'      => __('Enable geolocation', 'bot-blocker'),
            'dns_verification_enabled' => __('Enable DNS verification', 'bot-blocker'),
        ];
        foreach ($detection_checkboxes as $key => $label) {
            echo '<tr><th scope="row">' . esc_html($label) . '</th><td><label><input type="checkbox" name="settings[' . esc_attr($key) . ']" value="1" ' . checked(!empty($settings[$key]), true, false) . ' /> ' . esc_html__('Yes', 'bot-blocker') . '</label></td></tr>';
        }

        // ── Privacy ──────────────────────────────────────────────────────────
        $privacy_checkboxes = [
            'store_full_ip'    => __('Store full IP addresses', 'bot-blocker'),
            'log_query_strings'=> __('Log query strings', 'bot-blocker'),
            'log_referrers'    => __('Log referrers', 'bot-blocker'),
        ];
        foreach ($privacy_checkboxes as $key => $label) {
            echo '<tr><th scope="row">' . esc_html($label) . '</th><td><label><input type="checkbox" name="settings[' . esc_attr($key) . ']" value="1" ' . checked(!empty($settings[$key]), true, false) . ' /> ' . esc_html__('Yes', 'bot-blocker') . '</label></td></tr>';
        }

        // ── Network ──────────────────────────────────────────────────────────
        echo '<tr><th scope="row">' . esc_html__('Trust Cloudflare IP header', 'bot-blocker') . '</th><td><label><input type="checkbox" name="settings[trust_cloudflare_headers]" value="1" ' . checked(!empty($settings['trust_cloudflare_headers']), true, false) . ' /> ' . esc_html__('Yes', 'bot-blocker') . '</label><p class="description">' . esc_html__('Use the CF-Connecting-IP header when the request arrives from a trusted proxy.', 'bot-blocker') . '</p></td></tr>';

        echo '<tr><th scope="row">' . esc_html__('Trusted proxy IPs', 'bot-blocker') . '</th><td><textarea name="settings[trusted_proxy_ips]" rows="4" cols="70">' . esc_textarea($settings['trusted_proxy_ips']) . '</textarea><p class="description">' . esc_html__('One IP or CIDR per line. Requests from these addresses may supply forwarded client IP headers.', 'bot-blocker') . '</p></td></tr>';

        echo '<tr><th scope="row">' . esc_html__('Sensitive paths', 'bot-blocker') . '</th><td><textarea name="settings[sensitive_paths]" rows="5" cols="70">' . esc_textarea($settings['sensitive_paths']) . '</textarea><p class="description">' . esc_html__('One path prefix per line. Requests to these paths are flagged as sensitive path probes regardless of user agent.', 'bot-blocker') . '</p></td></tr>';

        // ── Rate limits ──────────────────────────────────────────────────────
        foreach (['ai_crawlers' => __('Rate limit - AI crawlers (req/min)', 'bot-blocker'), 'scraper_bots' => __('Rate limit - Scraper bots (req/min)', 'bot-blocker'), 'scanner_bots' => __('Rate limit - Scanner bots (req/min)', 'bot-blocker'), 'spam_bots' => __('Rate limit - Spam bots (req/min)', 'bot-blocker')] as $rate_key => $rate_label) {
            echo '<tr><th scope="row">' . esc_html($rate_label) . '</th><td><input type="number" min="1" max="5000" name="settings[rate_limits][' . esc_attr($rate_key) . ']" value="' . esc_attr($settings['rate_limits'][$rate_key] ?? '') . '" /></td></tr>';
        }

        // ── Monitor & Logs ───────────────────────────────────────────────────
        echo '<tr><th scope="row">' . esc_html__('Monitor refresh interval (seconds)', 'bot-blocker') . '</th><td><input type="number" min="2" max="30" name="settings[monitor_refresh_seconds]" value="' . esc_attr($settings['monitor_refresh_seconds']) . '" /><p class="description">' . esc_html__('How often the live monitor polls for new events. Min 2, max 30.', 'bot-blocker') . '</p></td></tr>';

        echo '<tr><th scope="row">' . esc_html__('Log retention (days)', 'bot-blocker') . '</th><td><input type="number" min="1" max="365" name="settings[log_retention_days]" value="' . esc_attr($settings['log_retention_days']) . '" /><p class="description">' . esc_html__('Events older than this are deleted by the daily cleanup task.', 'bot-blocker') . '</p></td></tr>';

        // ── Pro Settings ─────────────────────────────────────────────────
        echo '</tbody></table>';
        // Pro settings fields (part of the unified settings form)
        echo '<table class="form-table"><tbody>';

        // Country Blocking
        echo '<tr><th scope="row">' . esc_html__('Blocked countries', 'bot-blocker') . '</th><td>';
        echo '<input type="text" name="settings[pro_blocked_countries]" value="' . esc_attr( implode( ', ', (array) ( $settings['pro_blocked_countries'] ?? [] ) ) ) . '" class="regular-text" placeholder="e.g. CN, RU, KP" />';
        echo '<p class="description">' . esc_html__('Comma-separated ISO 3166-1 alpha-2 country codes. Requires geolocation to be enabled.', 'bot-blocker') . '</p>';
        echo '</td></tr>';

        echo '<tr><th scope="row">' . esc_html__('Country block action', 'bot-blocker') . '</th><td>';
        echo '<select name="settings[pro_country_block_action]">';
        echo '<option value="block" '      . selected( ( $settings['pro_country_block_action'] ?? 'block' ), 'block',      false ) . '>' . esc_html__('Block (403)', 'bot-blocker') . '</option>';
        echo '<option value="rate_limit" ' . selected( ( $settings['pro_country_block_action'] ?? 'block' ), 'rate_limit', false ) . '>' . esc_html__('Rate limit (5 min cooldown)', 'bot-blocker') . '</option>';
        echo '</select>';
        echo '</td></tr>';

        // Auto-escalation
        echo '<tr><th scope="row">' . esc_html__('Fake bot auto-escalation', 'bot-blocker') . '</th><td>';
        echo '<label><input type="checkbox" name="settings[pro_auto_escalate_fake_bots]" value="1" ' . checked( ! empty( $settings['pro_auto_escalate_fake_bots'] ), true, false ) . ' /> ' . esc_html__('Automatically block bots that fail DNS identity verification (fake Googlebot, fake Bingbot, etc.)', 'bot-blocker') . '</label>';
        echo '</td></tr>';

        // Email Digest
        echo '<tr><th scope="row">' . esc_html__('Email digest frequency', 'bot-blocker') . '</th><td>';
        echo '<select name="settings[pro_digest_frequency]">';
        echo '<option value="disabled" ' . selected( ( $settings['pro_digest_frequency'] ?? 'disabled' ), 'disabled', false ) . '>' . esc_html__('Disabled', 'bot-blocker') . '</option>';
        echo '<option value="daily" '    . selected( ( $settings['pro_digest_frequency'] ?? 'disabled' ), 'daily',    false ) . '>' . esc_html__('Daily', 'bot-blocker') . '</option>';
        echo '<option value="weekly" '   . selected( ( $settings['pro_digest_frequency'] ?? 'disabled' ), 'weekly',   false ) . '>' . esc_html__('Weekly', 'bot-blocker') . '</option>';
        echo '</select>';
        echo '</td></tr>';

        echo '<tr><th scope="row">' . esc_html__('Digest email address', 'bot-blocker') . '</th><td>';
        echo '<input type="email" name="settings[pro_digest_email]" value="' . esc_attr( $settings['pro_digest_email'] ?? get_option( 'admin_email' ) ) . '" class="regular-text" />';
        echo '<p class="description">' . esc_html__('Leave blank to use the site admin email.', 'bot-blocker') . '</p>';
        echo '</td></tr>';

        // Custom Block Page
        echo '<tr><th scope="row">' . esc_html__('Custom block page HTML', 'bot-blocker') . '</th><td>';
        echo '<textarea name="settings[pro_custom_block_html]" rows="6" class="large-text code" placeholder="' . esc_attr__('Leave blank to use the default WordPress error page. Use {{reason}} as a placeholder for the block reason.', 'bot-blocker') . '">' . esc_textarea( $settings['pro_custom_block_html'] ?? '' ) . '</textarea>';
        echo '<p class="description">' . esc_html__('Full HTML for the 403 response page. Use {{reason}} to insert the block reason.', 'bot-blocker') . '</p>';
        echo '</td></tr>';

        echo '</tbody></table>';
        submit_button(__('Save settings', 'bot-blocker'));
        echo '</form>';

        // Export buttons (outside the form - links, not inputs)
        $export_nonce = wp_create_nonce( 'bot_blocker_export' );
        echo '<h2>' . esc_html__('Export Logs', 'bot-blocker') . '</h2>';
        echo '<p>';
        echo '<a href="' . esc_url( admin_url( 'admin-post.php?action=bot_blocker_export_csv&_wpnonce=' . $export_nonce ) ) . '" class="button">' . esc_html__('Download CSV', 'bot-blocker') . '</a>';
        echo ' &nbsp; ';
        echo '<a href="' . esc_url( admin_url( 'admin-post.php?action=bot_blocker_export_json&_wpnonce=' . $export_nonce ) ) . '" class="button">' . esc_html__('Download JSON', 'bot-blocker') . '</a>';
        echo '</p>';

        // License section - always shown
        if ( class_exists('SeraLicense') ) {
            SeraLicense::render_license_section();
        }
        echo '</div>';
    }

    public static function save_rules() {
        if (!current_user_can('manage_options')) {
            wp_die(esc_html__('Forbidden', 'bot-blocker'));
        }

        check_admin_referer('bot_blocker_save_rules');
        $settings = BotBlocker_Settings::get();
        $rules = isset($_POST['rules']) ? (array) wp_unslash($_POST['rules']) : [];
        $valid_actions = array_keys(BotBlocker_Settings::actions());

        foreach (BotBlocker_Settings::categories() as $key => $label) {
            $candidate = isset($rules[$key]) ? sanitize_key($rules[$key]) : ($settings['rules'][$key] ?? 'log');
            $settings['rules'][$key] = in_array($candidate, $valid_actions, true) ? $candidate : ($settings['rules'][$key] ?? 'log');
        }

        BotBlocker_Settings::update($settings);
        wp_safe_redirect(admin_url('admin.php?page=bot-blocker-rules'));
        exit;
    }

    public static function save_lists() {
        if (!current_user_can('manage_options')) {
            wp_die(esc_html__('Forbidden', 'bot-blocker'));
        }

        check_admin_referer('bot_blocker_save_lists');
        $settings = BotBlocker_Settings::get();
        $incoming = isset($_POST['lists']) ? (array) wp_unslash($_POST['lists']) : [];

        foreach (array_keys($settings['lists']) as $key) {
            $settings['lists'][$key] = trim((string) ($incoming[$key] ?? ''));
        }

        BotBlocker_Settings::update($settings);
        wp_safe_redirect(admin_url('admin.php?page=bot-blocker-lists'));
        exit;
    }

    public static function save_settings() {
        if (!current_user_can('manage_options')) {
            wp_die(esc_html__('Forbidden', 'bot-blocker'));
        }

        check_admin_referer('bot_blocker_save_settings');
        $settings = BotBlocker_Settings::get();
        $incoming = isset($_POST['settings']) ? (array) wp_unslash($_POST['settings']) : [];

        foreach (['enforcement_enabled', 'logging_enabled', 'store_full_ip', 'log_query_strings', 'log_referrers', 'geolocation_enabled', 'dns_verification_enabled', 'trust_cloudflare_headers'] as $key) {
            $settings[$key] = empty($incoming[$key]) ? 0 : 1;
        }

        $settings['trusted_proxy_ips'] = trim((string) ($incoming['trusted_proxy_ips'] ?? $settings['trusted_proxy_ips']));
        $incoming_rate_limits = isset($incoming['rate_limits']) && is_array($incoming['rate_limits']) ? $incoming['rate_limits'] : [];
        foreach (array_keys($settings['rate_limits']) as $rate_key) {
            $settings['rate_limits'][$rate_key] = max(1, min(5000, (int) ($incoming_rate_limits[$rate_key] ?? $settings['rate_limits'][$rate_key])));
        }
        $settings['monitor_refresh_seconds'] = max(2, min(30, (int) ($incoming['monitor_refresh_seconds'] ?? $settings['monitor_refresh_seconds'])));
        $settings['log_retention_days']       = max(1, min(365, (int) ($incoming['log_retention_days'] ?? $settings['log_retention_days'])));
        $settings['sensitive_paths']          = trim((string) ($incoming['sensitive_paths'] ?? $settings['sensitive_paths']));

        // Pro settings
        $raw_countries = sanitize_text_field( (string) ( $incoming['pro_blocked_countries'] ?? implode( ', ', (array) ( $settings['pro_blocked_countries'] ?? [] ) ) ) );
        $settings['pro_blocked_countries'] = array_values( array_filter( array_map( 'strtoupper', array_map( 'trim', explode( ',', $raw_countries ) ) ) ) );

        $settings['pro_country_block_action'] = in_array( ( $incoming['pro_country_block_action'] ?? '' ), [ 'block', 'rate_limit' ], true )
            ? $incoming['pro_country_block_action'] : ( $settings['pro_country_block_action'] ?? 'block' );

        $settings['pro_auto_escalate_fake_bots'] = empty( $incoming['pro_auto_escalate_fake_bots'] ) ? false : true;

        $settings['pro_digest_frequency'] = in_array( ( $incoming['pro_digest_frequency'] ?? '' ), [ 'disabled', 'daily', 'weekly' ], true )
            ? $incoming['pro_digest_frequency'] : ( $settings['pro_digest_frequency'] ?? 'disabled' );

        $settings['pro_digest_email'] = sanitize_email( (string) ( $incoming['pro_digest_email'] ?? ( $settings['pro_digest_email'] ?? '' ) ) );

        $settings['pro_custom_block_html'] = wp_kses_post( (string) ( $incoming['pro_custom_block_html'] ?? ( $settings['pro_custom_block_html'] ?? '' ) ) );

        BotBlocker_Settings::update($settings);
        wp_safe_redirect(admin_url('admin.php?page=bot-blocker-settings'));
        exit;
    }

    public static function maybe_handle_logs() {
        if (!is_admin() || $_SERVER['REQUEST_METHOD'] !== 'POST') {
            return;
        }

        $page   = isset($_REQUEST['page']) ? sanitize_key(wp_unslash($_REQUEST['page'])) : '';
        $submit = isset($_POST['bot_blocker_logs_submit']) ? sanitize_key(wp_unslash($_POST['bot_blocker_logs_submit'])) : '';

        if ($page !== 'bot-blocker-logs' || $submit !== '1') {
            return;
        }

        self::process_logs_request();
    }

    public static function handle_logs() {
        self::process_logs_request();
    }

    private static function process_logs_request() {
        if (!current_user_can('manage_options')) {
            wp_die(esc_html__('Forbidden', 'bot-blocker'));
        }

        check_admin_referer('bulk-bot-events');

        $filters = [
            'category' => isset($_POST['filter_category']) ? sanitize_text_field(wp_unslash($_POST['filter_category'])) : '',
            'action'   => isset($_POST['filter_action']) ? sanitize_text_field(wp_unslash($_POST['filter_action'])) : '',
            's'        => isset($_POST['s']) ? sanitize_text_field(wp_unslash($_POST['s'])) : '',
        ];

        $redirect_args = ['page' => 'bot-blocker-logs'];
        if ($filters['category'] !== '') {
            $redirect_args['filter_category'] = $filters['category'];
        }
        if ($filters['action'] !== '') {
            $redirect_args['filter_action'] = $filters['action'];
        }
        if ($filters['s'] !== '') {
            $redirect_args['s'] = $filters['s'];
        }

        $orderby = isset($_POST['orderby']) ? sanitize_key(wp_unslash($_POST['orderby'])) : '';
        if ($orderby !== '') {
            $redirect_args['orderby'] = $orderby;
        }

        $order = isset($_POST['order']) ? sanitize_text_field(wp_unslash($_POST['order'])) : '';
        if ($order !== '') {
            $redirect_args['order'] = $order;
        }

        $paged = isset($_POST['paged']) ? max(1, (int) $_POST['paged']) : 1;
        if ($paged > 1) {
            $redirect_args['paged'] = $paged;
        }

        $mode = isset($_POST['action']) ? sanitize_text_field(wp_unslash($_POST['action'])) : '';
        if ($mode === '-1' || $mode === '') {
            $mode = isset($_POST['action2']) ? sanitize_text_field(wp_unslash($_POST['action2'])) : '';
        }

        $override = isset($_POST['bulk_action_override']) ? sanitize_key(wp_unslash($_POST['bulk_action_override'])) : '';

        // Consolidate both delete_all triggers into a single branch.
        if ($override === 'delete_all' || $mode === 'delete_all') {
            BotBlocker_Storage::delete_all();
        } elseif ($mode === 'delete_selected') {
            // IDs are cast to int inside delete_logs(); no further sanitization needed here.
            BotBlocker_Storage::delete_logs(isset($_POST['log_ids']) ? (array) $_POST['log_ids'] : []);
        } elseif ($mode === 'delete_filtered') {
            BotBlocker_Storage::delete_filtered($filters);
        }

        wp_safe_redirect(add_query_arg($redirect_args, admin_url('admin.php')));
        exit;
    }
}
