<?php
/**
 * ModulesManagerPage — Full module management admin page.
 *
 * Renders:
 *   • Stat cards (total / active / inactive / third-party)
 *   • Tab group: Feature | Core | Third-Party | Install New
 *   • Per-tab: search bar + module card list with license-aware action buttons
 *   • Module card states:
 *       active     → Deactivate button  (green left stripe)
 *       inactive   → Activate button    (grey left stripe)
 *       locked     → Upgrade CTA        (gold left stripe)
 *       core       → Core badge only    (no toggle)
 *       error      → Not Loaded badge   (amber left stripe)
 *
 * NO Closures anywhere in the scheme — RenderEngine::before_render() calls
 * serialize($scheme) which fatal-errors on Closure objects. All HTML is built
 * eagerly. The JS upload handler is registered on admin_footer via a named
 * static method (not an anonymous function) to allow remove_action() if needed.
 *
 * @package UltraguardPro\modules\dashboard\pages
 */

namespace UltraguardPro\modules\dashboard\pages;

use UltraguardPro\Plugin;
use UltraguardPro\modules\core\BasePage;
use UltraguardPro\support\LicenseInfo;

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

class ModulesManagerPage extends BasePage {

    /** Stored nonce for use in the footer JS callback (no Closure needed). */
    private string $upload_nonce = '';

    public function __construct( Plugin $plugin ) {
        parent::__construct( $plugin );
    }

    // =========================================================================
    // Scheme
    // =========================================================================

    /**
     * Build the modules manager page schema.
     *
     * @param  mixed $context  Page render context.
     * @return array<string,mixed>
     */
    public function get_scheme( $context ): array {
        $manager = $this->plugin->modules->get_module_manager();
        $all     = $manager ? $manager->get_all_modules() : [];
        $is_pro  = LicenseInfo::instance()->isPro();

        $total   = count( $all );
        $active  = count( array_filter( $all, fn( $m ) => (bool) ( $m['is_active'] ?? false ) ) );
        $inactive= $total - $active;
        $third_p = count( array_filter( $all, fn( $m ) => ! (bool) ( $m['is_builtin'] ?? true ) ) );

        $nonce = $this->create_nonce( 'ultraguard_admin_nonce' );
        $this->register_upload_footer_script( $nonce );

        $feature_mods = array_filter( $all, fn( $m ) => ( $m['type'] ?? '' ) === 'feature' );
        $core_mods    = array_filter( $all, fn( $m ) => ( $m['type'] ?? '' ) === 'core' );
        $other_mods   = array_filter( $all, fn( $m ) => ! in_array( $m['type'] ?? '', [ 'core', 'feature' ], true ) );
        $upgrade_url  = $manager ? esc_url( $manager->get_upgrade_url() ) : 'https://ultraguard.net/pricing';

        return apply_filters( 'ultraguard_modules_manager_scheme', [
            'type'      => 'page',
            'id'        => 'ultraguard-modules-manager',
            'page_slug' => 'modules-manager',
            'class'     => 'ultraguard-modules-manager-page ultraguard-page-no-sidebar',

            'header' => [
                'title'    => __( 'Module Manager', 'ultraguard-security-suite' ),
                'subtitle' => __( 'Activate, deactivate and install security modules.', 'ultraguard-security-suite' ),
                'icon'     => 'dashicons-plugins-checked',
                'badge'    => [
                    /* translators: %1$d: integer, %2$d: integer */
                    'text'       => sprintf( __( '%1$d / %2$d Active', 'ultraguard-security-suite' ), $active, $total ),
                    'badge_type' => $inactive > 0 ? 'warning' : 'success',
                ],
                'actions' => [
                    $this->create_ajax_button(
                        __( 'Refresh', 'ultraguard-security-suite' ),
                        'ultraguard_modules_list',
                        [],
                        'secondary',
                        'dashicons-update'
                    ),
                ],
            ],

            'data' => [

                // ── Stats row ────────────────────────────────────────────────
                [
                    'type'    => 'grid',
                    'columns' => 12,
                    'gap'     => '16px',
                    'items'   => [
                        [ 'span' => 3, 'component' => [ 'type' => 'stat-card', 'title' => __( 'Total Modules', 'ultraguard-security-suite' ), 'value' => $total,    'icon' => 'dashicons-plugins-checked', 'class' => 'info'                               ] ],
                        [ 'span' => 3, 'component' => [ 'type' => 'stat-card', 'title' => __( 'Active',        'ultraguard-security-suite' ), 'value' => $active,   'icon' => 'dashicons-yes-alt',         'class' => 'success'                            ] ],
                        [ 'span' => 3, 'component' => [ 'type' => 'stat-card', 'title' => __( 'Inactive',      'ultraguard-security-suite' ), 'value' => $inactive, 'icon' => 'dashicons-minus',           'class' => $inactive > 0 ? 'warning' : 'success' ] ],
                        [ 'span' => 3, 'component' => [ 'type' => 'stat-card', 'title' => __( 'Third-Party',   'ultraguard-security-suite' ), 'value' => $third_p,  'icon' => 'dashicons-upload',          'class' => 'info'                               ] ],
                    ],
                ],

                // ── License alert ────────────────────────────────────────────
                ! $is_pro ? [
                    'type'    => 'html',
                    'content' => sprintf(
                        '<div class="ug-module-upgrade-notice">'
                        . '<div class="ug-module-upgrade-notice__icon">'
                        . '<span class="dashicons dashicons-info-outline"></span>'
                        . '</div>'
                        . '<div class="ug-module-upgrade-notice__content">'
                        . '<strong class="ug-module-upgrade-notice__title">%s</strong>'
                        . '<span class="ug-module-upgrade-notice__text">%s</span>'
                        . '</div>'
                        . '<div class="ug-module-upgrade-notice__action">'
                        . '<a href="%s" target="_blank" rel="noopener noreferrer"'
                        . ' class="button ultraguard-button ug-module-btn ug-module-btn--upgrade">'
                        . '<span class="dashicons dashicons-star-filled"></span>%s</a>'
                        . '</div>'
                        . '</div>',
                        esc_html__( 'Free Plan Active: ', 'ultraguard-security-suite' ),
                        esc_html__( ' Some modules require a Pro license — File Checker, .htaccess Manager and Notifications.', 'ultraguard-security-suite' ),
                        esc_url( $upgrade_url ),
                        esc_html__( 'Upgrade to Pro', 'ultraguard-security-suite' )
                    ),
                ] : [
                    'type'       => 'alert-box',
                    'alert_type' => 'info',
                    'message'    => __( 'Changes take effect on the next page load. The page reloads automatically after each action.', 'ultraguard-security-suite' ),
                ],

                // ── Tabs ─────────────────────────────────────────────────────
                [
                    'type' => 'tabs',
                    'id'   => 'modules-tabs',
                    'tabs' => [
                        [
                            'id'    => 'feature-modules',
                            'title' => __( 'Feature Modules', 'ultraguard-security-suite' ) . ' (' . count( $feature_mods ) . ')',
                            'icon'  => 'dashicons-shield',
                            'data'  => [ $this->module_list_component( $feature_mods, $nonce, 'feature', $is_pro ) ],
                        ],
                        [
                            'id'    => 'core-modules',
                            'title' => __( 'Core', 'ultraguard-security-suite' ) . ' (' . count( $core_mods ) . ')',
                            'icon'  => 'dashicons-admin-settings',
                            'data'  => [ $this->module_list_component( $core_mods, $nonce, 'core', $is_pro ) ],
                        ],
                        [
                            'id'    => 'third-party',
                            'title' => __( 'Third-Party', 'ultraguard-security-suite' ) . ' (' . $third_p . ')',
                            'icon'  => 'dashicons-upload',
                            'data'  => [
                                $this->module_list_component( $other_mods, $nonce, 'third-party', $is_pro ),
                                $this->install_card( $nonce, $is_pro, $upgrade_url ),
                            ],
                        ],
                        [
                            'id'    => 'install-new',
                            'title' => __( 'Install New', 'ultraguard-security-suite' ),
                            'icon'  => 'dashicons-plus-alt',
                            'data'  => [
                                $this->install_card( $nonce, $is_pro, $upgrade_url ),
                                $this->module_format_card(),
                            ],
                        ],
                    ],
                ],
            ],

            'form' => [ 'enable' => false ],
        ], $context );
    }

    // =========================================================================
    // Module list component
    // =========================================================================

    /**
     * Build an HTML-type schema component for a list of modules.
     *
     * @param  array<string,array<string,mixed>> $modules
     * @param  string $nonce    Security nonce.
     * @param  string $group    Group key for search ID namespacing.
     * @param  bool   $is_pro   Whether the current license is Pro.
     * @return array<string,mixed>
     */
    private function module_list_component( array $modules, string $nonce, string $group, bool $is_pro ): array {
        return [
            'type'    => 'html',
            'content' => $this->build_module_list_html( $modules, $nonce, $group, $is_pro ),
        ];
    }

    /**
     * Build the HTML string for a module list section.
     *
     * @param  array<string,array<string,mixed>> $modules
     * @param  string $nonce
     * @param  string $group
     * @param  bool   $is_pro
     * @return string
     */
    private function build_module_list_html( array $modules, string $nonce, string $group, bool $is_pro ): string {
        if ( empty( $modules ) ) {
            return $this->build_empty_state_html( $group );
        }

        $search_id = 'ug-module-search-' . sanitize_html_class( $group );
        $list_id   = 'ug-module-list-'   . sanitize_html_class( $group );
        $count     = count( $modules );

        ob_start();
        echo '<div class="ug-module-section">';

        // Search bar
        printf(
            '<div class="ug-module-search-bar">'
            . '<span class="dashicons dashicons-search ug-module-search-icon"></span>'
            . '<input type="search" id="%s" class="ug-module-search-input"'
            . ' placeholder="%s" oninput="ugFilterModules(\'%s\', this.value)" autocomplete="off" />'
            . '<span class="ug-module-count">%s</span>'
            . '</div>',
            esc_attr( $search_id ),
            esc_attr__( 'Search modules…', 'ultraguard-security-suite' ),
            esc_js( $list_id ),
            /* translators: %d: number */
            esc_html( sprintf( _n( '%d module', '%d modules', $count, 'ultraguard-security-suite' ), $count ) )
        );

        echo '<div class="ug-module-list" id="' . esc_attr( $list_id ) . '">';
        foreach ( $modules as $id => $m ) {
            $this->render_module_card( (string) $id, $m, $nonce, $is_pro );
        }
        echo '</div></div>';

        return ob_get_clean();
    }

    /**
     * Render a single module card.
     *
     * @param string              $id     Module ID.
     * @param array<string,mixed> $m      Module data.
     * @param string              $nonce  Security nonce.
     * @param bool                $is_pro Current license state.
     */
    private function render_module_card( string $id, array $m, string $nonce, bool $is_pro ): void {
        $is_active        = (bool) ( $m['is_active']        ?? false );
        $is_builtin       = (bool) ( $m['is_builtin']       ?? false );
        $is_loaded        = (bool) ( $m['is_loaded']        ?? false );
        $is_core          = ( $m['type'] ?? '' ) === 'core';
        $can_remove       = ! $is_builtin && (bool) ( $m['removable'] ?? true );
        $license_required = (string) ( $m['license_required'] ?? 'free' );
        $license_ok       = (bool) ( $m['license_ok']         ?? true );
            $upgrade_url      = esc_url( $m['upgrade_url'] ?? 'https://ultraguard.net/pricing' );

        $icon       = esc_attr( $m['icon']        ?? 'dashicons-admin-plugins' );
        $name       = esc_html( $m['name']        ?? $id );
        $desc       = esc_html( $m['description'] ?? '' );
        $version    = esc_html( $m['version']     ?? '—' );
        $type_key   = esc_attr( $m['type']        ?? 'feature' );
        $type_label = esc_html( ucfirst( $m['type'] ?? 'feature' ) );

        $state = 'inactive';
        if ( ! $license_ok ) {
            $state = 'locked';
        } elseif ( $is_loaded && $is_active ) {
            $state = 'active';
        } elseif ( ! $is_loaded && $is_active ) {
            $state = 'error';
        }

        $search_str = esc_attr( strtolower( ( $m['name'] ?? '' ) . ' ' . ( $m['description'] ?? '' ) ) );

        printf(
            '<div class="ug-module-card ug-module-card--%s" data-module-name="%s" data-module-id="%s">',
            esc_attr( $state ),
            esc_attr( $search_str ),
            esc_attr( $id )
        );

        // Icon
        printf(
            '<div class="ug-module-icon-wrap ug-module-icon-wrap--%s"><span class="dashicons %s ug-module-icon"></span></div>',
            esc_attr( $state ),
            esc_attr( $icon )
        );

        // Body
        echo '<div class="ug-module-body">';
        echo '<div class="ug-module-name-row">';
        printf( '<span class="ug-module-name">%s</span>', esc_html( $name ) );
        printf( '<span class="ug-module-tag ug-module-tag--version">v%s</span>', esc_html( $version ) );
        printf( '<span class="ug-module-tag ug-module-tag--%s">%s</span>', esc_attr( $type_key ), esc_html( $type_label ) );

        // License badge
        if ( $license_required === 'pro' ) {
            if ( $is_pro ) {
                printf(
                    '<span class="ug-module-tag ug-module-tag--pro-active"><span class="dashicons dashicons-star-filled"></span>%s</span>',
                    esc_html__( 'Pro', 'ultraguard-security-suite' )
                );
            } else {
                printf(
                    '<span class="ug-module-tag ug-module-tag--pro-locked"><span class="dashicons dashicons-lock"></span>%s</span>',
                    esc_html__( 'Pro', 'ultraguard-security-suite' )
                );
            }
        }

        // Status pill
        if ( $license_ok ) {
            $status_map = [
                'active'   => [ 'label' => __( 'Active',     'ultraguard-security-suite' ), 'cls' => 'active'   ],
                'inactive' => [ 'label' => __( 'Inactive',   'ultraguard-security-suite' ), 'cls' => 'inactive' ],
                'error'    => [ 'label' => __( 'Not Loaded', 'ultraguard-security-suite' ), 'cls' => 'error'    ],
            ];
            $status = $status_map[ $state ] ?? $status_map['inactive'];
            printf(
                '<span class="ug-module-status ug-module-status--%s"><span class="ug-module-status-dot"></span>%s</span>',
                esc_attr( $status['cls'] ),
                esc_html( $status['label'] )
            );
        }

        echo '</div>'; // .name-row
        if ( $desc ) {
            printf( '<p class="ug-module-desc">%s</p>', esc_html( $desc ) );
        }
        echo '</div>'; // .ug-module-body

        // Actions
        echo '<div class="ug-module-actions">';

        if ( $is_core ) {
            printf(
                '<span class="ug-module-core-badge">%s</span>',
                esc_html__( 'Core', 'ultraguard-security-suite' )
            );

        } elseif ( ! $license_ok ) {
            // Pro-locked — link to in-plugin comparison page first, then external
            $in_plugin_url = admin_url( \UltraguardPro\support\UpgradeManager::UPGRADE_PAGE_URL_PATTERN );
            printf(
                '<a href="%s" class="button ultraguard-button ug-module-btn ug-module-btn--upgrade">'
                . '<span class="dashicons dashicons-star-filled"></span>%s</a>',
                esc_url( $in_plugin_url ),
                esc_html__( 'See Pro Features', 'ultraguard-security-suite' )
            );

        } elseif ( $is_active ) {
            printf(
                '<button type="button"'
                . ' class="button ultraguard-button ultraguard-button-secondary ultraguard-ajax-action ug-module-btn"'
                . ' data-ajax-action="ultraguard_module_deactivate"'
                . ' data-nonce="%s"'
                . ' data-ajax-data=\'{"module_id":"%s"}\''
                . ' data-confirm="%s">'
                . '<span class="dashicons dashicons-no-alt"></span>%s</button>',
                esc_attr( $nonce ),
                esc_attr( $id ),
                /* translators: %s: string */
                esc_attr( sprintf( __( 'Deactivate the %s module?', 'ultraguard-security-suite' ), $m['name'] ?? $id ) ),
                esc_html__( 'Deactivate', 'ultraguard-security-suite' )
            );

        } else {
            printf(
                '<button type="button"'
                . ' class="button ultraguard-button ultraguard-button-primary ultraguard-ajax-action ug-module-btn"'
                . ' data-ajax-action="ultraguard_module_activate"'
                . ' data-nonce="%s"'
                . ' data-ajax-data=\'{"module_id":"%s"}\'>'
                . '<span class="dashicons dashicons-yes"></span>%s</button>',
                esc_attr( $nonce ),
                esc_attr( $id ),
                esc_html__( 'Activate', 'ultraguard-security-suite' )
            );
        }

        if ( $can_remove ) {
            printf(
                '<button type="button"'
                . ' class="button ultraguard-button ultraguard-button-danger ultraguard-ajax-action ug-module-btn"'
                . ' data-ajax-action="ultraguard_module_uninstall"'
                . ' data-nonce="%s"'
                . ' data-ajax-data=\'{"module_id":"%s"}\''
                . ' data-confirm="%s">'
                . '<span class="dashicons dashicons-trash"></span></button>',
                esc_attr( $nonce ),
                esc_attr( $id ),
                /* translators: %s: string */
                esc_attr( sprintf( __( 'Permanently uninstall "%s"? This cannot be undone.', 'ultraguard-security-suite' ), $m['name'] ?? $id ) )
            );
        }

        echo '</div>'; // .ug-module-actions
        echo '</div>'; // .ug-module-card
    }

    /**
     * Build the empty-state HTML for a module group with no entries.
     *
     * @param  string $group  Group key.
     * @return string
     */
    private function build_empty_state_html( string $group ): string {
        $msg = $group === 'third-party'
            ? __( 'No third-party modules installed. Use the Install New tab to add extensions.', 'ultraguard-security-suite' )
            : __( 'No modules in this group.', 'ultraguard-security-suite' );
        return sprintf(
            '<div class="ug-module-empty"><span class="dashicons dashicons-plugins-checked"></span><p>%s</p></div>',
            esc_html( $msg )
        );
    }

    // =========================================================================
    // Install card
    // =========================================================================

    /**
     * Build the "Install Module from ZIP" card schema.
     *
     * @param  string $nonce       Security nonce.
     * @param  bool   $is_pro      Whether the current user has a Pro license.
     * @param  string $upgrade_url Upgrade page URL.
     * @return array<string,mixed>
     */
    private function install_card( string $nonce, bool $is_pro, string $upgrade_url ): array {
        $data = [];

        if ( ! $is_pro ) {
            $in_plugin_url = admin_url( \UltraguardPro\support\UpgradeManager::UPGRADE_PAGE_URL_PATTERN );
            $data[] = [
                'type'    => 'html',
                'content' => sprintf(
                    '<table width="100%%" cellpadding="0" cellspacing="0" style="background:#fffbeb;border:1px solid #f59e0b;border-radius:8px;"><tr>'
                    . '<td width="44" valign="middle" style="padding:16px 0 16px 16px;">'
                    . '<span class="dashicons dashicons-awards" style="font-size:28px;width:28px;height:28px;color:#d97706;display:block;"></span>'
                    . '</td>'
                    . '<td valign="middle" style="padding:16px 12px;">'
                    . '<strong style="display:block;font-size:13px;color:#92400e;margin:0 0 3px;">%s</strong>'
                    . '<span style="font-size:13px;color:#78350f;">%s</span>'
                    . '</td>'
                    . '<td width="180" valign="middle" style="padding:16px 16px 16px 0;white-space:nowrap;">'
                    . '<a href="%s" class="button ultraguard-button ug-module-btn ug-module-btn--upgrade">'
                    . '<span class="dashicons dashicons-star-filled"></span>%s</a>'
                    . '</td>'
                    . '</tr></table>',
                    esc_html__( 'Pro Feature', 'ultraguard-security-suite' ),
                    esc_html__( 'Third-party module upload requires UltraGuard Pro. See the full comparison to learn what\'s included.', 'ultraguard-security-suite' ),
                    esc_url( $in_plugin_url ),
                    esc_html__( 'Compare Free vs Pro', 'ultraguard-security-suite' )
                ),
            ];
        } else {
            $data[] = [
                'type'       => 'alert-box',
                'alert_type' => 'info',
                'message'    => __( 'Upload a ZIP file containing a valid UltraGuard Pro module. The ZIP must include a module.json manifest at its root.', 'ultraguard-security-suite' ),
            ];
            $data[] = [
                'type'    => 'html',
                'content' => $this->render_upload_form(),
            ];
        }

        return [
            'type'  => 'card',
            'id'    => 'modules-install-card',
            'title' => __( 'Install Module from ZIP', 'ultraguard-security-suite' ),
            'icon'  => 'dashicons-upload',
            'data'  => $data,
        ];
    }

    /**
     * Build the upload drop-zone HTML string.
     *
     * @return string
     */
    private function render_upload_form(): string {
        ob_start(); ?>
        <div class="ug-upload-wrapper">
            <input type="file" id="module-zip-input" name="module_zip" accept=".zip" style="display:none;" />
            <div class="ug-drop-zone" id="module-drop-zone"
                 onclick="document.getElementById('module-zip-input').click()">
                <span class="dashicons dashicons-upload ug-drop-icon"></span>
                <p class="ug-drop-title"><?php esc_html_e( 'Drop ZIP here or click to browse', 'ultraguard-security-suite' ); ?></p>
                <p class="ug-drop-hint"><?php esc_html_e( 'Maximum 50 MB · must contain module.json', 'ultraguard-security-suite' ); ?></p>
            </div>
            <div id="module-upload-progress" style="display:none;" class="ug-upload-progress">
                <div class="ug-upload-track"><div id="module-upload-bar" class="ug-upload-fill"></div></div>
                <p id="module-upload-status" class="ug-upload-status-text"></p>
            </div>
            <div id="module-upload-result" style="display:none;margin-top:12px;"></div>
        </div>
        <?php return ob_get_clean();
    }

    /**
     * Build the "Module Package Format" reference card.
     *
     * @return array<string,mixed>
     */
    private function module_format_card(): array {
        return [
            'type'  => 'card',
            'id'    => 'modules-format-card',
            'title' => __( 'Module Package Format', 'ultraguard-security-suite' ),
            'icon'  => 'dashicons-info-outline',
            'data'  => [
                [
                    'type'  => 'list',
                    'items' => [
                        [ 'icon' => 'dashicons-yes', 'text' => __( 'ZIP must contain one root folder named after the module ID', 'ultraguard-security-suite' ) ],
                        [ 'icon' => 'dashicons-yes', 'text' => __( 'Root folder must contain a module.json manifest file', 'ultraguard-security-suite' ) ],
                        [ 'icon' => 'dashicons-yes', 'text' => __( 'module.json must define: id, name, description, version, class, type', 'ultraguard-security-suite' ) ],
                        [ 'icon' => 'dashicons-yes', 'text' => __( 'The class must extend AbstractModule and implement get_id() and boot()', 'ultraguard-security-suite' ) ],
                        [ 'icon' => 'dashicons-yes', 'text' => __( 'Set "license_required": "pro" in module.json to restrict to Pro users', 'ultraguard-security-suite' ) ],
                        [ 'icon' => 'dashicons-yes', 'text' => __( 'All cross-module communication must use WordPress actions/filters only', 'ultraguard-security-suite' ) ],
                    ],
                ],
                [
                    'type'    => 'terminal',
                    'id'      => 'module-json-example',
                    'title'   => 'module.json example',
                    'content' => "{\n  \"id\":               \"my-module\",\n  \"name\":             \"My Security Module\",\n  \"description\":      \"What this module does.\",\n  \"version\":          \"1.0.0\",\n  \"author\":           \"Your Name\",\n  \"class\":            \"MyVendor\\\\MyModule\\\\MyModuleModule\",\n  \"type\":             \"feature\",\n  \"requires\":         \"6.5.0\",\n  \"license_required\": \"free\"\n}",
                ],
            ],
        ];
    }

    // =========================================================================
    // Upload JS (named method — no Closure, so remove_action() works correctly)
    // =========================================================================

    /**
     * Register the upload JavaScript on admin_footer.
     * Uses a named static method so it can be unhooked if needed.
     *
     * @param string $nonce  Security nonce to embed in the script.
     */
    private function register_upload_footer_script( string $nonce ): void {
        // Store nonce for the named callback to access without a Closure
        $this->upload_nonce = $nonce;
        add_action( 'admin_footer', [ $this, 'print_upload_script' ] );
    }

    /**
     * Output the inline upload/search JS to the admin footer.
     * Public so it works as an add_action() callback with no Closure.
     */
    public function print_upload_script(): void {
        $ajax_url   = wp_json_encode( self_admin_url( 'admin-ajax.php' ) );
        $nonce_js   = wp_json_encode( $this->upload_nonce );

        // All translatable strings encoded once — avoids repeated calls in JS
        $i18n = wp_json_encode( [
            'zip_only'    => __( 'Only ZIP files are accepted.',           'ultraguard-security-suite' ),
            'uploading'   => __( 'Uploading…',                             'ultraguard-security-suite' ),
            'installing'  => __( 'Installing…',                            'ultraguard-security-suite' ),
            'reloading'   => __( 'Reloading…',                             'ultraguard-security-suite' ),
            'up_fail'     => __( 'Upload failed.',                         'ultraguard-security-suite' ),
            'bad_resp'    => __( 'Invalid server response.',               'ultraguard-security-suite' ),
            'net_up'      => __( 'Network error during upload.',           'ultraguard-security-suite' ),
            'inst_fail'   => __( 'Installation failed.',                   'ultraguard-security-suite' ),
            'net_inst'    => __( 'Network error during installation.',     'ultraguard-security-suite' ),
        ] );
        ?>
        <script id="ultraguard-module-upload-script">
        (function() {
            'use strict';

            /* ── Live search filter ───────────────────────────── */
            window.ugFilterModules = function(listId, query) {
                var list = document.getElementById(listId);
                if (!list) { return; }
                var q = (query || '').toLowerCase().trim();
                list.querySelectorAll('.ug-module-card').forEach(function(card) {
                    var name = (card.dataset.moduleName || '').toLowerCase();
                    card.style.display = (!q || name.includes(q)) ? '' : 'none';
                });
            };

            /* ── ZIP upload handler ───────────────────────────── */
            var ajaxUrl = <?php echo wp_json_encode($ajax_url); ?>
            var nonce   = <?php echo wp_json_encode($nonce_js); ?>
            var i18n    = <?php echo wp_json_encode($i18n); ?>

            var input  = document.getElementById('module-zip-input');
            var zone   = document.getElementById('module-drop-zone');
            var prog   = document.getElementById('module-upload-progress');
            var bar    = document.getElementById('module-upload-bar');
            var status = document.getElementById('module-upload-status');
            var result = document.getElementById('module-upload-result');

            if (!input || !zone) { return; }

            zone.addEventListener('dragover', function(e) {
                e.preventDefault();
                zone.classList.add('ug-drop-zone--over');
            });
            zone.addEventListener('dragleave', function() {
                zone.classList.remove('ug-drop-zone--over');
            });
            zone.addEventListener('drop', function(e) {
                e.preventDefault();
                zone.classList.remove('ug-drop-zone--over');
                if (e.dataTransfer.files.length) { upload(e.dataTransfer.files[0]); }
            });
            input.addEventListener('change', function() {
                if (input.files.length) { upload(input.files[0]); }
            });

            function upload(file) {
                if (!file.name.endsWith('.zip')) {
                    showResult('error', i18n.zip_only);
                    return;
                }

                prog.style.display   = 'block';
                result.style.display = 'none';
                bar.style.width      = '10%';
                status.textContent   = i18n.uploading;

                var fd = new FormData();
                fd.append('action',     'ultraguard_module_upload_zip');
                fd.append('nonce',      nonce);
                fd.append('module_zip', file);

                var xhr = new XMLHttpRequest();
                xhr.upload.onprogress = function(e) {
                    if (e.lengthComputable) {
                        bar.style.width = Math.round((e.loaded / e.total) * 70) + '%';
                    }
                };
                xhr.onload = function() {
                    bar.style.width = '80%';
                    var resp;
                    try { resp = JSON.parse(xhr.responseText); }
                    catch(ex) { showResult('error', i18n.bad_resp); return; }

                    if (!resp.success) {
                        showResult('error', (resp.data && resp.data.message) ? resp.data.message : i18n.up_fail);
                        return;
                    }
                    status.textContent = i18n.installing;
                    installModule(resp.data.zip_path);
                };
                xhr.onerror = function() { showResult('error', i18n.net_up); };
                xhr.open('POST', ajaxUrl);
                xhr.send(fd);
            }

            function installModule(zipPath) {
                var fd = new FormData();
                fd.append('action',   'ultraguard_module_install');
                fd.append('nonce',    nonce);
                fd.append('zip_path', zipPath);

                fetch(ajaxUrl, { method: 'POST', body: fd })
                    .then(function(r) { return r.json(); })
                    .then(function(resp) {
                        bar.style.width = '100%';
                        if (resp.success) {
                            showResult('success', resp.data.message || '');
                            if (resp.data.reload) {
                                status.textContent = i18n.reloading;
                                setTimeout(function() { window.location.reload(); }, 1500);
                            }
                        } else {
                            var msg = (resp.data && resp.data.message) ? resp.data.message : i18n.inst_fail;
                            if (resp.data && resp.data.upgrade_url) {
                                msg += ' <a href="' + resp.data.upgrade_url + '" target="_blank" rel="noopener noreferrer">Upgrade to Pro</a>';
                            }
                            showResult('error', msg, true);
                        }
                    })
                    .catch(function() { showResult('error', i18n.net_inst); });
            }

            function showResult(type, message, isHtml) {
                prog.style.display   = 'none';
                result.style.display = 'block';
                var isOk   = (type === 'success');
                var colour = isOk ? '#10b981' : '#ef4444';
                var icon   = isOk ? 'dashicons-yes-alt' : 'dashicons-warning';
                var safe   = isHtml ? message
                    : message.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
                result.innerHTML =
                    '<div style="display:flex;align-items:center;gap:10px;padding:12px 16px;border-radius:8px;' +
                    'background:' + (isOk ? '#f0fdf4' : '#fef2f2') + ';border:1px solid ' + colour + '30;">' +
                    '<span class="dashicons ' + icon + '" style="color:' + colour + ';font-size:22px;width:22px;height:22px;flex-shrink:0;"></span>' +
                    '<span style="color:' + colour + ';font-weight:500;font-size:14px;">' + safe + '</span></div>';
            }
        })();
        </script>
        <?php
    }
}
