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

trait EEP_Admin_Trait {
    private function can_manage_freemius_license_page() {
        if (!function_exists('epw_fs')) {
            return false;
        }

        try {
            $fs = epw_fs();
            $premium_active = method_exists($fs, 'can_use_premium_code__premium_only')
                ? (bool) $fs->can_use_premium_code__premium_only()
                : false;
            $trial_active = method_exists($fs, 'is_trial') ? (bool) $fs->is_trial() : false;
            return $premium_active || $trial_active;
        } catch (Throwable $unused) {
            return false;
        }
    }


    public function maybe_redirect_unlicensed_pricing_page() {
        if (!is_admin()) {
            return;
        }

        $page = isset($_GET['page']) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            ? sanitize_key((string) wp_unslash($_GET['page'])) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            : '';
        if ($page !== 'eep-settings-pricing') {
            return;
        }

        if ($this->can_manage_freemius_license_page()) {
            return;
        }

        $fallback = admin_url('admin.php?page=eep-settings#eep-tab-monetization--boost-packages');
        wp_safe_redirect($fallback);
        exit;
    }


    public function maybe_enable_theme_menu_support_for_wp_menu_source() {
        $wp_menu_source_enabled = (string) get_option('eep_frontend_sticky_nav_use_wp_menus', '0') === '1'
            || (string) get_option('eep_frontend_footer_use_wp_menus', '0') === '1';
        if (!$wp_menu_source_enabled) {
            return;
        }
        if (!current_theme_supports('menus')) {
            add_theme_support('menus');
        }
    }


    public function register_wp_menu_source_appearance_menu() {
        $wp_menu_source_enabled = (string) get_option('eep_frontend_sticky_nav_use_wp_menus', '0') === '1'
            || (string) get_option('eep_frontend_footer_use_wp_menus', '0') === '1';
        if (!$wp_menu_source_enabled || !current_user_can('edit_theme_options')) {
            return;
        }

        global $submenu;
        $appearance_submenus = isset($submenu['themes.php']) && is_array($submenu['themes.php']) ? (array) $submenu['themes.php'] : [];
        foreach ($appearance_submenus as $submenu_item) {
            if (!is_array($submenu_item)) {
                continue;
            }
            $submenu_slug = isset($submenu_item[2]) ? sanitize_key((string) $submenu_item[2]) : '';
            if ($submenu_slug === 'nav-menusphp' || $submenu_slug === 'eep-wp-menu-source') {
                return;
            }
        }

        add_submenu_page(
            'themes.php',
            __('Menus', 'nexdirectory'),
            __('Menus', 'nexdirectory'),
            'edit_theme_options',
            'eep-wp-menu-source',
            [$this, 'render_wp_menu_source_bridge_page']
        );
    }


    public function render_wp_menu_source_bridge_page() {
        if (!current_user_can('edit_theme_options')) {
            wp_die(__('Sorry, you are not allowed to access this page.', 'nexdirectory'));
        }

        $nav_menu_source_enabled = (string) get_option('eep_frontend_sticky_nav_use_wp_menus', '0') === '1';
        $footer_menu_source_enabled = (string) get_option('eep_frontend_footer_use_wp_menus', '0') === '1';
        $wp_menu_source_enabled = $nav_menu_source_enabled || $footer_menu_source_enabled;
        $settings_anchor = $nav_menu_source_enabled && !$footer_menu_source_enabled ? 'navbar' : 'footer';
        $settings_url = admin_url('admin.php?page=eep-settings#eep-tab-general--' . $settings_anchor);
        if (!$wp_menu_source_enabled) {
            wp_safe_redirect($settings_url);
            exit;
        }

        $classic_menus_url = admin_url('nav-menus.php');
        if (current_theme_supports('menus')) {
            wp_safe_redirect($classic_menus_url);
            exit;
        }

        $navigation_editor_url = '';
        if (function_exists('wp_is_block_theme') && wp_is_block_theme()) {
            $navigation_editor_url = admin_url('site-editor.php?path=%2Fnavigation');
            wp_safe_redirect($navigation_editor_url);
            exit;
        }

        echo '<div class="wrap">';
        echo '<h1>' . esc_html__('Menus', 'nexdirectory') . '</h1>';
        echo '<p>' . esc_html__('Menu management is enabled, but this theme does not currently expose a direct menu editor screen.', 'nexdirectory') . '</p>';
        echo '<p><a class="button button-primary" href="' . esc_url($classic_menus_url) . '">' . esc_html__('Open Classic Menus', 'nexdirectory') . '</a></p>';
        if ($navigation_editor_url !== '') {
            echo '<p><a class="button" href="' . esc_url($navigation_editor_url) . '">' . esc_html__('Open Navigation Editor', 'nexdirectory') . '</a></p>';
        }
        $brand_name = $this->get_white_label_brand_name();
        $settings_label = sprintf(__('Back to %s Settings', 'nexdirectory'), $brand_name);
        echo '<p><a class="button" href="' . esc_url($settings_url) . '">' . esc_html($settings_label) . '</a></p>';
        echo '</div>';
    }


    public function register_settings_page() {
        $moderation_badge_count = $this->get_open_moderation_items_count();
        $badge_toggle = get_option('eep_notify_admin_pending_badge', null);
        if ($badge_toggle === null || $badge_toggle === false) {
            $badge_toggle = get_option('eep_enable_pending_admin_notifications', '1');
        }
        $show_pending_badge = (string) $badge_toggle === '1';
        $brand_name = $this->get_white_label_brand_name();
        $menu_page_title = sprintf(__('%s Events', 'nexdirectory'), $brand_name);
        $settings_menu_label = sprintf(__('%s Settings', 'nexdirectory'), $brand_name);
        $menu_title = $menu_page_title;
        if ($show_pending_badge && $moderation_badge_count > 0) {
            $menu_title .= ' <span class="awaiting-mod count-' . (int) $moderation_badge_count . '"><span class="pending-count">' . (int) $moderation_badge_count . '</span></span>';
        }
        $ui_labels = method_exists($this, 'get_site_profile_ui_labels') ? (array) $this->get_site_profile_ui_labels() : [];
        $plural_label = sanitize_text_field((string) ($ui_labels['plural'] ?? __('Events', 'nexdirectory')));
        if ($plural_label === '') {
            $plural_label = __('Events', 'nexdirectory');
        }
        $import_menu_label = __('Import Listing', 'nexdirectory');
        add_menu_page(
            $menu_page_title,
            $menu_title,
            'manage_options',
            'eep-dashboard',
            [$this, 'render_dashboard_page'],
            $this->get_white_label_menu_icon(),
            58
        );
        add_submenu_page(
            'eep-dashboard',
            $settings_menu_label,
            $settings_menu_label,
            'manage_options',
            'eep-settings',
            [$this, 'render_settings_page']
        );
        add_submenu_page(
            'eep-dashboard',
            __('Pricing & License', 'nexdirectory'),
            __('Pricing & License', 'nexdirectory'),
            'manage_options',
            'eep-settings-pricing',
            [$this, 'render_settings_page']
        );
        add_submenu_page(
            'eep-dashboard',
            __('User Management', 'nexdirectory'),
            __('User Management', 'nexdirectory'),
            'manage_options',
            'eep-user-management',
            [$this, 'render_admin_user_management_page']
        );
        $moderation_menu_title = __('Moderation Queue', 'nexdirectory');
        if ($show_pending_badge && $moderation_badge_count > 0) {
            $moderation_menu_title .= ' <span class="awaiting-mod count-' . (int) $moderation_badge_count . '"><span class="pending-count">' . (int) $moderation_badge_count . '</span></span>';
        }
        add_submenu_page(
            'eep-dashboard',
            __('Moderation Queue', 'nexdirectory'),
            $moderation_menu_title,
            'manage_options',
            'eep-moderation',
            [$this, 'render_admin_moderation_page']
        );
        if (!function_exists('epw_fs') || epw_fs()->can_use_premium_code__premium_only()) {
            add_submenu_page(
                'eep-dashboard',
                __('Metrics', 'nexdirectory'),
                __('Metrics', 'nexdirectory'),
                'manage_options',
                'eep-metrics',
                [$this, 'render_metrics_page']
            );
        }
        add_submenu_page(
            'eep-dashboard',
            __('Onboarding Wizard', 'nexdirectory'),
            __('Onboarding Wizard', 'nexdirectory'),
            'manage_options',
            'eep-onboarding',
            [$this, 'render_onboarding_page']
        );
        add_submenu_page(
            'eep-dashboard',
            __('Diagnostics', 'nexdirectory'),
            __('Diagnostics', 'nexdirectory'),
            'manage_options',
            'eep-diagnostics',
            [$this, 'render_diagnostics_page']
        );
        add_submenu_page(
            'eep-dashboard',
            $import_menu_label,
            $import_menu_label,
            'manage_options',
            'eep-import',
            [$this, 'render_import_page']
        );
        add_submenu_page(
            'eep-dashboard',
            __('Change Listing Owner', 'nexdirectory'),
            __('Change Listing Owner', 'nexdirectory'),
            'manage_options',
            'eep-transfer-owner',
            [$this, 'render_transfer_owner_page']
        );
        remove_submenu_page('eep-dashboard', 'eep-transfer-owner');
    }


    public function enqueue_admin_page_assets() {
        if (!is_admin()) {
            return;
        }
        $page = isset($_GET['page']) ? sanitize_key(wp_unslash($_GET['page'])) : '';
        if ($page !== 'eep-moderation') {
            return;
        }
        $this->enqueue_assets();
    }

    public function redirect_event_add_new_to_frontend_submit() {
        if (!is_admin()) {
            return;
        }

        $post_type = isset($_GET['post_type']) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            ? sanitize_key((string) wp_unslash($_GET['post_type'])) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            : 'post';
        if ($post_type !== self::POST_TYPE) {
            return;
        }

        if (isset($_GET['eep_wp_editor']) && (string) wp_unslash($_GET['eep_wp_editor']) === '1') { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
            return;
        }

        $post_type_object = get_post_type_object(self::POST_TYPE);
        if (!$post_type_object || !is_object($post_type_object) || !isset($post_type_object->cap)) {
            return;
        }
        $create_capability = isset($post_type_object->cap->create_posts) && is_string($post_type_object->cap->create_posts)
            ? $post_type_object->cap->create_posts
            : ((isset($post_type_object->cap->edit_posts) && is_string($post_type_object->cap->edit_posts)) ? $post_type_object->cap->edit_posts : 'edit_posts');
        if (!current_user_can($create_capability)) {
            return;
        }

        $submit_page_url = trim((string) get_option('eep_page_submit_event_url', ''));
        if ($submit_page_url === '') {
            $submit_page_url = method_exists($this, 'get_profile_route_default_url')
                ? (string) $this->get_profile_route_default_url('submit')
                : (string) home_url('/submit/');
        }
        $submit_page_url = esc_url_raw($submit_page_url);
        if ($submit_page_url === '') {
            return;
        }

        $target_url = (string) eep_add_query_arg('eep_tab', 'submit', $submit_page_url);
        if (strpos($target_url, '#submit') === false) {
            $target_url .= '#submit';
        }

        wp_safe_redirect($target_url);
        exit;
    }


    public function register_elementor_category($elements_manager) {
        if (!is_object($elements_manager) || !method_exists($elements_manager, 'add_category')) {
            return;
        }
        $elements_manager->add_category('eep-widgets', [
            'title' => $this->get_white_label_brand_name(),
            'icon' => 'fa fa-plug',
        ]);
    }


    public function register_elementor_widgets($widgets_manager) {
        if (!did_action('elementor/loaded')) {
            return;
        }
        $file = plugin_dir_path(EEP_PLUGIN_FILE) . 'includes/elementor-widgets.php';
        if (file_exists($file)) {
            require_once $file;
        }
        if (function_exists('eep_register_elementor_widgets')) {
            eep_register_elementor_widgets($widgets_manager);
        }
    }


    public function register_settings() {
        register_setting('eep_settings_group', 'eep_google_maps_api_key', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_google_maps_api_key_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_map_pin_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_recaptcha_site_key', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_recaptcha_secret_key', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_recaptcha_secret_key_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_recaptcha_version', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_recaptcha_version_option'],
            'default' => 'v3',
        ]);
        register_setting('eep_settings_group', 'eep_recaptcha_show_submit', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        if (!function_exists('epw_fs') || epw_fs()->can_use_premium_code__premium_only()) {
            register_setting('eep_settings_group', 'eep_chatbot_enabled', [
                'type' => 'string',
                'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
                'default' => '0',
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_debug_mode', [
                'type' => 'string',
                'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
                'default' => '0',
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_openai_api_key', [
                'type' => 'string',
                'sanitize_callback' => [$this, 'sanitize_chatbot_openai_api_key_option'],
                'default' => '',
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_model', [
                'type' => 'string',
                'sanitize_callback' => 'eep_sanitize_text',
                'default' => 'gpt-5.2',
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_embedding_model', [
                'type' => 'string',
                'sanitize_callback' => [$this, 'sanitize_chatbot_embedding_model_option'],
                'default' => 'text-embedding-3-small',
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_embedding_dimensions', [
                'type' => 'integer',
                'sanitize_callback' => [$this, 'sanitize_chatbot_embedding_dimensions_option'],
                'default' => 512,
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_index_post_types', [
                'type' => 'string',
                'sanitize_callback' => [$this, 'sanitize_chatbot_index_post_types_option'],
                'default' => wp_json_encode([self::POST_TYPE, 'post', 'page']),
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_ai_catalog_enabled', [
                'type' => 'string',
                'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
                'default' => '1',
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_name', [
                'type' => 'string',
                'sanitize_callback' => 'eep_sanitize_text',
                'default' => __('Listing Assistant', 'nexdirectory'),
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_personality', [
                'type' => 'string',
                'sanitize_callback' => 'eep_sanitize_textarea',
                'default' => '',
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_welcome_text', [
                'type' => 'string',
                'sanitize_callback' => 'eep_sanitize_text',
                'default' => __('Ask me about upcoming listings and I will recommend the best matches.', 'nexdirectory'),
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_position_desktop', [
                'type' => 'string',
                'sanitize_callback' => [$this, 'sanitize_chatbot_desktop_position_option'],
                'default' => 'bottom-right',
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_position_mobile', [
                'type' => 'string',
                'sanitize_callback' => [$this, 'sanitize_chatbot_mobile_position_option'],
                'default' => 'right-edge-center',
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_theme_color', [
                'type' => 'string',
                'sanitize_callback' => [$this, 'sanitize_color_option'],
                'default' => '#FF5E14',
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_text_color', [
                'type' => 'string',
                'sanitize_callback' => [$this, 'sanitize_color_option'],
                'default' => '#0B1221',
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_top_k', [
                'type' => 'integer',
                'sanitize_callback' => [$this, 'sanitize_chatbot_top_k_option'],
                'default' => 6,
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_max_candidates', [
                'type' => 'integer',
                'sanitize_callback' => [$this, 'sanitize_chatbot_candidates_option'],
                'default' => 250,
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_reindex_interval_hours', [
                'type' => 'integer',
                'sanitize_callback' => [$this, 'sanitize_chatbot_reindex_hours_option'],
                'default' => 24,
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_rate_limit_requests', [
                'type' => 'integer',
                'sanitize_callback' => [$this, 'sanitize_chatbot_rate_limit_requests_option'],
                'default' => 30,
            ]);
            register_setting('eep_settings_group', 'eep_chatbot_rate_limit_window_seconds', [
                'type' => 'integer',
                'sanitize_callback' => [$this, 'sanitize_chatbot_rate_limit_window_option'],
                'default' => 600,
            ]);
        }
        register_setting('eep_settings_group', 'eep_require_email_verification', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_enable_pending_admin_notifications', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_notify_admin_pending_badge', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_notify_admin_pending_email', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_notify_author_confirmation', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_notify_author_reminder', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_notify_author_update', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_notify_author_cancellation', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_onboarding_complete', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_smtp_enabled', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_smtp_host', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_smtp_port', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_smtp_port_option'],
            'default' => 587,
        ]);
        register_setting('eep_settings_group', 'eep_smtp_encryption', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_smtp_encryption_option'],
            'default' => 'tls',
        ]);
        register_setting('eep_settings_group', 'eep_smtp_auth', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_smtp_username', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_smtp_password', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_smtp_password_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_smtp_from_email', [
            'type' => 'string',
            'sanitize_callback' => 'sanitize_email',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_smtp_from_name', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_login_redirect_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_page_events_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_page_events_map_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_page_events_calendar_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_page_submit_event_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_page_my_events_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_page_boost_posts_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_page_owner_analytics_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_page_my_tickets_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_page_whos_attending_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_page_event_webapp_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_page_whats_new_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_page_account_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_page_login_signup_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_show_frontend_auth_links', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_enable_spa_hybrid', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_show_spa_feedback_badge', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_enable_frontend_sticky_nav', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_sticky_nav_behavior', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_sticky_nav_behavior_option'],
            'default' => 'sticky',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_sticky_nav_show_for_guests', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_sticky_nav_show_for_members', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_sticky_nav_include_auth_cta', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_sticky_nav_show_logo', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_sticky_nav_logo_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_sticky_nav_logo_link_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_sticky_nav_logo_size', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_sticky_nav_logo_size_option'],
            'default' => '66px',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_sticky_nav_custom_links', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_sticky_nav_custom_links_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_sticky_nav_use_wp_menus', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_sticky_nav_wp_menu_guest', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_nav_menu_id_option'],
            'default' => 0,
        ]);
        register_setting('eep_settings_group', 'eep_frontend_sticky_nav_wp_menu_member', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_nav_menu_id_option'],
            'default' => 0,
        ]);
        register_setting('eep_settings_group', 'eep_frontend_sticky_nav_wp_menu_admin', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_nav_menu_id_option'],
            'default' => 0,
        ]);
        register_setting('eep_settings_group', 'eep_frontend_sticky_nav_wp_menu_roles', [
            'type' => 'array',
            'sanitize_callback' => [$this, 'sanitize_sticky_nav_role_menu_map_option'],
            'default' => [],
        ]);
        register_setting('eep_settings_group', 'eep_enable_frontend_footer', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_footer_show_logo', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_footer_logo_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_footer_logo_link_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_footer_use_wp_menus', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_footer_menu_count', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_footer_menu_count_option'],
            'default' => 3,
        ]);
        register_setting('eep_settings_group', 'eep_frontend_footer_wp_menus', [
            'type' => 'array',
            'sanitize_callback' => [$this, 'sanitize_footer_wp_menu_list_option'],
            'default' => [],
        ]);
        register_setting('eep_settings_group', 'eep_frontend_footer_show_privacy_link', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_frontend_footer_bottom_text', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_footer_bottom_text_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_style_use_theme_defaults', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_style_accent_color', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_color_option'],
            'default' => '#FF5E14',
        ]);
        register_setting('eep_settings_group', 'eep_style_accent_hover_color', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_color_option'],
            'default' => '#E04F0D',
        ]);
        register_setting('eep_settings_group', 'eep_style_fallback_thumb_url', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_multi_image_urls_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_style_fallback_hero_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_style_favicon_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_home_meta_title', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_home_meta_title_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_home_meta_description', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_home_meta_description_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_style_font_family', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_font_family_option'],
            'default' => 'Inter, system-ui, -apple-system, sans-serif',
        ]);
        register_setting('eep_settings_group', 'eep_style_display_font_family', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_font_family_option'],
            'default' => 'Oswald, Inter, sans-serif',
        ]);
        register_setting('eep_settings_group', 'eep_style_font_size_base', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_size_option'],
            'default' => '18px',
        ]);
        register_setting('eep_settings_group', 'eep_style_h2_size', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_size_option'],
            'default' => '1.75rem',
        ]);
        register_setting('eep_settings_group', 'eep_style_h3_size', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_size_option'],
            'default' => '1.35rem',
        ]);
        register_setting('eep_settings_group', 'eep_style_font_weight_body', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_font_weight_option'],
            'default' => '400',
        ]);
        register_setting('eep_settings_group', 'eep_style_font_weight_heading', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_font_weight_option'],
            'default' => '700',
        ]);
        register_setting('eep_settings_group', 'eep_style_spacing_unit', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_size_option'],
            'default' => '16px',
        ]);
        register_setting('eep_settings_group', 'eep_style_spacing_scale', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_spacing_scale_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_style_radius_md', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_size_option'],
            'default' => '12px',
        ]);
        register_setting('eep_settings_group', 'eep_style_radius_lg', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_size_option'],
            'default' => '24px',
        ]);
        register_setting('eep_settings_group', 'eep_style_box_style', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_style_box_style_option'],
            'default' => 'default',
        ]);
        register_setting('eep_settings_group', 'eep_style_button_style', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_style_button_style_option'],
            'default' => 'solid',
        ]);
        register_setting('eep_settings_group', 'eep_style_button_radius_mode', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_style_button_radius_mode_option'],
            'default' => 'inherit',
        ]);
        register_setting('eep_settings_group', 'eep_style_density_mode', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_style_density_mode_option'],
            'default' => 'comfortable',
        ]);
        register_setting('eep_settings_group', 'eep_style_border_mode', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_style_border_mode_option'],
            'default' => 'subtle',
        ]);
        register_setting('eep_settings_group', 'eep_style_shadow_mode', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_style_shadow_mode_option'],
            'default' => 'soft',
        ]);
        register_setting('eep_settings_group', 'eep_style_content_width', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_style_content_width_option'],
            'default' => 'standard',
        ]);
        register_setting('eep_settings_group', 'eep_style_input_style', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_style_input_style_option'],
            'default' => 'outline',
        ]);
        register_setting('eep_settings_group', 'eep_enable_submit_autosave', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_autosave_interval_seconds', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_autosave_interval'],
            'default' => 60,
        ]);
        register_setting('eep_settings_group', 'eep_enable_event_reporting', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_default_submit_show_nav', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_hide_theme_titles_on_plugin_pages', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_theme_override_all_plugin_pages', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_theme_override_full_width', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_theme_override_remove_padding', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_theme_override_hide_title', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_theme_override_hide_comments', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_theme_override_hide_featured_image', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_theme_override_hide_header', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_theme_override_reset_theme_styles', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_enable_map_auto_search', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_map_results_per_page', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_map_results_per_page_option'],
            'default' => 120,
        ]);
        register_setting('eep_settings_group', 'eep_map_layout_default', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_map_layout_option'],
            'default' => 'three-column',
        ]);
        register_setting('eep_settings_group', 'eep_page_side_padding', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_page_side_padding_option'],
            'default' => '10%',
        ]);
        register_setting('eep_settings_group', 'eep_page_side_padding_mobile', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_page_side_padding_mobile_option'],
            'default' => '2%',
        ]);
        register_setting('eep_settings_group', 'eep_nav_side_padding_desktop', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_nav_side_padding_desktop_option'],
            'default' => '0%',
        ]);
        register_setting('eep_settings_group', 'eep_enable_smooth_scrolling', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_smooth_scroll_profile', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_smooth_scroll_profile_option'],
            'default' => 'balanced',
        ]);
        register_setting('eep_settings_group', 'eep_smooth_scroll_touchpad_behavior', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_smooth_scroll_touchpad_behavior_option'],
            'default' => 'native',
        ]);
        register_setting('eep_settings_group', 'eep_smooth_scroll_wheel_multiplier', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_smooth_scroll_wheel_multiplier_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_smooth_scroll_ease', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_smooth_scroll_ease_option'],
            'default' => '1.2',
        ]);
        register_setting('eep_settings_group', 'eep_smooth_scroll_max_step_px', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_smooth_scroll_max_step_option'],
            'default' => 960,
        ]);
        register_setting('eep_settings_group', 'eep_smooth_scroll_min_step_px', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_smooth_scroll_min_step_option'],
            'default' => '0.16',
        ]);
        register_setting('eep_settings_group', 'eep_smooth_scroll_enable_on_touch', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_preloader_enabled', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_preloader_source', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_preloader_source_option'],
            'default' => 'svg',
        ]);
        register_setting('eep_settings_group', 'eep_preloader_svg_markup', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_preloader_svg_option'],
            'default' => $this->get_default_preloader_svg_markup(),
        ]);
        register_setting('eep_settings_group', 'eep_preloader_image_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_preloader_background_color', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_preloader_background_color_option'],
            'default' => '#FFFFFF',
        ]);
        register_setting('eep_settings_group', 'eep_preloader_logo_max_width', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_preloader_logo_max_width_option'],
            'default' => 420,
        ]);
        register_setting('eep_settings_group', 'eep_preloader_min_duration_ms', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_preloader_min_duration_option'],
            'default' => 400,
        ]);
        register_setting('eep_settings_group', 'eep_preloader_fade_duration_ms', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_preloader_fade_duration_option'],
            'default' => 420,
        ]);
        register_setting('eep_settings_group', 'eep_preloader_show_on_initial', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_preloader_show_on_spa', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_preloader_show_only_home', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_preloader_show_once', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_preloader_disable_mobile', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_preloader_respect_motion', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_map_view_template', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_map_view_template_option'],
            'default' => 'default',
        ]);
        register_setting('eep_settings_group', 'eep_map_focus_region', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_map_focus_region_option'],
            'default' => 'global',
        ]);
        register_setting('eep_settings_group', 'eep_map_results_density', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_map_density_option'],
            'default' => 'comfortable',
        ]);
        register_setting('eep_settings_group', 'eep_map_mobile_filter_mode', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_map_mobile_filter_mode_option'],
            'default' => 'drawer',
        ]);
        register_setting('eep_settings_group', 'eep_map_provider', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_map_provider_option'],
            'default' => 'openstreetmap',
        ]);
        register_setting('eep_settings_group', 'eep_map_style', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_map_style_option'],
            'default' => 'osm-standard',
        ]);
        register_setting('eep_settings_group', 'eep_mapbox_access_token', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_mapbox_access_token_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_mapbox_style_id', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_mapbox_style_id_option'],
            'default' => 'mapbox/streets-v12',
        ]);
        register_setting('eep_settings_group', 'eep_map_custom_tile_url', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_map_custom_tile_attribution', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_map_custom_tile_subdomains', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_site_profile', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_site_profile_option'],
            'default' => 'events',
        ]);
        register_setting('eep_settings_group', 'eep_platform_mode', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_platform_mode_option'],
            'default' => 'user_generated',
        ]);
        register_setting('eep_settings_group', 'eep_event_hero_layout', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_hero_layout_option'],
            'default' => 'cinematic',
        ]);
        register_setting('eep_settings_group', 'eep_event_hero_kicker_text', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => 'NexDirectory',
        ]);
        register_setting('eep_settings_group', 'eep_company_brand_name', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_company_brand_name_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_event_page_layout', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_event_page_layout_option'],
            'default' => 'modern',
        ]);
        register_setting('eep_settings_group', 'eep_event_gallery_type', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_event_gallery_type_option'],
            'default' => 'default',
        ]);
        register_setting('eep_settings_group', 'eep_enable_hero_parallax', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_map_filter_show_search', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_map_filter_show_type', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_map_filter_show_mode', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_map_filter_show_tag', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_map_filter_show_price', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_map_filter_show_official', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_map_filter_show_date', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_map_filter_show_distance', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_enable_account_tabs_ajax', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_enable_moderation_ajax', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_use_action_scheduler', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_uninstall_remove_data', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_use_rich_editor', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_enable_duplicate_detection', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_official_classification_suffix', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_white_label_enabled', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_white_label_enabled_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_white_label_plugin_name', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_white_label_name_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_white_label_plugin_description', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_white_label_textarea_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_white_label_plugin_author', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_white_label_text_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_white_label_plugin_url', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_white_label_url_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_white_label_support_url', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_white_label_url_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_white_label_support_email', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_white_label_support_email_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_white_label_admin_menu_icon', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_white_label_menu_icon_option'],
            'default' => 'dashicons-admin-generic',
        ]);
        register_setting('eep_settings_group', 'eep_white_label_admin_footer_text', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_white_label_text_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_white_label_lock_enabled', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_white_label_lock_enabled_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_white_label_password_hash', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_white_label_password_hash_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_upload_cover_max_kb', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_upload_limit_kb_option'],
            'default' => 500,
        ]);
        register_setting('eep_settings_group', 'eep_upload_gallery_max_kb', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_upload_limit_kb_option'],
            'default' => 2000,
        ]);
        register_setting('eep_settings_group', 'eep_upload_gallery_max_files', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_upload_files_count_option'],
            'default' => 10,
        ]);
        register_setting('eep_settings_group', 'eep_upload_file_max_kb', [
            'type' => 'integer',
            'sanitize_callback' => [$this, 'sanitize_upload_limit_kb_option'],
            'default' => 2048,
        ]);
        register_setting('eep_settings_group', 'eep_custom_form_fields', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_custom_form_fields_option'],
            'default' => '[]',
        ]);
        register_setting('eep_settings_group', 'eep_custom_taxonomies', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_custom_taxonomies_option'],
            'default' => '[]',
        ]);
        register_setting('eep_settings_group', 'eep_enable_custom_submission_fields', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_enable_per_event_email_templates', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_enable_event_seo_fields', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_enable_claim_listings', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_claim_require_admin_approval', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_claim_listing_page_url', [
            'type' => 'string',
            'sanitize_callback' => 'esc_url_raw',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_extension_enabled', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_extension_app_pass', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_extension_app_pass_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_extension_import_status', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_extension_import_status_option'],
            'default' => 'draft',
        ]);
        register_setting('eep_settings_group', 'eep_extension_import_media_policy', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_extension_import_media_policy_option'],
            'default' => 'none',
        ]);
        register_setting('eep_settings_group', 'eep_extension_import_content_mode', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_extension_import_content_mode_option'],
            'default' => 'rewrite',
        ]);
        register_setting('eep_settings_group', 'eep_extension_notify_potential_owner_default', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_extension_import_author_id', [
            'type' => 'integer',
            'sanitize_callback' => 'absint',
            'default' => 0,
        ]);
        register_setting('eep_settings_group', 'eep_extension_import_mark_claimable', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_enable_autogenerated_disclaimer', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_indexnow_enabled', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_indexnow_key', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_indexnow_key_option'],
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_indexnow_endpoint', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_indexnow_endpoint_option'],
            'default' => 'https://api.indexnow.org/indexnow',
        ]);
        register_setting('eep_settings_group', 'eep_indexnow_submit_updates', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_indexnow_submit_removals', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_autogenerated_disclaimer_text', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_textarea',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_notify_admin_claim_email', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_notify_extension_potential_owner', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_user_edit_policy', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_user_edit_policy_option'],
            'default' => 'require_approval',
        ]);
        register_setting('eep_settings_group', 'eep_auto_approve_edits_after_first_approval', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '0',
        ]);
        register_setting('eep_settings_group', 'eep_role_event_submitter_can_submit', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_role_author_can_submit', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_role_editor_can_moderate', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_role_editor_manage_organizers', [
            'type' => 'string',
            'sanitize_callback' => [$this, 'sanitize_checkbox_option'],
            'default' => '1',
        ]);
        register_setting('eep_settings_group', 'eep_email_subject_confirmation', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => 'Listing submission received: {event_title}',
        ]);
        register_setting('eep_settings_group', 'eep_email_body_confirmation', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_textarea',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_email_subject_reminder', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => 'Reminder: {event_title}',
        ]);
        register_setting('eep_settings_group', 'eep_email_body_reminder', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_textarea',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_email_subject_update', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => 'Listing update: {event_title}',
        ]);
        register_setting('eep_settings_group', 'eep_email_body_update', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_textarea',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_email_subject_cancellation', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => 'Listing status changed: {event_title}',
        ]);
        register_setting('eep_settings_group', 'eep_email_body_cancellation', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_textarea',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_email_subject_extension_potential_owner', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => 'Your listing was added to {site_name}: {listing_title}',
        ]);
        register_setting('eep_settings_group', 'eep_email_body_extension_potential_owner', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_textarea',
            'default' => '',
        ]);
        register_setting('eep_settings_group', 'eep_email_subject_ticket_confirmation', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_text',
            'default' => 'Ticket confirmation: {event_title}',
        ]);
        register_setting('eep_settings_group', 'eep_email_body_ticket_confirmation', [
            'type' => 'string',
            'sanitize_callback' => 'eep_sanitize_textarea',
            'default' => '',
        ]);
        if (method_exists($this, 'register_monetization_settings')) {
            $this->register_monetization_settings();
        }
        $this->sync_role_capabilities_from_settings();
    }


    public function sanitize_checkbox_option($value) {
        return ((string) $value === '1') ? '1' : '0';
    }

    public function sanitize_home_meta_title_option($value) {
        $clean = sanitize_text_field((string) $value);
        if ($clean === '') {
            return '';
        }
        if (function_exists('mb_substr')) {
            $clean = mb_substr($clean, 0, 60);
        } else {
            $clean = substr($clean, 0, 60);
        }
        return trim((string) $clean);
    }

    public function sanitize_home_meta_description_option($value) {
        $clean = sanitize_text_field((string) $value);
        if ($clean === '') {
            return '';
        }
        if (function_exists('mb_substr')) {
            $clean = mb_substr($clean, 0, 158);
        } else {
            $clean = substr($clean, 0, 158);
        }
        return trim((string) $clean);
    }


    private function sanitize_secret_option_with_fallback($value, $option_key) {
        $value = is_scalar($value) ? (string) $value : '';
        $sanitized = eep_sanitize_text($value);
        if ($sanitized !== '' && preg_match('/^\*{6,}$/', $sanitized)) {
            return (string) get_option($option_key, '');
        }
        if ($sanitized !== '') {
            return $sanitized;
        }
        return (string) get_option($option_key, '');
    }


    public function sanitize_google_maps_api_key_option($value) {
        return $this->sanitize_secret_option_with_fallback($value, 'eep_google_maps_api_key');
    }


    public function sanitize_recaptcha_secret_key_option($value) {
        return $this->sanitize_secret_option_with_fallback($value, 'eep_recaptcha_secret_key');
    }


    public function sanitize_chatbot_openai_api_key_option($value) {
        return $this->sanitize_secret_option_with_fallback($value, 'eep_chatbot_openai_api_key');
    }


    public function sanitize_smtp_password_option($value) {
        return $this->sanitize_secret_option_with_fallback($value, 'eep_smtp_password');
    }


    public function sanitize_mapbox_access_token_option($value) {
        return $this->sanitize_secret_option_with_fallback($value, 'eep_mapbox_access_token');
    }


    public function sanitize_site_profile_option($value) {
        $previous_value = (string) get_option('eep_site_profile', 'events');
        if (method_exists($this, 'normalize_site_profile_key')) {
            $value = (string) $this->normalize_site_profile_key($value);
            $previous_value = (string) $this->normalize_site_profile_key($previous_value);
        } else {
            $value = sanitize_key((string) $value);
            $previous_value = sanitize_key((string) $previous_value);
        }
        $catalog = method_exists($this, 'get_site_profile_catalog') ? (array) $this->get_site_profile_catalog() : [];
        if ($value === '' || !isset($catalog[$value])) {
            return 'events';
        }
        if ($value !== 'events') {
            $value = 'events';
        }

        if ($previous_value !== '' && isset($catalog[$previous_value]) && $previous_value !== $value) {
            $this->maybe_sync_profile_page_urls($previous_value, $value);
        }
        return $value;
    }


    public function sanitize_platform_mode_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['user_generated', 'single_organisation'], true)
            ? $value
            : 'user_generated';
    }


    private function maybe_sync_profile_page_urls($from_profile_key, $to_profile_key) {
        if (!method_exists($this, 'get_profile_route_slugs') || !method_exists($this, 'get_profile_route_slug')) {
            return;
        }

        $from_profile_key = sanitize_key((string) $from_profile_key);
        $to_profile_key = sanitize_key((string) $to_profile_key);
        if ($from_profile_key === '' || $to_profile_key === '' || $from_profile_key === $to_profile_key) {
            return;
        }

        $route_map = [
            'eep_page_events_url' => 'events',
            'eep_page_events_map_url' => 'map',
            'eep_page_events_calendar_url' => 'calendar',
            'eep_page_submit_event_url' => 'submit',
            'eep_page_my_events_url' => 'my_items',
            'eep_page_boost_posts_url' => 'boost',
            'eep_page_owner_analytics_url' => 'analytics',
            'eep_page_my_tickets_url' => 'attending',
            'eep_page_whos_attending_url' => 'attendees',
            'eep_page_account_url' => 'account',
            'eep_page_login_signup_url' => 'auth',
            'eep_claim_listing_page_url' => 'claim',
        ];

        foreach ($route_map as $option_key => $route_key) {
            $current_url = esc_url_raw((string) get_option($option_key, ''));
            $from_slugs = array_values(array_unique(array_filter(array_map('eep_sanitize_title', (array) $this->get_profile_route_slugs($route_key, $from_profile_key)))));
            $to_slug = eep_sanitize_title((string) $this->get_profile_route_slug($route_key, $to_profile_key));
            if ($to_slug === '') {
                continue;
            }

            $current_slug = '';
            if ($current_url !== '') {
                $current_page_id = absint((int) url_to_postid($current_url));
                if ($current_page_id > 0) {
                    $page_uri = trim((string) get_page_uri($current_page_id), '/');
                    if ($page_uri !== '') {
                        $parts = array_values(array_filter(explode('/', $page_uri)));
                        if (!empty($parts)) {
                            $current_slug = eep_sanitize_title((string) end($parts));
                        }
                    }
                }
                if ($current_slug === '') {
                    $path = trim((string) wp_parse_url($current_url, PHP_URL_PATH), '/');
                    if ($path !== '') {
                        $parts = array_values(array_filter(explode('/', $path)));
                        if (!empty($parts)) {
                            $current_slug = eep_sanitize_title((string) end($parts));
                        }
                    }
                }
            }

            $is_mapped_to_old_mode = $current_url === '' || ($current_slug !== '' && in_array($current_slug, $from_slugs, true));
            if (!$is_mapped_to_old_mode) {
                continue;
            }

            $target_page = get_page_by_path($to_slug);
            if ($target_page instanceof WP_Post) {
                $target_url = get_permalink((int) $target_page->ID);
            } else {
                $target_url = $this->get_profile_route_default_url($route_key, $to_profile_key);
            }
            $target_url = esc_url_raw((string) $target_url);
            if ($target_url === '') {
                continue;
            }
            update_option($option_key, esc_url_raw($target_url), false);
        }
    }


    public function sanitize_company_brand_name_option($value) {
        $value = sanitize_text_field((string) $value);
        $value = trim((string) preg_replace('/\s+/u', ' ', $value));
        return function_exists('mb_substr') ? (string) mb_substr($value, 0, 120) : substr($value, 0, 120);
    }


    public function sanitize_white_label_name_option($value) {
        if (!$this->can_edit_white_label_settings_from_request()) {
            return (string) get_option('eep_white_label_plugin_name', '');
        }
        $value = sanitize_text_field((string) $value);
        $value = trim((string) preg_replace('/\s+/u', ' ', $value));
        return function_exists('mb_substr') ? (string) mb_substr($value, 0, 60) : substr($value, 0, 60);
    }


    public function sanitize_white_label_enabled_option($value) {
        if (!$this->can_edit_white_label_settings_from_request()) {
            return (string) get_option('eep_white_label_enabled', '0');
        }
        return ((string) $value === '1') ? '1' : '0';
    }


    public function sanitize_white_label_text_option($value) {
        if (!$this->can_edit_white_label_settings_from_request()) {
            return $this->get_existing_white_label_option_value('');
        }
        $value = sanitize_text_field((string) $value);
        $value = trim((string) preg_replace('/\s+/u', ' ', $value));
        return function_exists('mb_substr') ? (string) mb_substr($value, 0, 190) : substr($value, 0, 190);
    }


    public function sanitize_white_label_textarea_option($value) {
        if (!$this->can_edit_white_label_settings_from_request()) {
            return $this->get_existing_white_label_option_value('');
        }
        $value = eep_sanitize_textarea((string) $value);
        $value = trim((string) preg_replace('/[ \t]+/u', ' ', $value));
        return function_exists('mb_substr') ? (string) mb_substr($value, 0, 400) : substr($value, 0, 400);
    }


    public function sanitize_white_label_url_option($value) {
        if (!$this->can_edit_white_label_settings_from_request()) {
            return $this->get_existing_white_label_option_value('');
        }
        return esc_url_raw((string) $value);
    }


    public function sanitize_white_label_support_email_option($value) {
        if (!$this->can_edit_white_label_settings_from_request()) {
            return $this->get_existing_white_label_option_value('');
        }
        $email = sanitize_email((string) $value);
        return is_email($email) ? $email : '';
    }


    public function sanitize_white_label_menu_icon_option($value) {
        if (!$this->can_edit_white_label_settings_from_request()) {
            return (string) get_option('eep_white_label_admin_menu_icon', 'dashicons-admin-generic');
        }
        $value = sanitize_html_class((string) $value);
        if ($value === '' || strpos($value, 'dashicons-') !== 0) {
            return 'dashicons-admin-generic';
        }
        return $value;
    }


    public function sanitize_white_label_password_hash_option($value) {
        if (!$this->can_edit_white_label_settings_from_request()) {
            return (string) get_option('eep_white_label_password_hash', '');
        }
        $new_password = (string) wp_unslash($_POST['eep_white_label_password_new'] ?? '');
        $confirm_password = (string) wp_unslash($_POST['eep_white_label_password_confirm'] ?? '');
        if ($new_password === '' && $confirm_password === '') {
            return (string) get_option('eep_white_label_password_hash', '');
        }
        if (strlen($new_password) < 8 || $new_password !== $confirm_password) {
            add_settings_error(
                'eep_white_label_password_hash',
                'eep_white_label_password_hash_error',
                __('White label password was not updated. Make sure both password fields match and are at least 8 characters.', 'nexdirectory'),
                'error'
            );
            return (string) get_option('eep_white_label_password_hash', '');
        }
        $this->reset_white_label_unlock_tokens();
        return wp_hash_password($new_password);
    }


    public function sanitize_white_label_lock_enabled_option($value) {
        if (!$this->can_edit_white_label_settings_from_request()) {
            return (string) get_option('eep_white_label_lock_enabled', '0');
        }
        $enabled = ((string) $value === '1') ? '1' : '0';
        if ($enabled === '1') {
            $new_password = trim((string) wp_unslash($_POST['eep_white_label_password_new'] ?? ''));
            $confirm_password = trim((string) wp_unslash($_POST['eep_white_label_password_confirm'] ?? ''));
            $stored_hash = trim((string) get_option('eep_white_label_password_hash', ''));
            if ($new_password !== '' && (strlen($new_password) < 8 || $new_password !== $confirm_password)) {
                add_settings_error(
                    'eep_white_label_lock_enabled',
                    'eep_white_label_lock_enabled_password_error',
                    __('White label lock was not enabled because the password fields did not match or were shorter than 8 characters.', 'nexdirectory'),
                    'error'
                );
                return '0';
            }
            if ($new_password === '' && $stored_hash === '') {
                add_settings_error(
                    'eep_white_label_lock_enabled',
                    'eep_white_label_lock_enabled_error',
                    __('Set a white label password before enabling lock mode.', 'nexdirectory'),
                    'error'
                );
                return '0';
            }
            $this->reset_white_label_unlock_tokens();
        }
        return $enabled;
    }


    private function get_white_label_brand_name() {
        $company_brand_name = sanitize_text_field((string) get_option('eep_company_brand_name', ''));
        if ($company_brand_name !== '') {
            return $company_brand_name;
        }

        $enabled = (string) get_option('eep_white_label_enabled', '0') === '1';
        $custom_name = sanitize_text_field((string) get_option('eep_white_label_plugin_name', ''));
        if ($enabled && $custom_name !== '') {
            return $custom_name;
        }

        $site_name = sanitize_text_field((string) get_option('blogname', get_bloginfo('name')));
        if ($site_name !== '') {
            return $site_name;
        }

        return __('NexDirectory', 'nexdirectory');
    }


    private function get_white_label_menu_icon() {
        $icon = sanitize_html_class((string) get_option('eep_white_label_admin_menu_icon', 'dashicons-admin-generic'));
        if ($icon === '' || strpos($icon, 'dashicons-') !== 0) {
            $icon = 'dashicons-admin-generic';
        }
        return $icon;
    }


    public function filter_plugins_list_white_label($plugins) {
        if (!is_array($plugins)) {
            return $plugins;
        }
        $basename = plugin_basename(EEP_PLUGIN_FILE);
        if (!isset($plugins[$basename]) || !is_array($plugins[$basename])) {
            return $plugins;
        }
        $brand_name = $this->get_white_label_brand_name();
        if ($brand_name === '') {
            return $plugins;
        }
        $plugins[$basename]['AuthorName'] = (string) get_option('eep_white_label_plugin_author', '') !== '' ? (string) get_option('eep_white_label_plugin_author', '') : (string) ($plugins[$basename]['AuthorName'] ?? '');
        $plugins[$basename]['Name'] = $brand_name;
        $plugins[$basename]['Title'] = $brand_name;
        $custom_description = trim((string) get_option('eep_white_label_plugin_description', ''));
        if ($custom_description !== '') {
            $plugins[$basename]['Description'] = $custom_description;
        }
        $custom_author = trim((string) get_option('eep_white_label_plugin_author', ''));
        if ($custom_author !== '') {
            $plugins[$basename]['Author'] = esc_html($custom_author);
            $plugins[$basename]['AuthorName'] = $custom_author;
        }
        $custom_url = trim((string) get_option('eep_white_label_plugin_url', ''));
        if ($custom_url !== '') {
            $plugins[$basename]['PluginURI'] = esc_url_raw($custom_url);
        }
        $description = (string) ($plugins[$basename]['Description'] ?? '');
        if ($description !== '') {
            $plugins[$basename]['Description'] = str_replace('nexdirectory', $brand_name, $description);
        }
        return $plugins;
    }


    public function filter_plugin_row_meta_white_label($meta, $plugin_file) {
        if (!is_array($meta)) {
            $meta = [];
        }
        if ((string) $plugin_file !== plugin_basename(EEP_PLUGIN_FILE)) {
            return $meta;
        }
        if ((string) get_option('eep_white_label_enabled', '0') !== '1') {
            return $meta;
        }

        $support_url = esc_url((string) get_option('eep_white_label_support_url', ''));
        $support_email = sanitize_email((string) get_option('eep_white_label_support_email', ''));

        if ($support_url !== '') {
            $meta[] = sprintf(
                '<a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>',
                esc_url($support_url),
                esc_html__('Support', 'nexdirectory')
            );
        }
        if ($support_email !== '' && is_email($support_email)) {
            $meta[] = sprintf(
                '<a href="mailto:%1$s">%2$s</a>',
                esc_attr($support_email),
                esc_html__('Contact', 'nexdirectory')
            );
        }

        return array_values(array_unique($meta));
    }


    public function filter_admin_footer_text($text) {
        if (!is_admin()) {
            return $text;
        }
        if ((string) get_option('eep_white_label_enabled', '0') !== '1') {
            return $text;
        }
        $screen = function_exists('get_current_screen') ? get_current_screen() : null;
        $screen_id = is_object($screen) && isset($screen->id) ? (string) $screen->id : '';
        if ($screen_id !== '' && strpos($screen_id, 'eep-') === false && strpos($screen_id, self::POST_TYPE) === false) {
            return $text;
        }
        $custom_footer = trim((string) get_option('eep_white_label_admin_footer_text', ''));
        if ($custom_footer === '') {
            return $text;
        }
        return esc_html($custom_footer);
    }


    private function get_existing_white_label_option_value($fallback = '') {
        $filter = (string) current_filter();
        if (strpos($filter, 'sanitize_option_') === 0) {
            $option_name = substr($filter, strlen('sanitize_option_'));
            if (is_string($option_name) && strpos($option_name, 'eep_white_label_') === 0) {
                return (string) get_option($option_name, $fallback);
            }
        }
        return (string) $fallback;
    }


    private function is_white_label_lock_enabled_for_request() {
        static $lock_state = null;
        if ($lock_state === null) {
            $lock_state = ((string) get_option('eep_white_label_lock_enabled', '0') === '1');
        }
        return (bool) $lock_state;
    }


    private function get_white_label_unlock_token_from_request() {
        $post_token = isset($_POST['eep_white_label_unlock_token']) ? sanitize_text_field((string) wp_unslash($_POST['eep_white_label_unlock_token'])) : '';
        if ($post_token !== '') {
            return $post_token;
        }
        return isset($_GET['eep_wl_unlock']) ? sanitize_text_field((string) wp_unslash($_GET['eep_wl_unlock'])) : '';
    }


    private function can_edit_white_label_settings_from_request($user_id = 0) {
        $user_id = absint((int) $user_id);
        if ($user_id <= 0) {
            $user_id = get_current_user_id();
        }
        if ($user_id <= 0) {
            return false;
        }
        if (!$this->is_white_label_lock_enabled_for_request()) {
            return true;
        }
        $hash = trim((string) get_option('eep_white_label_password_hash', ''));
        if ($hash === '') {
            return true;
        }
        $token = trim((string) $this->get_white_label_unlock_token_from_request());
        if ($token === '') {
            return false;
        }
        $stored_token = trim((string) get_user_meta($user_id, 'eep_white_label_unlock_token', true));
        $expires = (int) get_user_meta($user_id, 'eep_white_label_unlock_until', true);
        if ($stored_token === '' || $expires < time()) {
            return false;
        }
        return hash_equals($stored_token, $token);
    }


    private function is_white_label_section_unlocked($user_id = 0) {
        return $this->can_edit_white_label_settings_from_request($user_id);
    }

    private function get_white_label_master_reset_token() {
        return (string) apply_filters('eep_white_label_master_reset_token', 'eep-wl-master-reset-2026');
    }

    private function get_white_label_force_reset_url($user_id = 0) {
        $user_id = absint((int) $user_id);
        if ($user_id <= 0) {
            $user_id = get_current_user_id();
        }
        if ($user_id <= 0 || !current_user_can('manage_options')) {
            return '';
        }
        $url = eep_add_query_arg(
            [
                'action' => 'eep_white_label_force_reset',
                'eep_wl_master' => $this->get_white_label_master_reset_token(),
            ],
            admin_url('admin-post.php')
        );
        return $url;
    }


    public function handle_white_label_unlock() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (!isset($_POST['eep_white_label_unlock_nonce']) || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_white_label_unlock_nonce'])), 'eep_white_label_unlock')) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }
        $password = (string) wp_unslash($_POST['eep_white_label_unlock_password'] ?? '');
        $stored_hash = (string) get_option('eep_white_label_password_hash', '');
        if ($password === '' || $stored_hash === '' || !wp_check_password($password, $stored_hash)) {
            $this->redirect_with_message(
                admin_url('admin.php?page=eep-settings#eep-tab-advanced'),
                __('Incorrect white label password.', 'nexdirectory'),
                'error'
            );
        }
        $unlock_token = wp_generate_password(26, false, false);
        $user_id = get_current_user_id();
        update_user_meta($user_id, 'eep_white_label_unlock_token', $unlock_token);
        update_user_meta($user_id, 'eep_white_label_unlock_until', (string) (time() + (20 * MINUTE_IN_SECONDS)));
        $unlock_url = eep_add_query_arg('eep_wl_unlock', rawurlencode($unlock_token), admin_url('admin.php?page=eep-settings')) . '#eep-tab-advanced';
        $this->redirect_with_message(
            $unlock_url,
            __('White label section unlocked. Save your changes to keep them.', 'nexdirectory'),
            'success'
        );
    }


    public function handle_white_label_lock() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (!isset($_POST['eep_white_label_lock_nonce']) || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_white_label_lock_nonce'])), 'eep_white_label_lock')) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }
        $this->reset_white_label_unlock_tokens();
        $this->redirect_with_message(
            admin_url('admin.php?page=eep-settings#eep-tab-advanced'),
            __('White label section locked.', 'nexdirectory'),
            'success'
        );
    }


    public function handle_white_label_reset_defaults() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (
            !isset($_POST['eep_white_label_reset_defaults_nonce'])
            || !wp_verify_nonce(sanitize_text_field((string) wp_unslash($_POST['eep_white_label_reset_defaults_nonce'])), 'eep_white_label_reset_defaults')
        ) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }
        if (!$this->can_edit_white_label_settings_from_request()) {
            $this->redirect_with_message(
                admin_url('admin.php?page=eep-settings#eep-tab-advanced'),
                __('Unlock the White Label tab before resetting defaults.', 'nexdirectory'),
                'error'
            );
        }
        $defaults = [
            'eep_white_label_enabled' => '0',
            'eep_white_label_plugin_name' => '',
            'eep_white_label_plugin_description' => '',
            'eep_white_label_plugin_author' => '',
            'eep_white_label_plugin_url' => '',
            'eep_white_label_support_url' => '',
            'eep_white_label_support_email' => '',
            'eep_white_label_admin_menu_icon' => 'dashicons-admin-generic',
            'eep_white_label_admin_footer_text' => '',
            'eep_white_label_lock_enabled' => '0',
            'eep_white_label_password_hash' => '',
        ];
        foreach ($defaults as $key => $value) {
            update_option($key, $value, false);
        }
        $this->reset_white_label_unlock_tokens();
        $this->redirect_with_message(
            admin_url('admin.php?page=eep-settings#eep-tab-advanced'),
            __('White label settings reset to defaults.', 'nexdirectory'),
            'success'
        );
    }


    public function handle_white_label_force_reset() {
        $master_token = isset($_REQUEST['eep_wl_master']) ? sanitize_text_field((string) wp_unslash($_REQUEST['eep_wl_master'])) : '';
        $master_valid = false;
        if ($master_token !== '') {
            $expected_master = $this->get_white_label_master_reset_token();
            $master_valid = ($expected_master !== '' && hash_equals($expected_master, $master_token));
        }

        if (!$master_valid) {
            if (!current_user_can('manage_options')) {
                wp_die(__('Not allowed.', 'nexdirectory'));
            }
            $nonce = '';
            if (isset($_REQUEST['eep_wl_nonce'])) {
                $nonce = sanitize_text_field((string) wp_unslash($_REQUEST['eep_wl_nonce']));
            } elseif (isset($_REQUEST['eep_white_label_force_reset_nonce'])) {
                $nonce = sanitize_text_field((string) wp_unslash($_REQUEST['eep_white_label_force_reset_nonce']));
            }
            if ($nonce === '' || !wp_verify_nonce($nonce, 'eep_white_label_force_reset')) {
                wp_die(__('Invalid request.', 'nexdirectory'));
            }
        }

        update_option('eep_white_label_lock_enabled', '0', false);
        update_option('eep_white_label_password_hash', '', false);
        $this->reset_white_label_unlock_tokens();

        $this->redirect_with_message(
            admin_url('admin.php?page=eep-settings#eep-tab-advanced'),
            __('White label lock and password were cleared for this admin account.', 'nexdirectory'),
            'success'
        );
    }


    public function handle_reset_smooth_scroll_defaults() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (
            !isset($_POST['eep_reset_smooth_scroll_defaults_nonce'])
            || !wp_verify_nonce(sanitize_text_field((string) wp_unslash($_POST['eep_reset_smooth_scroll_defaults_nonce'])), 'eep_reset_smooth_scroll_defaults')
        ) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }

        $defaults = [
            'eep_enable_smooth_scrolling' => '1',
            'eep_smooth_scroll_profile' => 'balanced',
            'eep_smooth_scroll_touchpad_behavior' => 'native',
            'eep_smooth_scroll_wheel_multiplier' => '1',
            'eep_smooth_scroll_ease' => '1.2',
            'eep_smooth_scroll_max_step_px' => 960,
            'eep_smooth_scroll_min_step_px' => '0.16',
            'eep_smooth_scroll_enable_on_touch' => '0',
        ];
        foreach ($defaults as $option_key => $option_value) {
            update_option((string) $option_key, $option_value, false);
        }

        $this->redirect_with_message(
            admin_url('admin.php?page=eep-settings#eep-tab-advanced--display'),
            __('Smooth scrolling settings reset to Lenis defaults.', 'nexdirectory'),
            'success'
        );
    }


    private function reset_white_label_unlock_tokens() {
        global $wpdb;
        if (!($wpdb instanceof wpdb) || empty($wpdb->usermeta)) {
            return;
        }
        $wpdb->delete($wpdb->usermeta, ['meta_key' => 'eep_white_label_unlocked_until'], ['%s']);
        $wpdb->delete($wpdb->usermeta, ['meta_key' => 'eep_white_label_unlock_token'], ['%s']);
        $wpdb->delete($wpdb->usermeta, ['meta_key' => 'eep_white_label_unlock_until'], ['%s']);
    }


    public function sanitize_multi_image_urls_option($value) {
        $raw = (string) $value;
        $rows = preg_split('/\r\n|\r|\n|,/', $raw);
        if (!is_array($rows)) {
            return '';
        }
        $urls = [];
        foreach ($rows as $row) {
            $url = esc_url_raw(trim((string) $row));
            if ($url === '') {
                continue;
            }
            $urls[] = $url;
        }
        $urls = array_values(array_unique($urls));
        return implode("\n", $urls);
    }


    public function sanitize_autosave_interval($value) {
        $v = absint($value);
        if ($v < 15) {
            $v = 15;
        }
        if ($v > 600) {
            $v = 600;
        }
        return $v;
    }


    public function sanitize_color_option($value) {
        $color = sanitize_hex_color((string) $value);
        return $color ?: '#FF5E14';
    }


    public function sanitize_font_family_option($value) {
        $value = preg_replace('/[^A-Za-z0-9,\-_\s\'"]+/', '', (string) $value);
        return trim((string) $value);
    }


    public function sanitize_size_option($value) {
        $value = strtolower(trim((string) $value));
        if (preg_match('/^(\d+(?:\.\d+)?)(px|rem|em)$/', $value, $matches)) {
            return (string) $matches[1] . (string) $matches[2];
        }
        if (is_numeric($value)) {
            return rtrim((string) $value, '.') . 'px';
        }
        return '18px';
    }


    public function sanitize_sticky_nav_logo_size_option($value) {
        $raw = strtolower(trim((string) $value));
        if ($raw === '') {
            return '66px';
        }
        if (preg_match('/^(\d+(?:\.\d+)?)(px|rem|em)?$/', $raw, $matches)) {
            $amount = (float) $matches[1];
            if ($amount < 18) {
                $amount = 18;
            }
            if ($amount > 96) {
                $amount = 96;
            }
            $unit = (isset($matches[2]) && $matches[2] !== '') ? (string) $matches[2] : 'px';
            $normalized = rtrim(rtrim(number_format($amount, 2, '.', ''), '0'), '.');
            return $normalized . $unit;
        }
        return '66px';
    }


    public function sanitize_font_weight_option($value) {
        $value = strtolower(trim((string) $value));
        if (preg_match('/^[1-9]00$/', $value)) {
            return $value;
        }
        return in_array($value, ['normal', 'bold', 'bolder', 'lighter'], true) ? $value : '400';
    }


    public function sanitize_spacing_scale_option($value) {
        $value = str_replace(',', '.', trim((string) $value));
        if (!is_numeric($value)) {
            return '1';
        }
        $float = (float) $value;
        if ($float < 0.6) {
            $float = 0.6;
        }
        if ($float > 2) {
            $float = 2;
        }
        if (abs($float - (float) ((int) $float)) < 0.000001) {
            return (string) ((int) $float);
        }
        $normalized = rtrim(rtrim(sprintf('%.6F', $float), '0'), '.');
        return $normalized !== '' ? $normalized : '1';
    }

    public function sanitize_style_box_style_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['default', 'gradient', 'bold', 'neumorphic'], true) ? $value : 'default';
    }

    public function sanitize_style_button_style_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['solid', 'outline', 'soft', 'dark'], true) ? $value : 'solid';
    }

    public function sanitize_style_button_radius_mode_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['inherit', 'pill', 'sharp'], true) ? $value : 'inherit';
    }

    public function sanitize_style_density_mode_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['compact', 'comfortable', 'loose'], true) ? $value : 'comfortable';
    }

    public function sanitize_style_border_mode_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['minimal', 'subtle', 'strong'], true) ? $value : 'subtle';
    }

    public function sanitize_style_shadow_mode_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['none', 'soft', 'medium', 'dramatic'], true) ? $value : 'soft';
    }

    public function sanitize_style_content_width_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['narrow', 'standard', 'wide', 'full'], true) ? $value : 'standard';
    }

    public function sanitize_style_input_style_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['outline', 'filled', 'underlined'], true) ? $value : 'outline';
    }


    public function sanitize_map_layout_option($value) {
        $value = sanitize_key((string) $value);
        if ($value === 'below') {
            $value = 'below-list';
        } elseif ($value === 'sidebar') {
            $value = 'three-column';
        }
        $allowed = ['three-column', 'below-list', 'below-grid', 'below-grid-large', 'grid-no-map', 'grid-no-map-large'];
        return in_array($value, $allowed, true) ? $value : 'three-column';
    }

    public function sanitize_map_view_template_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['default', 'triple'], true) ? $value : 'default';
    }

    private function get_map_focus_region_options() {
        return [
            'global' => __('Global (No Restriction)', 'nexdirectory'),
            'uk' => __('United Kingdom', 'nexdirectory'),
            'europe' => __('Europe', 'nexdirectory'),
            'america' => __('America', 'nexdirectory'),
            'north-america' => __('North America', 'nexdirectory'),
            'americas' => __('Americas (North + South)', 'nexdirectory'),
            'south-america' => __('South America', 'nexdirectory'),
            'africa' => __('Africa', 'nexdirectory'),
            'middle-east' => __('Middle East', 'nexdirectory'),
            'asia' => __('Asia', 'nexdirectory'),
            'oceania' => __('Oceania', 'nexdirectory'),
        ];
    }

    public function sanitize_map_focus_region_option($value) {
        $value = sanitize_key((string) $value);
        $allowed = array_keys((array) $this->get_map_focus_region_options());
        return in_array($value, $allowed, true) ? $value : 'global';
    }


    public function sanitize_map_density_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['comfortable', 'compact'], true) ? $value : 'comfortable';
    }


    public function sanitize_map_mobile_filter_mode_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['drawer', 'inline'], true) ? $value : 'drawer';
    }


    public function sanitize_page_side_padding_option($value) {
        $value = strtolower(trim((string) $value));
        if ($value === '') {
            return '10%';
        }

        if (is_numeric($value)) {
            $value .= '%';
        }

        if (!preg_match('/^(\d+(?:\.\d+)?)%$/', $value, $matches)) {
            return '10%';
        }

        $padding = (float) ($matches[1] ?? 10);
        if ($padding < 0) {
            $padding = 0;
        } elseif ($padding > 15) {
            $padding = 15;
        }

        if (abs($padding - (float) ((int) $padding)) < 0.000001) {
            $normalized = (string) ((int) $padding);
        } else {
            $normalized = rtrim(rtrim(sprintf('%.6F', $padding), '0'), '.');
        }
        if ($normalized === '') {
            $normalized = '0';
        }

        return $normalized . '%';
    }


    public function sanitize_page_side_padding_mobile_option($value) {
        $value = strtolower(trim((string) $value));
        if ($value === '') {
            // Empty means "inherit desktop side padding".
            return '';
        }
        return $this->sanitize_page_side_padding_option($value);
    }

    public function sanitize_nav_side_padding_desktop_option($value) {
        $value = strtolower(trim((string) $value));
        if ($value === '') {
            // Empty means "inherit desktop page padding".
            return '';
        }
        return $this->sanitize_page_side_padding_option($value);
    }

    public function sanitize_smooth_scroll_profile_option($value) {
        $value = sanitize_key((string) $value);
        $allowed = ['gentle', 'balanced', 'snappy', 'custom'];
        return in_array($value, $allowed, true) ? $value : 'balanced';
    }

    public function sanitize_smooth_scroll_touchpad_behavior_option($value) {
        $value = sanitize_key((string) $value);
        $allowed = ['native', 'assist', 'force'];
        return in_array($value, $allowed, true) ? $value : 'native';
    }

    public function sanitize_smooth_scroll_wheel_multiplier_option($value) {
        $value = str_replace(',', '.', trim((string) $value));
        if (!is_numeric($value)) {
            return '1';
        }
        $normalized = (float) $value;
        if ($normalized < 0.4) {
            $normalized = 0.4;
        } elseif ($normalized > 3) {
            $normalized = 3;
        }
        return rtrim(rtrim(number_format($normalized, 2, '.', ''), '0'), '.');
    }

    public function sanitize_smooth_scroll_ease_option($value) {
        $value = str_replace(',', '.', trim((string) $value));
        if (!is_numeric($value)) {
            return '1.2';
        }
        $normalized = (float) $value;
        if ($normalized < 0.4) {
            $normalized = 0.4;
        } elseif ($normalized > 3) {
            $normalized = 3;
        }
        return rtrim(rtrim(number_format($normalized, 3, '.', ''), '0'), '.');
    }

    public function sanitize_smooth_scroll_max_step_option($value) {
        $normalized = absint((int) $value);
        if ($normalized < 180) {
            $normalized = 180;
        } elseif ($normalized > 2400) {
            $normalized = 2400;
        }
        return $normalized;
    }

    public function sanitize_smooth_scroll_min_step_option($value) {
        $value = str_replace(',', '.', trim((string) $value));
        if (!is_numeric($value)) {
            return '0.16';
        }
        $normalized = (float) $value;
        if ($normalized < 0.02) {
            $normalized = 0.02;
        } elseif ($normalized > 2) {
            $normalized = 2;
        }
        return rtrim(rtrim(number_format($normalized, 3, '.', ''), '0'), '.');
    }

    private function get_default_preloader_svg_markup() {
        return <<<'SVG'
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 200" width="100%" height="100%">
    <defs>
        <style>
            text {
                font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
                font-weight: 900;
                font-size: 85px;
                letter-spacing: -1.5px;
                -webkit-font-smoothing: antialiased;
                -moz-osx-font-smoothing: grayscale;
            }
        </style>
        <clipPath id="revealMask">
            <rect x="90" y="20" height="160" width="0" rx="10">
                <animate attributeName="width"
                         values="0; 0; 600; 600; 0; 0"
                         keyTimes="0; 0.1; 0.45; 0.55; 0.9; 1"
                         calcMode="spline"
                         keySplines="0.4 0 0.2 1; 0.4 0 0.2 1; 0.4 0 0.2 1; 0.4 0 0.2 1; 0.4 0 0.2 1"
                         dur="3s" repeatCount="indefinite" />
            </rect>
        </clipPath>
    </defs>
    <rect width="100%" height="100%" fill="#FFFFFF" />
    <text x="120" y="130"
          textLength="530"
          lengthAdjust="spacing"
          fill="#F3F4F6">NexDirectory</text>
    <text x="120" y="130"
          textLength="530"
          lengthAdjust="spacing"
          fill="#0A0A0A"
          clip-path="url(#revealMask)">NexDirectory</text>
    <circle cy="120" cx="90" r="14" fill="#C3FF29" opacity="0.5">
        <animate attributeName="cx"
                 values="90; 90; 675; 675; 90; 90"
                 keyTimes="0; 0.1; 0.45; 0.55; 0.9; 1"
                 calcMode="spline"
                 keySplines="0.4 0 0.2 1; 0.4 0 0.2 1; 0.4 0 0.2 1; 0.4 0 0.2 1; 0.4 0 0.2 1"
                 dur="3s" repeatCount="indefinite" />
        <animate attributeName="r"
                 values="14; 28; 14"
                 keyTimes="0; 0.5; 1"
                 dur="1s" repeatCount="indefinite" />
        <animate attributeName="opacity"
                 values="0.5; 0; 0.5"
                 keyTimes="0; 0.5; 1"
                 dur="1s" repeatCount="indefinite" />
    </circle>
    <circle cy="120" cx="90" r="14" fill="#C3FF29">
        <animate attributeName="cx"
                 values="90; 90; 675; 675; 90; 90"
                 keyTimes="0; 0.1; 0.45; 0.55; 0.9; 1"
                 calcMode="spline"
                 keySplines="0.4 0 0.2 1; 0.4 0 0.2 1; 0.4 0 0.2 1; 0.4 0 0.2 1; 0.4 0 0.2 1"
                 dur="3s" repeatCount="indefinite" />
    </circle>
</svg>
SVG;
    }

    public function sanitize_preloader_source_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['svg', 'image'], true) ? $value : 'svg';
    }

    public function sanitize_preloader_svg_option($value) {
        $markup = trim((string) $value);
        if ($markup === '') {
            return $this->get_default_preloader_svg_markup();
        }

        $allowed = [
            'svg' => [
                'xmlns' => true,
                'viewbox' => true,
                'viewBox' => true,
                'width' => true,
                'height' => true,
                'fill' => true,
                'stroke' => true,
                'role' => true,
                'aria-hidden' => true,
                'preserveaspectratio' => true,
                'preserveAspectRatio' => true,
                'class' => true,
            ],
            'defs' => [],
            'style' => [],
            'clippath' => [
                'id' => true,
            ],
            'clipPath' => [
                'id' => true,
            ],
            'rect' => [
                'x' => true,
                'y' => true,
                'width' => true,
                'height' => true,
                'rx' => true,
                'fill' => true,
                'opacity' => true,
            ],
            'text' => [
                'x' => true,
                'y' => true,
                'textlength' => true,
                'textLength' => true,
                'lengthadjust' => true,
                'lengthAdjust' => true,
                'fill' => true,
                'clip-path' => true,
            ],
            'circle' => [
                'cx' => true,
                'cy' => true,
                'r' => true,
                'fill' => true,
                'opacity' => true,
            ],
            'animate' => [
                'attributename' => true,
                'attributeName' => true,
                'values' => true,
                'keytimes' => true,
                'keyTimes' => true,
                'calcmode' => true,
                'calcMode' => true,
                'keysplines' => true,
                'keySplines' => true,
                'dur' => true,
                'repeatcount' => true,
                'repeatCount' => true,
            ],
        ];

        $sanitized = wp_kses($markup, $allowed);
        if (trim($sanitized) === '') {
            return $this->get_default_preloader_svg_markup();
        }
        return $sanitized;
    }

    public function sanitize_preloader_background_color_option($value) {
        $color = sanitize_hex_color((string) $value);
        return is_string($color) && $color !== '' ? $color : '#FFFFFF';
    }

    public function sanitize_preloader_logo_max_width_option($value) {
        $size = absint((int) $value);
        if ($size < 120) {
            $size = 120;
        } elseif ($size > 900) {
            $size = 900;
        }
        return $size;
    }

    public function sanitize_preloader_min_duration_option($value) {
        $duration = absint((int) $value);
        if ($duration > 8000) {
            $duration = 8000;
        }
        return $duration;
    }

    public function sanitize_preloader_fade_duration_option($value) {
        $duration = absint((int) $value);
        if ($duration < 80) {
            $duration = 80;
        } elseif ($duration > 2000) {
            $duration = 2000;
        }
        return $duration;
    }


    public function sanitize_map_provider_option($value) {
        $value = sanitize_key((string) $value);
        $allowed = ['openstreetmap', 'mapbox', 'google'];
        return in_array($value, $allowed, true) ? $value : 'openstreetmap';
    }

    private function get_mapbox_style_id_options() {
        return [
            'mapbox/streets-v12' => __('Streets v12', 'nexdirectory'),
            'mapbox/outdoors-v12' => __('Outdoors v12', 'nexdirectory'),
            'mapbox/satellite-streets-v12' => __('Satellite Streets v12', 'nexdirectory'),
            'mapbox/light-v11' => __('Light v11', 'nexdirectory'),
            'mapbox/dark-v11' => __('Dark v11', 'nexdirectory'),
            'mapbox/navigation-day-v1' => __('Navigation Day v1', 'nexdirectory'),
            'mapbox/navigation-night-v1' => __('Navigation Night v1', 'nexdirectory'),
        ];
    }

    public function sanitize_mapbox_style_id_option($value) {
        $value = sanitize_text_field((string) $value);
        $allowed = array_keys((array) $this->get_mapbox_style_id_options());
        if (in_array($value, $allowed, true)) {
            return $value;
        }
        return 'mapbox/streets-v12';
    }


    public function sanitize_map_style_option($value) {
        $value = sanitize_key((string) $value);
        $allowed = [
            'osm-standard',
            'osm-hot',
            'carto-light',
            'carto-dark',
            'topo',
            'mapbox-streets',
            'mapbox-outdoors',
            'mapbox-satellite',
            'google-roadmap',
            'google-satellite',
            'custom',
        ];
        return in_array($value, $allowed, true) ? $value : 'osm-standard';
    }


    public function sanitize_recaptcha_version_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['v3', 'v2'], true) ? $value : 'v3';
    }


    public function sanitize_chatbot_embedding_model_option($value) {
        $value = sanitize_text_field((string) $value);
        return in_array($value, ['text-embedding-3-small', 'text-embedding-3-large'], true) ? $value : 'text-embedding-3-small';
    }


    public function sanitize_chatbot_embedding_dimensions_option($value) {
        $dimensions = absint((int) $value);
        if ($dimensions < 128) {
            $dimensions = 128;
        }
        if ($dimensions > 3072) {
            $dimensions = 3072;
        }
        return $dimensions;
    }


    public function sanitize_chatbot_index_post_types_option($value) {
        $candidates = [];
        if (is_array($value)) {
            $candidates = $value;
        } elseif (is_string($value)) {
            $decoded = json_decode($value, true);
            if (is_array($decoded)) {
                $candidates = $decoded;
            } else {
                $candidates = explode(',', $value);
            }
        }

        $available = method_exists($this, 'get_chatbot_available_post_types')
            ? array_keys((array) $this->get_chatbot_available_post_types())
            : [self::POST_TYPE];

        $selected = [];
        foreach ((array) $candidates as $candidate) {
            $slug = sanitize_key((string) $candidate);
            if ($slug === '' || !in_array($slug, $available, true)) {
                continue;
            }
            $selected[] = $slug;
        }
        $selected = array_values(array_unique($selected));
        if (empty($selected)) {
            if (method_exists($this, 'chatbot_default_source_post_types')) {
                $selected = (array) $this->chatbot_default_source_post_types($available);
            }
            if (empty($selected) && !empty($available)) {
                $selected = [(string) reset($available)];
            }
        }
        $previous_raw = get_option('eep_chatbot_index_post_types', '');
        $previous_candidates = [];
        if (is_array($previous_raw)) {
            $previous_candidates = $previous_raw;
        } elseif (is_string($previous_raw) && trim($previous_raw) !== '') {
            $previous_decoded = json_decode($previous_raw, true);
            if (is_array($previous_decoded)) {
                $previous_candidates = $previous_decoded;
            } else {
                $previous_candidates = explode(',', $previous_raw);
            }
        }
        $previous_selected = [];
        foreach ((array) $previous_candidates as $candidate) {
            $slug = sanitize_key((string) $candidate);
            if ($slug === '' || !in_array($slug, $available, true)) {
                continue;
            }
            $previous_selected[] = $slug;
        }
        $previous_selected = array_values(array_unique($previous_selected));
        sort($previous_selected);
        $compare_selected = $selected;
        sort($compare_selected);
        if ($previous_selected !== $compare_selected) {
            update_option('eep_chatbot_knowledge_catalog_stale', '1', false);
        }
        return wp_json_encode($selected);
    }

    private function get_settings_email_health() {
        $smtp_enabled = (string) get_option('eep_smtp_enabled', '0') === '1';
        $smtp_host = trim((string) get_option('eep_smtp_host', ''));
        $smtp_from_email = sanitize_email((string) get_option('eep_smtp_from_email', ''));

        if (!$smtp_enabled) {
            return [
                'connected' => false,
                'summary' => __('SMTP is disabled. Enable SMTP and add provider credentials to connect email delivery.', 'nexdirectory'),
            ];
        }
        if ($smtp_host === '') {
            return [
                'connected' => false,
                'summary' => __('SMTP is enabled but host is missing.', 'nexdirectory'),
            ];
        }
        if ($smtp_from_email !== '' && !is_email($smtp_from_email)) {
            return [
                'connected' => false,
                'summary' => __('SMTP From Email is invalid.', 'nexdirectory'),
            ];
        }

        return [
            'connected' => true,
            'summary' => sprintf(__('SMTP is connected to %s.', 'nexdirectory'), $smtp_host),
        ];
    }

    private function get_settings_api_health($premium_unlocked = true) {
        if (!$premium_unlocked) {
            return [
                'connected' => false,
                'summary' => __('Premium is not active, so the OpenAI API integration is unavailable.', 'nexdirectory'),
            ];
        }

        $api_key = trim((string) get_option('eep_chatbot_openai_api_key', ''));
        $model = trim((string) get_option('eep_chatbot_model', 'gpt-5.2'));
        if ($model === '') {
            $model = 'gpt-5.2';
        }

        if ($api_key === '') {
            return [
                'connected' => false,
                'summary' => __('OpenAI API key is missing.', 'nexdirectory'),
            ];
        }

        return [
            'connected' => true,
            'summary' => sprintf(__('OpenAI API key is configured (model: %s).', 'nexdirectory'), $model),
        ];
    }

    private function get_settings_map_health() {
        $provider = sanitize_key((string) get_option('eep_map_provider', 'openstreetmap'));
        if (!in_array($provider, ['openstreetmap', 'mapbox', 'google'], true)) {
            $provider = 'openstreetmap';
        }

        $style_mode = sanitize_key((string) get_option('eep_map_style', 'osm-standard'));
        $provider_label = [
            'openstreetmap' => __('OpenStreetMap', 'nexdirectory'),
            'mapbox' => __('Mapbox', 'nexdirectory'),
            'google' => __('Google Maps', 'nexdirectory'),
        ];

        if ($provider === 'mapbox') {
            $token = trim((string) get_option('eep_mapbox_access_token', ''));
            if ($token === '') {
                return [
                    'connected' => false,
                    'summary' => __('Mapbox is selected but access token is missing.', 'nexdirectory'),
                ];
            }
        } elseif ($provider === 'google') {
            $google_key = trim((string) get_option('eep_google_maps_api_key', ''));
            if ($google_key === '') {
                return [
                    'connected' => false,
                    'summary' => __('Google Maps is selected but API key is missing.', 'nexdirectory'),
                ];
            }
        }

        if ($style_mode === 'custom') {
            $custom_tile_url = trim((string) get_option('eep_map_custom_tile_url', ''));
            if ($custom_tile_url === '') {
                return [
                    'connected' => false,
                    'summary' => __('Custom tile mode is selected but tile URL template is missing.', 'nexdirectory'),
                ];
            }
        }

        $active_provider_label = (string) ($provider_label[$provider] ?? __('Map provider', 'nexdirectory'));
        return [
            'connected' => true,
            'summary' => sprintf(__('%s provider is configured.', 'nexdirectory'), $active_provider_label),
        ];
    }

    private function get_settings_captcha_health() {
        $site_key = trim((string) get_option('eep_recaptcha_site_key', ''));
        $secret_key = trim((string) get_option('eep_recaptcha_secret_key', ''));
        $version = sanitize_key((string) get_option('eep_recaptcha_version', 'v3'));
        if (!in_array($version, ['v3', 'v2'], true)) {
            $version = 'v3';
        }

        if ($site_key === '' || $secret_key === '') {
            return [
                'connected' => false,
                'summary' => __('reCAPTCHA site key or secret key is missing.', 'nexdirectory'),
            ];
        }

        return [
            'connected' => true,
            'summary' => sprintf(__('reCAPTCHA %s keys are configured.', 'nexdirectory'), strtoupper($version)),
        ];
    }

    private function get_settings_route_targets($site_profile_key = '') {
        $profile_key = sanitize_key((string) $site_profile_key);
        if ($profile_key === '' && method_exists($this, 'get_site_profile_key')) {
            $profile_key = sanitize_key((string) $this->get_site_profile_key());
        }
        if ($profile_key === '') {
            $profile_key = 'events';
        }

        $build_route = function ($option_key, $route_key, $label) use ($profile_key) {
            $fallback = '';
            if (method_exists($this, 'get_profile_route_default_url')) {
                $fallback = esc_url_raw((string) $this->get_profile_route_default_url($route_key, $profile_key));
            }
            return [
                'option' => (string) $option_key,
                'label' => (string) $label,
                'fallback' => (string) $fallback,
            ];
        };

        return [
            $build_route('eep_page_events_url', 'events', __('Listings Page', 'nexdirectory')),
            $build_route('eep_page_events_map_url', 'map', __('Map Page', 'nexdirectory')),
            $build_route('eep_page_events_calendar_url', 'calendar', __('Calendar Page', 'nexdirectory')),
            $build_route('eep_page_submit_event_url', 'submit', __('Submit Listing Page', 'nexdirectory')),
            $build_route('eep_page_my_events_url', 'my_items', __('My Listings Page', 'nexdirectory')),
            $build_route('eep_page_boost_posts_url', 'boost', __('Boost Posts Page', 'nexdirectory')),
            $build_route('eep_page_owner_analytics_url', 'analytics', __('Analytics Page', 'nexdirectory')),
            $build_route('eep_page_my_tickets_url', 'attending', __('Saved/Attending Page', 'nexdirectory')),
            $build_route('eep_page_whos_attending_url', 'attendees', __('Who\'s Attending Page', 'nexdirectory')),
            [
                'option' => 'eep_page_event_webapp_url',
                'label' => __('Event Web App Page', 'nexdirectory'),
                'fallback' => esc_url_raw((string) home_url('/event-app/')),
            ],
            [
                'option' => 'eep_page_whats_new_url',
                'label' => __('What\'s New Page', 'nexdirectory'),
                'fallback' => esc_url_raw((string) home_url('/whats-new/')),
            ],
            $build_route('eep_page_account_url', 'account', __('Account Page', 'nexdirectory')),
            $build_route('eep_page_login_signup_url', 'auth', __('Login/Signup Page', 'nexdirectory')),
            $build_route('eep_claim_listing_page_url', 'claim', __('Claim Listing Page', 'nexdirectory')),
        ];
    }

    private function get_settings_routing_health($site_profile_key = '') {
        $routes = $this->get_settings_route_targets($site_profile_key);
        $site_host = strtolower((string) wp_parse_url(home_url('/'), PHP_URL_HOST));
        $connected_count = 0;
        $issues = [];

        foreach ($routes as $route) {
            $option_key = sanitize_key((string) ($route['option'] ?? ''));
            if ($option_key === '') {
                continue;
            }
            $label = sanitize_text_field((string) ($route['label'] ?? $option_key));
            $raw_url = trim((string) get_option($option_key, ''));
            if ($raw_url === '') {
                $raw_url = trim((string) ($route['fallback'] ?? ''));
            }
            if ($raw_url === '') {
                $issues[] = sprintf(__('%s has no URL configured.', 'nexdirectory'), $label);
                continue;
            }
            if (strpos($raw_url, '/') === 0) {
                $raw_url = home_url($raw_url);
            }
            $url = esc_url_raw($raw_url);
            if ($url === '') {
                $issues[] = sprintf(__('%s URL is invalid.', 'nexdirectory'), $label);
                continue;
            }
            $path = trim((string) wp_parse_url($url, PHP_URL_PATH));
            if ($path === '' || $path === '/') {
                $issues[] = sprintf(__('%s points to the site root instead of a dedicated page.', 'nexdirectory'), $label);
                continue;
            }
            $route_host = strtolower((string) wp_parse_url($url, PHP_URL_HOST));
            if ($route_host !== '' && $site_host !== '' && $route_host !== $site_host) {
                $issues[] = sprintf(__('%s points to an external domain.', 'nexdirectory'), $label);
                continue;
            }

            $post_id = absint((int) url_to_postid($url));
            if ($post_id <= 0) {
                $issues[] = sprintf(__('%s is not linked to a WordPress page.', 'nexdirectory'), $label);
                continue;
            }
            $post_status = (string) get_post_status($post_id);
            if ($post_status === '' || in_array($post_status, ['trash', 'auto-draft'], true)) {
                $issues[] = sprintf(__('%s points to an unavailable page status.', 'nexdirectory'), $label);
                continue;
            }
            $connected_count++;
        }

        $total_count = count($routes);
        $is_connected = $total_count > 0 && $connected_count === $total_count;
        if ($is_connected) {
            $summary = sprintf(__('All %d frontend routes are connected to valid pages.', 'nexdirectory'), $total_count);
        } else {
            $summary = sprintf(
                __('%1$d of %2$d routes are connected. %3$s', 'nexdirectory'),
                $connected_count,
                $total_count,
                (string) ($issues[0] ?? __('Review routing URLs and generate missing pages if needed.', 'nexdirectory'))
            );
        }

        return [
            'connected' => $is_connected,
            'summary' => $summary,
            'connected_count' => $connected_count,
            'total_count' => $total_count,
            'issues' => $issues,
        ];
    }

    private function sync_route_options_to_existing_pages($profile_key = '') {
        if (!method_exists($this, 'get_profile_route_slug') || !method_exists($this, 'get_profile_route_slugs') || !method_exists($this, 'get_profile_route_default_url')) {
            return;
        }

        $profile_key = sanitize_key((string) $profile_key);
        if ($profile_key === '' && method_exists($this, 'get_site_profile_key')) {
            $profile_key = sanitize_key((string) $this->get_site_profile_key());
        }
        if ($profile_key === '') {
            $profile_key = 'events';
        }

        $route_map = [
            'eep_page_events_url' => 'events',
            'eep_page_events_map_url' => 'map',
            'eep_page_events_calendar_url' => 'calendar',
            'eep_page_submit_event_url' => 'submit',
            'eep_page_my_events_url' => 'my_items',
            'eep_page_boost_posts_url' => 'boost',
            'eep_page_owner_analytics_url' => 'analytics',
            'eep_page_my_tickets_url' => 'attending',
            'eep_page_whos_attending_url' => 'attendees',
            'eep_page_account_url' => 'account',
            'eep_page_login_signup_url' => 'auth',
            'eep_claim_listing_page_url' => 'claim',
        ];

        foreach ($route_map as $option_key => $route_key) {
            $current_url = esc_url_raw((string) get_option($option_key, ''));
            $is_current_valid = false;
            if ($current_url !== '') {
                $path = trim((string) wp_parse_url($current_url, PHP_URL_PATH));
                $is_root_url = ($path === '' || $path === '/');
                if (!$is_root_url) {
                    $is_current_valid = absint((int) url_to_postid($current_url)) > 0;
                }
            }

            if ($is_current_valid) {
                continue;
            }

            $default_slug = eep_sanitize_title((string) $this->get_profile_route_slug($route_key, $profile_key));
            $candidate_slugs = array_values(array_unique(array_filter(array_map('eep_sanitize_title',
                array_merge([$default_slug], (array) $this->get_profile_route_slugs($route_key, $profile_key))
            ))));
            $target_url = '';
            foreach ($candidate_slugs as $candidate_slug) {
                $page = get_page_by_path($candidate_slug);
                if ($page instanceof WP_Post) {
                    $target_url = esc_url_raw((string) get_permalink((int) $page->ID));
                    break;
                }
            }
            if ($target_url === '') {
                $shortcode_map = [
                    'events' => 'eep_listings_archive',
                    'map' => 'eep_listings_map',
                    'calendar' => 'eep_listings_calendar',
                    'submit' => 'eep_submit',
                    'my_items' => 'eep_my_listings',
                    'boost' => 'eep_boost_posts',
                    'analytics' => 'eep_owner_analytics',
                    'attending' => 'eep_saved_listings',
                    'attendees' => 'eep_whos_attending',
                    'account' => 'eep_account',
                    'auth' => 'eep_auth',
                    'claim' => 'eep_claim_listing',
                ];
                $shortcode_tag = sanitize_key((string) ($shortcode_map[$route_key] ?? ''));
                if ($shortcode_tag !== '') {
                    global $wpdb;
                    if ($wpdb instanceof wpdb) {
                        $like = '%' . $wpdb->esc_like('[' . $shortcode_tag) . '%';
                        $shortcode_page_id = (int) $wpdb->get_var($wpdb->prepare(
                            "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'page' AND post_status = 'publish' AND post_content LIKE %s ORDER BY ID ASC LIMIT 1",
                            $like
                        )); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
                        if ($shortcode_page_id > 0) {
                            $shortcode_url = get_permalink($shortcode_page_id);
                            if (is_string($shortcode_url) && $shortcode_url !== '') {
                                $target_url = esc_url_raw((string) $shortcode_url);
                            }
                        }
                    }
                }
            }
            if ($target_url === '') {
                $target_url = esc_url_raw((string) $this->get_profile_route_default_url($route_key, $profile_key));
            }
            if ($target_url !== '') {
                $target_path = trim((string) wp_parse_url($target_url, PHP_URL_PATH));
                if ($target_path === '' || $target_path === '/') {
                    $target_url = '';
                }
            }
            if ($target_url !== '') {
                update_option($option_key, $target_url, false);
            }
        }

        $event_webapp_url = esc_url_raw((string) get_option('eep_page_event_webapp_url', ''));
        $event_webapp_valid = false;
        if ($event_webapp_url !== '') {
            $path = trim((string) wp_parse_url($event_webapp_url, PHP_URL_PATH));
            $is_root_url = ($path === '' || $path === '/');
            if (!$is_root_url) {
                $event_webapp_valid = absint((int) url_to_postid($event_webapp_url)) > 0;
            }
        }
        if (!$event_webapp_valid) {
            $event_webapp_target = '';
            $event_webapp_page = get_page_by_path('event-app');
            if ($event_webapp_page instanceof WP_Post && (string) get_post_status((int) $event_webapp_page->ID) === 'publish') {
                $event_webapp_target = esc_url_raw((string) get_permalink((int) $event_webapp_page->ID));
            }
            if ($event_webapp_target === '') {
                global $wpdb;
                if ($wpdb instanceof wpdb) {
                    $like = '%' . $wpdb->esc_like('[eep_event_webapp') . '%';
                    $shortcode_page_id = (int) $wpdb->get_var($wpdb->prepare(
                        "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'page' AND post_status = 'publish' AND post_content LIKE %s ORDER BY ID ASC LIMIT 1",
                        $like
                    )); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
                    if ($shortcode_page_id > 0) {
                        $shortcode_url = get_permalink($shortcode_page_id);
                        if (is_string($shortcode_url) && $shortcode_url !== '') {
                            $event_webapp_target = esc_url_raw((string) $shortcode_url);
                        }
                    }
                }
            }
            if ($event_webapp_target === '') {
                $event_webapp_target = esc_url_raw((string) home_url('/event-app/'));
            }
            if ($event_webapp_target !== '') {
                update_option('eep_page_event_webapp_url', $event_webapp_target, false);
            }
        }

        $whats_new_page = get_page_by_path('whats-new');
        $whats_new_url = $whats_new_page instanceof WP_Post
            ? esc_url_raw((string) get_permalink((int) $whats_new_page->ID))
            : esc_url_raw(home_url('/whats-new/'));
        if ($whats_new_url !== '') {
            update_option('eep_page_whats_new_url', $whats_new_url, false);
        }
    }

    private function run_settings_map_connection_test() {
        $health = $this->get_settings_map_health();
        if (empty($health['connected'])) {
            return [
                'ok' => false,
                'message' => sanitize_text_field((string) ($health['summary'] ?? __('Map configuration is incomplete.', 'nexdirectory'))),
            ];
        }

        $provider = sanitize_key((string) get_option('eep_map_provider', 'openstreetmap'));
        if (!in_array($provider, ['openstreetmap', 'mapbox', 'google'], true)) {
            $provider = 'openstreetmap';
        }

        $headers = [
            'Accept' => 'application/json',
            'User-Agent' => 'NexDirectory/' . self::VERSION . ' (' . home_url('/') . ')',
        ];
        $provider_message = '';

        if ($provider === 'google') {
            $google_key = trim((string) get_option('eep_google_maps_api_key', ''));
            $google_url = eep_add_query_arg([
                'address' => 'London',
                'key' => $google_key,
            ], 'https://maps.googleapis.com/maps/api/geocode/json');
            $google_response = wp_remote_get($google_url, [
                'timeout' => 12,
                'headers' => $headers,
            ]);
            if (is_wp_error($google_response)) {
                return [
                    'ok' => false,
                    'message' => sprintf(__('Google Maps request failed: %s', 'nexdirectory'), $google_response->get_error_message()),
                ];
            }
            $payload = json_decode((string) wp_remote_retrieve_body($google_response), true);
            $status = sanitize_key((string) ($payload['status'] ?? ''));
            if (!in_array($status, ['ok', 'zero_results'], true)) {
                $error_message = sanitize_text_field((string) ($payload['error_message'] ?? $status));
                if ($error_message === '') {
                    $error_message = __('Unknown Google Maps error.', 'nexdirectory');
                }
                return [
                    'ok' => false,
                    'message' => sprintf(__('Google Maps test failed: %s', 'nexdirectory'), $error_message),
                ];
            }
            $provider_message = __('Google Maps API responded successfully.', 'nexdirectory');
        } elseif ($provider === 'mapbox') {
            $token = trim((string) get_option('eep_mapbox_access_token', ''));
            $style_id = $this->sanitize_mapbox_style_id_option((string) get_option('eep_mapbox_style_id', 'mapbox/streets-v12'));
            $style_segments = array_filter(array_map('trim', explode('/', $style_id)), static function ($segment) {
                return $segment !== '';
            });
            if (empty($style_segments)) {
                $style_segments = ['mapbox', 'streets-v12'];
            }
            $style_path = implode('/', array_map('rawurlencode', $style_segments));
            $style_url = eep_add_query_arg([
                'access_token' => $token,
            ], 'https://api.mapbox.com/styles/v1/' . $style_path);
            $mapbox_response = wp_remote_get($style_url, [
                'timeout' => 12,
                'headers' => $headers,
            ]);
            if (is_wp_error($mapbox_response)) {
                return [
                    'ok' => false,
                    'message' => sprintf(__('Mapbox request failed: %s', 'nexdirectory'), $mapbox_response->get_error_message()),
                ];
            }
            $status_code = (int) wp_remote_retrieve_response_code($mapbox_response);
            if ($status_code < 200 || $status_code >= 300) {
                $payload = json_decode((string) wp_remote_retrieve_body($mapbox_response), true);
                $error_message = sanitize_text_field((string) ($payload['message'] ?? ''));
                if ($error_message === '') {
                    $error_message = sprintf(__('HTTP %d', 'nexdirectory'), $status_code);
                }
                return [
                    'ok' => false,
                    'message' => sprintf(__('Mapbox test failed: %s', 'nexdirectory'), $error_message),
                ];
            }
            $provider_message = __('Mapbox API responded successfully.', 'nexdirectory');
        } else {
            $osm_url = eep_add_query_arg([
                'format' => 'json',
                'limit' => 1,
                'q' => 'London',
            ], 'https://nominatim.openstreetmap.org/search');
            $osm_response = wp_remote_get($osm_url, [
                'timeout' => 12,
                'headers' => $headers,
            ]);
            if (is_wp_error($osm_response)) {
                return [
                    'ok' => false,
                    'message' => sprintf(__('OpenStreetMap request failed: %s', 'nexdirectory'), $osm_response->get_error_message()),
                ];
            }
            $status_code = (int) wp_remote_retrieve_response_code($osm_response);
            if ($status_code < 200 || $status_code >= 300) {
                return [
                    'ok' => false,
                    'message' => sprintf(__('OpenStreetMap test failed with HTTP %d.', 'nexdirectory'), $status_code),
                ];
            }
            $payload = json_decode((string) wp_remote_retrieve_body($osm_response), true);
            if (!is_array($payload)) {
                return [
                    'ok' => false,
                    'message' => __('OpenStreetMap returned an unexpected response payload.', 'nexdirectory'),
                ];
            }
            $provider_message = __('OpenStreetMap endpoint responded successfully.', 'nexdirectory');
        }

        if (class_exists('WP_REST_Request')) {
            $rest_request = new WP_REST_Request('GET', '/eep/v1/map-events');
            $rest_request->set_query_params(['limit' => 1]);
            $rest_response = rest_do_request($rest_request);
            if ($rest_response instanceof WP_Error) {
                return [
                    'ok' => false,
                    'message' => sprintf(__('Map REST endpoint failed: %s', 'nexdirectory'), $rest_response->get_error_message()),
                ];
            }
            $rest_status = (int) $rest_response->get_status();
            if ($rest_status < 200 || $rest_status >= 300) {
                return [
                    'ok' => false,
                    'message' => sprintf(__('Map REST endpoint returned HTTP %d.', 'nexdirectory'), $rest_status),
                ];
            }
        }

        return [
            'ok' => true,
            'message' => sprintf(__('Map connection test passed. %s', 'nexdirectory'), $provider_message),
        ];
    }

    private function run_settings_captcha_connection_test() {
        $health = $this->get_settings_captcha_health();
        if (empty($health['connected'])) {
            return [
                'ok' => false,
                'message' => sanitize_text_field((string) ($health['summary'] ?? __('reCAPTCHA keys are incomplete.', 'nexdirectory'))),
            ];
        }

        $secret_key = trim((string) get_option('eep_recaptcha_secret_key', ''));
        $siteverify_response = wp_remote_post('https://www.google.com/recaptcha/api/siteverify', [
            'timeout' => 12,
            'body' => [
                'secret' => $secret_key,
                'response' => 'settings_connection_test_token',
                'remoteip' => sanitize_text_field((string) ($_SERVER['REMOTE_ADDR'] ?? '')),
            ],
        ]);
        if (is_wp_error($siteverify_response)) {
            return [
                'ok' => false,
                'message' => sprintf(__('reCAPTCHA test request failed: %s', 'nexdirectory'), $siteverify_response->get_error_message()),
            ];
        }

        $status_code = (int) wp_remote_retrieve_response_code($siteverify_response);
        if ($status_code < 200 || $status_code >= 300) {
            return [
                'ok' => false,
                'message' => sprintf(__('reCAPTCHA test failed with HTTP %d.', 'nexdirectory'), $status_code),
            ];
        }

        $payload = json_decode((string) wp_remote_retrieve_body($siteverify_response), true);
        if (!is_array($payload)) {
            return [
                'ok' => false,
                'message' => __('reCAPTCHA returned an unexpected response payload.', 'nexdirectory'),
            ];
        }

        if (!empty($payload['success'])) {
            return [
                'ok' => true,
                'message' => __('reCAPTCHA connection test passed.', 'nexdirectory'),
            ];
        }

        $error_codes = [];
        if (!empty($payload['error-codes']) && is_array($payload['error-codes'])) {
            foreach ((array) $payload['error-codes'] as $error_code) {
                $code = sanitize_key((string) $error_code);
                if ($code !== '') {
                    $error_codes[] = $code;
                }
            }
        }

        if (in_array('invalid-input-secret', $error_codes, true) || in_array('missing-input-secret', $error_codes, true)) {
            return [
                'ok' => false,
                'message' => __('reCAPTCHA secret key is invalid or missing.', 'nexdirectory'),
            ];
        }

        if (in_array('invalid-input-response', $error_codes, true) || in_array('missing-input-response', $error_codes, true)) {
            return [
                'ok' => true,
                'message' => __('reCAPTCHA keys are reachable. Dummy token was rejected as expected.', 'nexdirectory'),
            ];
        }

        return [
            'ok' => false,
            'message' => sprintf(
                __('reCAPTCHA test returned errors: %s', 'nexdirectory'),
                !empty($error_codes) ? implode(', ', $error_codes) : __('unknown', 'nexdirectory')
            ),
        ];
    }


    public function get_chatbot_position_options($context = 'any') {
        $desktop = [
            'bottom-right',
            'bottom-left',
            'right-edge-center',
            'left-edge-center',
            'inline',
        ];
        $mobile = [
            'bottom-right',
            'bottom-left',
            'bottom-center',
            'right-edge-center',
            'left-edge-center',
            'inline',
        ];

        $mode = sanitize_key((string) $context);
        if ($mode === 'desktop') {
            return $desktop;
        }
        if ($mode === 'mobile') {
            return $mobile;
        }
        return array_values(array_unique(array_merge($desktop, $mobile)));
    }


    public function sanitize_chatbot_desktop_position_option($value) {
        $value = sanitize_key((string) $value);
        $allowed = $this->get_chatbot_position_options('desktop');
        return in_array($value, $allowed, true) ? $value : 'bottom-right';
    }


    public function sanitize_chatbot_mobile_position_option($value) {
        $value = sanitize_key((string) $value);
        $allowed = $this->get_chatbot_position_options('mobile');
        return in_array($value, $allowed, true) ? $value : 'right-edge-center';
    }


    public function sanitize_chatbot_top_k_option($value) {
        $count = absint((int) $value);
        if ($count < 1) {
            $count = 1;
        }
        if ($count > 12) {
            $count = 12;
        }
        return $count;
    }


    public function sanitize_chatbot_candidates_option($value) {
        $count = absint((int) $value);
        if ($count < 20) {
            $count = 20;
        }
        if ($count > 1200) {
            $count = 1200;
        }
        return $count;
    }


    public function sanitize_chatbot_reindex_hours_option($value) {
        $hours = absint((int) $value);
        if ($hours < 1) {
            $hours = 1;
        }
        if ($hours > 168) {
            $hours = 168;
        }
        return $hours;
    }


    public function sanitize_chatbot_rate_limit_requests_option($value) {
        $count = absint((int) $value);
        if ($count < 3) {
            $count = 3;
        }
        if ($count > 120) {
            $count = 120;
        }
        return $count;
    }


    public function sanitize_chatbot_rate_limit_window_option($value) {
        $seconds = absint((int) $value);
        if ($seconds < 60) {
            $seconds = 60;
        }
        if ($seconds > 3600) {
            $seconds = 3600;
        }
        return $seconds;
    }


    public function sanitize_user_edit_policy_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['allow', 'require_approval', 'disallow'], true) ? $value : 'require_approval';
    }


    public function sanitize_extension_import_status_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['draft', 'publish'], true) ? $value : 'draft';
    }


    public function sanitize_extension_import_media_policy_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['none', 'images', 'images_video', 'video'], true) ? $value : 'none';
    }

    public function sanitize_indexnow_key_option($value) {
        $value = preg_replace('/[^A-Za-z0-9]/', '', (string) $value);
        $value = substr((string) $value, 0, 128);
        $length = strlen((string) $value);
        if ($length >= 8) {
            return $value;
        }
        $existing = preg_replace('/[^A-Za-z0-9]/', '', (string) get_option('eep_indexnow_key', ''));
        $existing = substr((string) $existing, 0, 128);
        if (strlen((string) $existing) >= 8) {
            return $existing;
        }
        if (method_exists($this, 'generate_indexnow_key')) {
            return (string) $this->generate_indexnow_key();
        }
        $generated = wp_generate_password(40, false, false);
        $generated = preg_replace('/[^A-Za-z0-9]/', '', (string) $generated);
        if (strlen((string) $generated) < 8) {
            $generated .= substr(md5(uniqid((string) wp_rand(), true)), 0, 16);
        }
        return substr((string) $generated, 0, 128);
    }

    public function sanitize_indexnow_endpoint_option($value) {
        $value = esc_url_raw((string) $value);
        if ($value === '') {
            return 'https://api.indexnow.org/indexnow';
        }
        return $value;
    }

    public function sanitize_extension_import_content_mode_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['rewrite', 'verbatim'], true) ? $value : 'rewrite';
    }


    public function sanitize_sticky_nav_behavior_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['sticky', 'static', 'smart'], true) ? $value : 'sticky';
    }


    public function sanitize_sticky_nav_custom_links_option($value) {
        $lines = preg_split('/\r\n|\r|\n/', (string) $value);
        if (!is_array($lines)) {
            $lines = [];
        }

        $normalized = [];
        foreach ($lines as $line) {
            $line = trim((string) $line);
            if ($line === '' || strpos($line, '#') === 0) {
                continue;
            }
            $parts = array_map('trim', explode('|', $line));
            $label = sanitize_text_field((string) ($parts[0] ?? ''));
            $url = esc_url_raw((string) ($parts[1] ?? ''));
            $audience = sanitize_key((string) ($parts[2] ?? 'all'));
            $group = sanitize_text_field((string) ($parts[3] ?? ''));
            $group = trim((string) str_replace('|', ' ', $group));
            if ($group === '') {
                $group = 'More';
            }
            if ($audience === 'loggedin' || $audience === 'member') {
                $audience = 'member';
            } elseif ($audience === 'loggedout' || $audience === 'guest') {
                $audience = 'guest';
            }
            if (!in_array($audience, ['all', 'guest', 'member'], true)) {
                $audience = 'all';
            }
            if ($label === '' || $url === '') {
                continue;
            }
            $normalized[] = $label . '|' . $url . '|' . $audience . '|' . $group;
            if (count($normalized) >= 16) {
                break;
            }
        }

        return implode("\n", $normalized);
    }

    public function sanitize_nav_menu_id_option($value) {
        $menu_id = absint((int) $value);
        if ($menu_id <= 0) {
            return 0;
        }
        $menu_object = wp_get_nav_menu_object($menu_id);
        if (!$menu_object instanceof WP_Term) {
            return 0;
        }
        return (int) $menu_object->term_id;
    }

    public function sanitize_sticky_nav_role_menu_map_option($value) {
        if (!is_array($value)) {
            return [];
        }

        $editable_roles = function_exists('get_editable_roles') ? (array) get_editable_roles() : [];
        $sanitized = [];

        foreach ($value as $role_key => $menu_id) {
            $role_key = sanitize_key((string) $role_key);
            if ($role_key === '' || !isset($editable_roles[$role_key])) {
                continue;
            }
            $normalized_menu_id = $this->sanitize_nav_menu_id_option($menu_id);
            if ($normalized_menu_id > 0) {
                $sanitized[$role_key] = $normalized_menu_id;
            }
        }

        return $sanitized;
    }

    public function sanitize_footer_menu_count_option($value) {
        $count = absint((int) $value);
        if ($count < 1) {
            $count = 1;
        } elseif ($count > 5) {
            $count = 5;
        }
        return $count;
    }

    public function sanitize_footer_wp_menu_list_option($value) {
        if (!is_array($value)) {
            return [];
        }

        $sanitized = [];
        foreach ($value as $menu_id) {
            $normalized_menu_id = $this->sanitize_nav_menu_id_option($menu_id);
            if ($normalized_menu_id > 0) {
                $sanitized[$normalized_menu_id] = $normalized_menu_id;
            }
            if (count($sanitized) >= 5) {
                break;
            }
        }

        return array_values($sanitized);
    }

    public function sanitize_footer_bottom_text_option($value) {
        $value = sanitize_text_field((string) $value);
        $value = trim((string) preg_replace('/\s+/u', ' ', $value));
        return function_exists('mb_substr') ? (string) mb_substr($value, 0, 190) : substr($value, 0, 190);
    }


    public function sanitize_extension_app_pass_option($value) {
        $value = trim((string) $value);
        $value = preg_replace('/[^A-Za-z0-9_\-]/', '', $value);
        $value = substr((string) $value, 0, 128);
        if ($value === '') {
            $existing = trim((string) get_option('eep_extension_app_pass', ''));
            if ($existing !== '') {
                return $existing;
            }
            return wp_generate_password(48, false, false);
        }
        return $value;
    }


    private function get_extension_app_pass($create_if_missing = true) {
        $current = trim((string) get_option('eep_extension_app_pass', ''));
        if ($current !== '') {
            return $current;
        }
        if (!$create_if_missing) {
            return '';
        }
        $generated = wp_generate_password(48, false, false);
        update_option('eep_extension_app_pass', $generated, false);
        return $generated;
    }


    public function sanitize_map_results_per_page_option($value) {
        $count = absint((int) $value);
        if ($count < 12) {
            $count = 12;
        }
        if ($count > 250) {
            $count = 250;
        }
        return $count;
    }


    public function sanitize_hero_layout_option($value) {
        $value = sanitize_key((string) $value);
        return in_array($value, ['cinematic', 'compact', 'split', 'minimal', 'immersive', 'spotlight'], true) ? $value : 'cinematic';
    }


    public function sanitize_event_page_layout_option($value) {
        $value = sanitize_key((string) $value);
        $allowed = ['modern', 'single-column', 'editorial', 'fifty-fifty', 'left-sidebar', 'zig-zag', 'full3', 'zen'];
        return in_array($value, $allowed, true) ? $value : 'modern';
    }


    public function sanitize_event_gallery_type_option($value) {
        $value = sanitize_key((string) $value);
        $allowed = ['default', 'carousel', 'wall'];
        return in_array($value, $allowed, true) ? $value : 'default';
    }


    public function sanitize_smtp_port_option($value) {
        $port = absint((int) $value);
        if ($port < 1) {
            $port = 587;
        }
        if ($port > 65535) {
            $port = 65535;
        }
        return $port;
    }


    public function sanitize_smtp_encryption_option($value) {
        $value = strtolower(trim((string) $value));
        return in_array($value, ['', 'none', 'tls', 'ssl'], true) ? $value : 'tls';
    }


    public function sanitize_upload_limit_kb_option($value) {
        $v = absint((int) $value);
        if ($v < 64) {
            $v = 64;
        }
        if ($v > 20480) {
            $v = 20480;
        }
        return $v;
    }


    public function sanitize_upload_files_count_option($value) {
        $v = absint((int) $value);
        if ($v < 1) {
            $v = 1;
        }
        if ($v > 100) {
            $v = 100;
        }
        return $v;
    }


    public function sanitize_custom_form_fields_option($value) {
        $decoded = [];
        if (is_string($value)) {
            $decoded = json_decode($value, true);
            if (!is_array($decoded)) {
                $decoded = [];
            }
        } elseif (is_array($value)) {
            $decoded = $value;
        }

        if (isset($decoded['id']) && is_array($decoded['id'])) {
            $rows = [];
            foreach ((array) $decoded['id'] as $index => $id_value) {
                $rows[] = [
                    'id' => $id_value,
                    'label' => isset($decoded['label'][$index]) ? $decoded['label'][$index] : '',
                    'type' => isset($decoded['type'][$index]) ? $decoded['type'][$index] : 'text',
                    'placeholder' => isset($decoded['placeholder'][$index]) ? $decoded['placeholder'][$index] : '',
                    'help' => isset($decoded['help'][$index]) ? $decoded['help'][$index] : '',
                    'required' => isset($decoded['required'][$index]) ? $decoded['required'][$index] : '0',
                    'show_in_event' => isset($decoded['show_in_event'][$index]) ? $decoded['show_in_event'][$index] : '1',
                    'options' => isset($decoded['options'][$index]) ? $decoded['options'][$index] : '',
                ];
            }
            $decoded = $rows;
        }

        $sanitized = [];
        $seen_ids = [];
        foreach ((array) $decoded as $index => $row) {
            if (!is_array($row)) {
                continue;
            }
            $field = $this->sanitize_custom_field_definition($row, (int) $index);
            if ($field['id'] === '' || isset($seen_ids[$field['id']])) {
                continue;
            }
            $seen_ids[$field['id']] = true;
            $sanitized[] = $field;
        }

        return wp_json_encode(array_values($sanitized));
    }


    public function sanitize_custom_taxonomies_option($value) {
        $rows = [];
        if (is_array($value)) {
            $rows = $value;
        } else {
            $raw = (string) $value;
            $lines = preg_split('/\r\n|\r|\n/', $raw);
            if (!is_array($lines)) {
                $lines = [];
            }
            foreach ($lines as $line) {
                $line = trim((string) $line);
                if ($line === '' || strpos($line, '#') === 0) {
                    continue;
                }
                $parts = array_map('trim', explode('|', $line));
                $rows[] = [
                    'slug' => $parts[0] ?? '',
                    'label' => $parts[1] ?? '',
                    'hierarchical' => $parts[2] ?? '1',
                    'show_on_submit' => $parts[3] ?? '1',
                    'show_on_overview' => $parts[4] ?? '1',
                ];
            }
        }

        $reserved = [
            self::TAX_TYPE,
            self::TAX_MODE,
            self::TAX_TAG,
            self::TAX_PRICE,
            'category',
            'post_tag',
        ];
        $normalized = [];
        $seen = [];
        foreach ((array) $rows as $row) {
            if (!is_array($row)) {
                continue;
            }
            $slug = eep_sanitize_title((string) ($row['slug'] ?? ''));
            if ($slug === '') {
                continue;
            }
            if (strpos($slug, 'eep_') !== 0) {
                $slug = 'eep_' . $slug;
            }
            if (in_array($slug, $reserved, true) || isset($seen[$slug])) {
                continue;
            }
            $label = sanitize_text_field((string) ($row['label'] ?? ''));
            if ($label === '') {
                $label = ucwords(str_replace(['_', '-'], ' ', preg_replace('/^eep_/', '', $slug)));
            }
            $to_bool_flag = static function ($input, $default = '1') {
                $value = strtolower(trim((string) $input));
                if (in_array($value, ['1', 'true', 'yes', 'y', 'on'], true)) {
                    return '1';
                }
                if (in_array($value, ['0', 'false', 'no', 'n', 'off'], true)) {
                    return '0';
                }
                return $default;
            };
            $normalized[] = [
                'slug' => $slug,
                'label' => $label,
                'hierarchical' => $to_bool_flag($row['hierarchical'] ?? '1', '1'),
                'show_on_submit' => $to_bool_flag($row['show_on_submit'] ?? '1', '1'),
                'show_on_overview' => $to_bool_flag($row['show_on_overview'] ?? '1', '1'),
            ];
            $seen[$slug] = true;
        }

        return wp_json_encode(array_values($normalized));
    }


    private function get_pending_events_count() {
        $counts = wp_count_posts(self::POST_TYPE);
        if (!$counts || !isset($counts->pending)) {
            return 0;
        }
        return max(0, (int) $counts->pending);
    }


    private function get_pending_claim_requests_count() {
        $count = get_comments([
            'type' => 'eep_claim',
            'status' => 'hold',
            'count' => true,
        ]);
        if (!is_numeric($count)) {
            return 0;
        }
        return max(0, (int) $count);
    }


    private function get_user_reports_count() {
        $count = get_comments([
            'type' => 'eep_report',
            'status' => 'approve',
            'count' => true,
        ]);
        if (!is_numeric($count)) {
            return 0;
        }
        return max(0, (int) $count);
    }


    private function get_open_moderation_items_count() {
        return $this->get_pending_events_count()
            + $this->get_pending_claim_requests_count()
            + $this->get_user_reports_count();
    }


    private function sync_role_capabilities_from_settings() {
        $role_flags = [
            'event_submitter' => [
                'eep_submit_events' => (string) get_option('eep_role_event_submitter_can_submit', '1') === '1',
            ],
            'author' => [
                'eep_submit_events' => (string) get_option('eep_role_author_can_submit', '1') === '1',
            ],
            'editor' => [
                'eep_moderate_events' => (string) get_option('eep_role_editor_can_moderate', '1') === '1',
                'eep_manage_organizers' => (string) get_option('eep_role_editor_manage_organizers', '1') === '1',
            ],
        ];
        foreach ($role_flags as $role_name => $capabilities) {
            $role = get_role($role_name);
            if (!$role instanceof WP_Role) {
                continue;
            }
            foreach ($capabilities as $capability => $enabled) {
                if ($enabled) {
                    $role->add_cap($capability, true);
                } else {
                    $role->remove_cap($capability);
                }
            }
        }
    }

    /**
     * Returns upgrade/license action URLs and label for admin CTAs.
     *
     * @return array<string, string>
     */
    private function get_freemius_admin_action_urls() {
        $context = [
            'upgrade_url' => 'https://nexdirectory.com/purchase',
            'license_url' => admin_url('admin.php?page=eep-settings#eep-tab-monetization--boost-packages'),
            'license_label' => __('Activate License', 'nexdirectory'),
        ];

        if (!function_exists('epw_fs')) {
            return $context;
        }

        try {
            $fs = epw_fs();
            if (method_exists($fs, 'get_upgrade_url')) {
                $upgrade_url = (string) $fs->get_upgrade_url();
                if ($upgrade_url !== '') {
                    $context['upgrade_url'] = $upgrade_url;
                }
            }

            $can_manage_license = $this->can_manage_freemius_license_page();

            if ($can_manage_license) {
                if (method_exists($fs, 'get_account_url')) {
                    $account_url = (string) $fs->get_account_url();
                    if ($account_url !== '') {
                        $context['license_url'] = $account_url;
                    }
                }
                $context['license_label'] = __('Manage License', 'nexdirectory');
            } else {
                if (method_exists($fs, 'get_activation_url')) {
                    $activation_url = (string) $fs->get_activation_url();
                    if ($activation_url !== '') {
                        $context['license_url'] = $activation_url;
                    }
                }
                $context['license_label'] = __('Activate License', 'nexdirectory');
            }
        } catch (Throwable $unused) {
            // Keep defaults when Freemius is unavailable.
        }

        return $context;
    }

    /**
     * Returns normalized demo-mode usage details for admin screens.
     *
     * @return array<string, mixed>
     */
    private function get_demo_limit_admin_context() {
        $limit_status = method_exists($this, 'get_demo_event_limit_status')
            ? (array) $this->get_demo_event_limit_status()
            : [];
        $license_links = $this->get_freemius_admin_action_urls();
        $is_demo_mode = !empty($limit_status['enabled']);
        $limit = max(1, (int) ($limit_status['limit'] ?? 3));
        $used = max(0, (int) ($limit_status['used'] ?? 0));
        $remaining = max(0, (int) ($limit_status['remaining'] ?? max(0, $limit - $used)));

        return [
            'is_demo_mode' => $is_demo_mode,
            'limit' => $limit,
            'used' => $used,
            'remaining' => $remaining,
            'is_at_limit' => $is_demo_mode && $used >= $limit,
            'upgrade_url' => (string) ($license_links['upgrade_url'] ?? 'https://nexdirectory.com/purchase'),
            'license_url' => (string) ($license_links['license_url'] ?? admin_url('admin.php?page=eep-settings#eep-tab-monetization--boost-packages')),
            'license_label' => (string) ($license_links['license_label'] ?? __('Activate License', 'nexdirectory')),
        ];
    }


    public function render_dashboard_page() {
        if (!current_user_can('manage_options')) {
            return;
        }

        global $wpdb;

        $brand_name = $this->get_white_label_brand_name();
        $user = wp_get_current_user();
        $display_name = '';
        if ($user instanceof WP_User) {
            $display_name = trim((string) ($user->display_name ?: $user->user_login));
        }
        if ($display_name === '') {
            $display_name = __('Admin', 'nexdirectory');
        }

        $profile_key = method_exists($this, 'get_site_profile_key')
            ? (string) $this->get_site_profile_key()
            : 'events';
        $profile_config = method_exists($this, 'get_site_profile_config')
            ? (array) $this->get_site_profile_config($profile_key)
            : [];
        $mode_label = sanitize_text_field((string) ($profile_config['label'] ?? ucfirst(str_replace('_', ' ', $profile_key))));
        if ($mode_label === '') {
            $mode_label = __('Events (default)', 'nexdirectory');
        }

        $counts = wp_count_posts(self::POST_TYPE);
        $published_count = (int) ($counts->publish ?? 0);
        $pending_count = (int) ($counts->pending ?? 0);
        $draft_count = (int) ($counts->draft ?? 0);
        $expired_count = (int) ($counts->expired ?? 0);
        $private_count = (int) ($counts->private ?? 0);
        $future_count = (int) ($counts->future ?? 0);
        $total_listings = $published_count + $pending_count + $draft_count + $private_count + $future_count;

        $users_summary = function_exists('count_users') ? (array) count_users() : [];
        $total_users = (int) ($users_summary['total_users'] ?? 0);
        $active_users = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(DISTINCT post_author) FROM {$wpdb->posts} WHERE post_type = %s AND post_status IN ('publish','pending','draft','future')",
                self::POST_TYPE
            )
        );

        $license_label = __('Unknown', 'nexdirectory');
        $license_class = 'eep-status-neutral';
        $show_purchase_cta = false;
        if (function_exists('epw_fs')) {
            try {
                $premium_enabled = epw_fs()->can_use_premium_code__premium_only();
                $is_registered = method_exists(epw_fs(), 'is_registered') ? (bool) epw_fs()->is_registered() : false;
                if ($premium_enabled) {
                    $license_label = __('Premium Active', 'nexdirectory');
                    $license_class = 'eep-status-ok';
                    if (method_exists(epw_fs(), 'is_trial') && epw_fs()->is_trial()) {
                        $license_label = __('Trial Active', 'nexdirectory');
                        $license_class = 'eep-status-warn';
                    }
                } else {
                    $license_label = $is_registered
                        ? __('Free / Locked', 'nexdirectory')
                        : __('Free / Unregistered', 'nexdirectory');
                    $license_class = 'eep-status-warn';
                    $show_purchase_cta = true;
                }
            } catch (Throwable $exception) {
                $license_label = __('Unavailable', 'nexdirectory');
                $license_class = 'eep-status-neutral';
                $show_purchase_cta = true;
            }
        }

        $analytics_report = method_exists($this, 'get_platform_analytics_report')
            ? (array) $this->get_platform_analytics_report(30)
            : [];
        $analytics_summary = is_array($analytics_report['summary'] ?? null)
            ? (array) $analytics_report['summary']
            : [];
        $view_to_enquiry = (float) ($analytics_summary['view_to_enquiry_conversion'] ?? 0);
        $estimated_revenue = (float) ($analytics_summary['revenue_estimate'] ?? 0);

        $embeddings_count = 0;
        if (method_exists($this, 'get_chatbot_index_stats')) {
            $chatbot_stats = (array) $this->get_chatbot_index_stats();
            $embeddings_count = (int) ($chatbot_stats['rows'] ?? 0);
        }

        $rsvp_total = 0;
        $rsvp_table = $wpdb->prefix . self::RSVP_TABLE;
        $rsvp_table_exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $rsvp_table));
        if (is_string($rsvp_table_exists) && $rsvp_table_exists !== '') {
            $rsvp_total = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$rsvp_table}");
        }

        $submit_url = $this->get_platform_page_url(
            'eep_page_submit_event_url',
            $this->get_profile_route_slugs('submit', $profile_key),
            $this->get_profile_route_default_url('submit', $profile_key)
        );

        $map_provider = sanitize_key((string) get_option('eep_map_provider', 'openstreetmap'));
        $map_ready = true;
        if ($map_provider === 'google') {
            $map_ready = trim((string) get_option('eep_google_maps_api_key', '')) !== '';
        } elseif ($map_provider === 'mapbox') {
            $map_ready = trim((string) get_option('eep_mapbox_access_token', '')) !== '';
        }
        $smtp_ready = (string) get_option('eep_smtp_enabled', '0') === '1' && trim((string) get_option('eep_smtp_host', '')) !== '';
        $demo_limit_context = (array) $this->get_demo_limit_admin_context();
        $demo_mode_enabled = !empty($demo_limit_context['is_demo_mode']);
        $demo_limit_value = max(1, (int) ($demo_limit_context['limit'] ?? 3));
        $demo_used_value = max(0, (int) ($demo_limit_context['used'] ?? 0));
        $demo_remaining_value = max(0, (int) ($demo_limit_context['remaining'] ?? 0));
        $demo_is_at_limit = !empty($demo_limit_context['is_at_limit']);
        $freemius_upgrade_url = esc_url((string) ($demo_limit_context['upgrade_url'] ?? 'https://nexdirectory.com/purchase'));
        $freemius_license_url = esc_url((string) ($demo_limit_context['license_url'] ?? admin_url('admin.php?page=eep-settings#eep-tab-monetization--boost-packages')));
        $freemius_license_label = sanitize_text_field((string) ($demo_limit_context['license_label'] ?? __('Activate License', 'nexdirectory')));
        $pricing_settings_url = esc_url(admin_url('admin.php?page=eep-settings#eep-tab-monetization--boost-packages'));
        $license_status_summary = $demo_mode_enabled
            ? sprintf(__('Demo mode: %1$d/%2$d events used.', 'nexdirectory'), $demo_used_value, $demo_limit_value)
            : __('Premium is active. Manage billing, seats, and license connection below.', 'nexdirectory');

        ?>
        <div class="wrap eep-admin-premium eep-dashboard-page">
            <?php $this->render_admin_premium_shell_styles(); ?>
            <style id="eep-admin-dashboard-styles">
                .eep-dashboard-page .eep-dashboard-status-line { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }
                .eep-dashboard-page .eep-dashboard-chip { background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.22); color: #fff; border-radius: 999px; padding: 8px 12px; font-size: 12px; letter-spacing: .02em; }
                .eep-dashboard-page .eep-dashboard-chip strong { color: #fff; margin-right: 5px; }
                .eep-dashboard-page .eep-dashboard-chip-link { text-decoration: none; transition: all .2s ease; }
                .eep-dashboard-page .eep-dashboard-chip-link:hover,
                .eep-dashboard-page .eep-dashboard-chip-link:focus-visible { border-color: rgba(255, 255, 255, .7); background: rgba(255,255,255,.2); color: #fff; }
                .eep-dashboard-page .eep-status-ok { background: rgba(22, 163, 74, .14); border-color: rgba(22, 163, 74, .55); }
                .eep-dashboard-page .eep-status-warn { background: rgba(245, 158, 11, .16); border-color: rgba(245, 158, 11, .55); }
                .eep-dashboard-page .eep-status-neutral { background: rgba(148, 163, 184, .18); border-color: rgba(148, 163, 184, .5); }
                .eep-dashboard-page .eep-admin-quick-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 10px; }
                .eep-dashboard-page .eep-admin-quick-actions .button { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 38px; font-weight: 600; }
                .eep-dashboard-page .eep-admin-two-col { display: grid; grid-template-columns: 1.2fr .8fr; gap: 14px; }
                .eep-dashboard-page .eep-dashboard-help-card { border: 1px solid #e2e8f0; border-radius: 12px; background: #f8fafc; padding: 12px; }
                .eep-dashboard-page .eep-dashboard-help-card iframe { width: 100%; min-height: 260px; border: 1px solid #dbe3ec; border-radius: 8px; background: #fff; }
                .eep-dashboard-page .eep-dashboard-checklist { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
                .eep-dashboard-page .eep-dashboard-checklist li { display: flex; align-items: center; gap: 8px; font-size: 13px; }
                .eep-dashboard-page .eep-dashboard-check { width: 20px; height: 20px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-weight: 700; font-size: 12px; color: #fff; background: #94a3b8; }
                .eep-dashboard-page .eep-dashboard-check.is-done { background: #16a34a; }
                .eep-dashboard-page .eep-dashboard-update-list { margin: 8px 0 0 18px; }
                .eep-dashboard-page .eep-dashboard-update-list li { margin-bottom: 6px; }
                .eep-dashboard-page .eep-dashboard-upsell {
                    border: 1px solid #fecaca;
                    border-radius: 14px;
                    background: linear-gradient(135deg, #fff7ed 0%, #ffedd5 100%);
                    box-shadow: 0 10px 30px rgba(255, 94, 20, .12);
                    padding: 18px;
                    display: flex;
                    align-items: center;
                    justify-content: space-between;
                    gap: 12px;
                    flex-wrap: wrap;
                }
                .eep-dashboard-page .eep-dashboard-upsell h3 {
                    margin: 0 0 4px;
                    color: #9a3412;
                    font-size: 19px;
                    line-height: 1.3;
                }
                .eep-dashboard-page .eep-dashboard-upsell p {
                    margin: 0;
                    color: #7c2d12;
                    font-size: 13px;
                }
                .eep-dashboard-page .eep-dashboard-upsell .button-primary {
                    min-height: 44px;
                    min-width: 190px;
                    font-size: 14px;
                    font-weight: 700;
                    letter-spacing: .03em;
                }
                .eep-dashboard-page .eep-dashboard-upsell .eep-dashboard-upsell-actions {
                    display: flex;
                    align-items: center;
                    gap: 8px;
                    flex-wrap: wrap;
                }
                .eep-dashboard-page .eep-dashboard-upsell .eep-dashboard-upsell-actions .button {
                    min-height: 42px;
                    font-weight: 700;
                    letter-spacing: .02em;
                }
                .eep-dashboard-page .eep-dashboard-upsell .eep-demo-counter {
                    display: inline-flex;
                    align-items: center;
                    gap: 6px;
                    margin-top: 6px;
                    padding: 4px 10px;
                    border-radius: 999px;
                    border: 1px solid #fdba74;
                    background: rgba(255, 255, 255, .6);
                    color: #9a3412;
                    font-size: 12px;
                    font-weight: 700;
                }
                .eep-dashboard-page .eep-license-card {
                    border: 1px solid #dbe2ec;
                    border-radius: 14px;
                    background: linear-gradient(180deg, #ffffff 0%, #f8fbff 100%);
                    box-shadow: 0 8px 20px rgba(15, 23, 42, .06);
                    padding: 16px;
                    display: flex;
                    align-items: center;
                    justify-content: space-between;
                    gap: 12px;
                    flex-wrap: wrap;
                }
                .eep-dashboard-page .eep-license-card h3 {
                    margin: 0 0 4px;
                    color: #0f172a;
                    font-size: 18px;
                    line-height: 1.25;
                }
                .eep-dashboard-page .eep-license-card p {
                    margin: 0;
                    color: #475569;
                    font-size: 13px;
                }
                .eep-dashboard-page .eep-license-card-actions {
                    display: flex;
                    align-items: center;
                    gap: 8px;
                    flex-wrap: wrap;
                }
                .eep-dashboard-page .eep-license-card-actions .button {
                    min-height: 40px;
                    font-weight: 700;
                }
                @media (max-width: 900px) {
                    .eep-dashboard-page .eep-admin-two-col { grid-template-columns: 1fr; }
                }
            </style>

            <section class="eep-admin-hero">
                <span class="eep-admin-hero-kicker"><?php esc_html_e('Welcome Dashboard', 'nexdirectory'); ?></span>
                <h1><?php echo esc_html(sprintf(__('Welcome back, %s', 'nexdirectory'), $display_name)); ?> <span aria-hidden="true">👋</span></h1>
                <p>
                    <?php
                    echo esc_html(
                        sprintf(
                            __('This is your %1$s control center. Manage listings, moderation, imports, and AI tools from one place.', 'nexdirectory'),
                            $brand_name
                        )
                    );
                    ?>
                </p>
                <div class="eep-dashboard-status-line">
                    <span class="eep-dashboard-chip"><strong><?php esc_html_e('Current Mode:', 'nexdirectory'); ?></strong><?php echo esc_html($mode_label); ?></span>
                    <span class="eep-dashboard-chip"><strong><?php esc_html_e('Total Listings:', 'nexdirectory'); ?></strong><?php echo esc_html((string) $total_listings); ?></span>
                    <span class="eep-dashboard-chip"><strong><?php esc_html_e('Pending Moderation:', 'nexdirectory'); ?></strong><?php echo esc_html((string) $pending_count); ?></span>
                    <span class="eep-dashboard-chip"><strong><?php esc_html_e('Active Users:', 'nexdirectory'); ?></strong><?php echo esc_html((string) $active_users); ?></span>
                    <span class="eep-dashboard-chip <?php echo esc_attr($license_class); ?>"><strong><?php esc_html_e('Plan:', 'nexdirectory'); ?></strong><?php echo esc_html($license_label); ?></span>
                    <?php if ($demo_mode_enabled) : ?>
                        <a class="eep-dashboard-chip eep-status-warn eep-dashboard-chip-link" href="<?php echo $pricing_settings_url; ?>" title="<?php echo esc_attr(sprintf(__('Demo mode usage: %1$d/%2$d used. Click to manage pricing and license.', 'nexdirectory'), $demo_used_value, $demo_limit_value)); ?>">
                            <strong><?php esc_html_e('Free Events Left:', 'nexdirectory'); ?></strong><?php echo esc_html((string) $demo_remaining_value); ?>
                        </a>
                    <?php endif; ?>
                </div>
            </section>

            <?php if ($show_purchase_cta) : ?>
                <section class="eep-admin-panel eep-dashboard-upsell" aria-label="<?php esc_attr_e('Upgrade to premium', 'nexdirectory'); ?>">
                    <div>
                        <h3><?php echo esc_html(sprintf(__('Demo Mode Active: %d Free Events', 'nexdirectory'), $demo_limit_value)); ?></h3>
                        <p><?php echo esc_html(sprintf(__('This site is running in demo mode. You can publish up to %d events before upgrading or activating your Freemius license.', 'nexdirectory'), $demo_limit_value)); ?></p>
                        <?php if ($demo_mode_enabled) : ?>
                            <span class="eep-demo-counter">
                                <?php
                                echo esc_html(
                                    sprintf(
                                        __('Used %1$d of %2$d (Remaining: %3$d)', 'nexdirectory'),
                                        $demo_used_value,
                                        $demo_limit_value,
                                        $demo_remaining_value
                                    )
                                );
                                ?>
                            </span>
                        <?php endif; ?>
                    </div>
                    <div class="eep-dashboard-upsell-actions">
                        <a class="button button-primary" href="<?php echo $freemius_upgrade_url; ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Buy / Upgrade', 'nexdirectory'); ?></a>
                        <a class="button" href="<?php echo $freemius_license_url; ?>"><?php echo esc_html($freemius_license_label); ?></a>
                    </div>
                </section>
            <?php endif; ?>

            <section class="eep-admin-panel eep-license-card" aria-label="<?php esc_attr_e('License and billing', 'nexdirectory'); ?>">
                <div>
                    <h3><?php esc_html_e('License & Billing', 'nexdirectory'); ?></h3>
                    <p><?php echo esc_html($license_status_summary); ?></p>
                </div>
                <div class="eep-license-card-actions">
                    <a class="button button-primary" href="<?php echo $freemius_license_url; ?>"><?php echo esc_html($freemius_license_label); ?></a>
                    <a class="button" href="<?php echo $freemius_upgrade_url; ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Buy / Upgrade', 'nexdirectory'); ?></a>
                </div>
            </section>

            <section class="eep-admin-panel">
                <h2><span class="dashicons dashicons-chart-area" aria-hidden="true"></span><?php esc_html_e('At-a-Glance Stats', 'nexdirectory'); ?></h2>
                <div class="eep-admin-grid">
                    <div class="eep-admin-stat-card"><p class="eep-admin-stat-label"><?php esc_html_e('Total Listings', 'nexdirectory'); ?></p><p class="eep-admin-stat-value"><?php echo esc_html((string) $total_listings); ?></p></div>
                    <div class="eep-admin-stat-card"><p class="eep-admin-stat-label"><?php esc_html_e('Published', 'nexdirectory'); ?></p><p class="eep-admin-stat-value"><?php echo esc_html((string) $published_count); ?></p></div>
                    <div class="eep-admin-stat-card"><p class="eep-admin-stat-label"><?php esc_html_e('Pending', 'nexdirectory'); ?></p><p class="eep-admin-stat-value"><?php echo esc_html((string) $pending_count); ?></p></div>
                    <div class="eep-admin-stat-card"><p class="eep-admin-stat-label"><?php esc_html_e('Expired', 'nexdirectory'); ?></p><p class="eep-admin-stat-value"><?php echo esc_html((string) $expired_count); ?></p></div>
                    <div class="eep-admin-stat-card"><p class="eep-admin-stat-label"><?php esc_html_e('RSVP Count', 'nexdirectory'); ?></p><p class="eep-admin-stat-value"><?php echo esc_html((string) $rsvp_total); ?></p></div>
                    <div class="eep-admin-stat-card"><p class="eep-admin-stat-label"><?php esc_html_e('Embeddings Indexed', 'nexdirectory'); ?></p><p class="eep-admin-stat-value"><?php echo esc_html((string) $embeddings_count); ?></p></div>
                    <div class="eep-admin-stat-card"><p class="eep-admin-stat-label"><?php esc_html_e('Total Users', 'nexdirectory'); ?></p><p class="eep-admin-stat-value"><?php echo esc_html((string) $total_users); ?></p></div>
                    <div class="eep-admin-stat-card"><p class="eep-admin-stat-label"><?php esc_html_e('View → Enquiry', 'nexdirectory'); ?></p><p class="eep-admin-stat-value"><?php echo esc_html(number_format($view_to_enquiry, 2)); ?>%</p></div>
                    <div class="eep-admin-stat-card"><p class="eep-admin-stat-label"><?php esc_html_e('Revenue (Estimated)', 'nexdirectory'); ?></p><p class="eep-admin-stat-value">$<?php echo esc_html(number_format($estimated_revenue, 2)); ?></p></div>
                </div>
            </section>

            <section class="eep-admin-panel">
                <h2><span class="dashicons dashicons-superhero" aria-hidden="true"></span><?php esc_html_e('Quick Actions', 'nexdirectory'); ?></h2>
                <div class="eep-admin-quick-actions">
                    <a class="button button-primary" href="<?php echo esc_url($submit_url); ?>"><span class="dashicons dashicons-plus-alt2" aria-hidden="true"></span><?php esc_html_e('Add New Listing', 'nexdirectory'); ?></a>
                    <a class="button" href="<?php echo esc_url(admin_url('admin.php?page=eep-import')); ?>"><span class="dashicons dashicons-upload" aria-hidden="true"></span><?php esc_html_e('Import Listings', 'nexdirectory'); ?></a>
                    <a class="button" href="<?php echo esc_url(admin_url('admin.php?page=eep-settings#eep-tab-pages')); ?>"><span class="dashicons dashicons-layout" aria-hidden="true"></span><?php esc_html_e('Configure Templates', 'nexdirectory'); ?></a>
                    <a class="button" href="<?php echo esc_url(admin_url('admin.php?page=eep-settings')); ?>"><span class="dashicons dashicons-admin-generic" aria-hidden="true"></span><?php esc_html_e('Settings', 'nexdirectory'); ?></a>
                    <a class="button" href="<?php echo esc_url(admin_url('admin.php?page=eep-diagnostics')); ?>"><span class="dashicons dashicons-shield-alt" aria-hidden="true"></span><?php esc_html_e('Run Diagnostics', 'nexdirectory'); ?></a>
                    <a class="button" href="<?php echo esc_url(admin_url('admin.php?page=eep-metrics')); ?>"><span class="dashicons dashicons-chart-bar" aria-hidden="true"></span><?php esc_html_e('Export Data', 'nexdirectory'); ?></a>
                </div>
            </section>

            <section class="eep-admin-panel eep-admin-two-col">
                <div class="eep-dashboard-help-card">
                    <h2><span class="dashicons dashicons-video-alt3" aria-hidden="true"></span><?php esc_html_e('Tutorials & Help', 'nexdirectory'); ?></h2>
                    <iframe src="https://nexdirectory.com/tutorials" loading="lazy" title="<?php echo esc_attr($brand_name . ' tutorials'); ?>"></iframe>
                    <p style="margin-top:10px;display:flex;gap:8px;flex-wrap:wrap;">
                        <a class="button button-primary" href="<?php echo esc_url('https://nexdirectory.com/tutorials'); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e('View All Tutorials', 'nexdirectory'); ?></a>
                        <a class="button" href="<?php echo esc_url('https://nexdirectory.com/support'); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Get Support', 'nexdirectory'); ?></a>
                    </p>
                </div>
                <div class="eep-dashboard-help-card">
                    <h2><span class="dashicons dashicons-yes-alt" aria-hidden="true"></span><?php esc_html_e('Getting Started Checklist', 'nexdirectory'); ?></h2>
                    <ul class="eep-dashboard-checklist">
                        <li><span class="eep-dashboard-check is-done">✓</span><?php esc_html_e('Choose template mode', 'nexdirectory'); ?></li>
                        <li><span class="eep-dashboard-check <?php echo $smtp_ready ? 'is-done' : ''; ?>"><?php echo $smtp_ready ? '✓' : '•'; ?></span><?php esc_html_e('Configure email delivery', 'nexdirectory'); ?></li>
                        <li><span class="eep-dashboard-check <?php echo $total_listings > 0 ? 'is-done' : ''; ?>"><?php echo $total_listings > 0 ? '✓' : '•'; ?></span><?php esc_html_e('Add first listing', 'nexdirectory'); ?></li>
                        <li><span class="eep-dashboard-check <?php echo $map_ready ? 'is-done' : ''; ?>"><?php echo $map_ready ? '✓' : '•'; ?></span><?php esc_html_e('Configure map provider', 'nexdirectory'); ?></li>
                        <li><span class="eep-dashboard-check <?php echo $estimated_revenue > 0 ? 'is-done' : ''; ?>"><?php echo $estimated_revenue > 0 ? '✓' : '•'; ?></span><?php esc_html_e('Enable monetisation (optional)', 'nexdirectory'); ?></li>
                    </ul>
                </div>
            </section>

            <section class="eep-admin-panel">
                <h2><span class="dashicons dashicons-megaphone" aria-hidden="true"></span><?php esc_html_e('Updates & Changelog', 'nexdirectory'); ?></h2>
                <p><strong><?php echo esc_html(sprintf(__('Current version: %s', 'nexdirectory'), (string) self::VERSION)); ?></strong></p>
                <ul class="eep-dashboard-update-list">
                    <li><?php esc_html_e('New profile-aware routing and template mode handling.', 'nexdirectory'); ?></li>
                    <li><?php esc_html_e('Improved import tooling, moderation UX, and white-label controls.', 'nexdirectory'); ?></li>
                    <li><?php esc_html_e('Expanded AI assistant controls and embedding workflows.', 'nexdirectory'); ?></li>
                </ul>
                <p style="margin-top:10px;display:flex;gap:8px;flex-wrap:wrap;">
                    <a class="button" href="<?php echo esc_url('https://nexdirectory.com/tutorials'); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Release Notes', 'nexdirectory'); ?></a>
                    <a class="button" href="<?php echo esc_url('https://nexdirectory.com/support'); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e('Roadmap & Support', 'nexdirectory'); ?></a>
                </p>
            </section>
        </div>
        <?php
    }


    public function render_settings_page() {
        if (!current_user_can('manage_options')) {
            return;
        }

        echo $this->render_admin_template('settings/page.php');
    }


    public function render_admin_moderation_page() {
        if (!current_user_can('manage_options')) {
            return;
        }
        $this->enqueue_assets();
        $settings_brand_name = $this->get_white_label_brand_name();
        $ui_labels = method_exists($this, 'get_site_profile_ui_labels') ? (array) $this->get_site_profile_ui_labels() : [];
        $plural_label = sanitize_text_field((string) ($ui_labels['plural'] ?? __('Events', 'nexdirectory')));
        ?>
        <div class="wrap eep-admin-premium eep-settings-premium eep-moderation-admin-page">
            <?php $this->render_admin_premium_shell_styles(); ?>
            <style id="eep-moderation-admin-shell">
                .eep-moderation-admin-page .eep-admin-hero {
                    display: grid;
                    grid-template-columns: minmax(0, 1fr) auto;
                    gap: 16px;
                    align-items: center;
                }
                .eep-moderation-admin-page .eep-admin-hero-badges {
                    display: flex;
                    flex-wrap: wrap;
                    gap: 8px;
                    margin-top: 10px;
                }
                .eep-moderation-admin-page .eep-admin-hero-badge {
                    display: inline-flex;
                    align-items: center;
                    gap: 6px;
                    padding: 4px 10px;
                    border-radius: 999px;
                    border: 1px solid rgba(148, 163, 184, .4);
                    background: rgba(15, 23, 42, .35);
                    color: #dbeafe;
                    font-size: 11px;
                    font-weight: 700;
                }
                .eep-moderation-admin-page .eep-admin-hero-action .button {
                    border-color: rgba(148, 163, 184, .48);
                    background: rgba(255, 255, 255, .1);
                    color: #fff;
                }
                .eep-moderation-admin-page .eep-admin-hero-action .button:hover,
                .eep-moderation-admin-page .eep-admin-hero-action .button:focus {
                    background: rgba(255, 255, 255, .16);
                    color: #fff;
                    border-color: rgba(148, 163, 184, .72);
                }
                .eep-moderation-admin-page .eep-my-events.eep-moderation-queue {
                    max-width: none !important;
                    width: 100% !important;
                    margin: 0 !important;
                    border-radius: 0 !important;
                    padding-inline: 0 !important;
                }
                .eep-moderation-admin-page [data-eep-uniform-page="1"],
                .eep-moderation-admin-page .eep-uniform-page-gutter[data-eep-uniform-page="1"] {
                    padding-left: 0 !important;
                    padding-right: 0 !important;
                }
                .eep-moderation-admin-page .eep-moderation-queue {
                    min-height: auto;
                    padding-bottom: 0;
                    background: transparent;
                }
                .eep-moderation-admin-page .eep-moderation-queue-shell {
                    max-width: 100%;
                    width: 100%;
                    margin: 0;
                    padding: 0;
                }
                .eep-moderation-admin-page .eep-moderation-queue-shell > section,
                .eep-moderation-admin-page .eep-moderation-queue-shell > nav {
                    width: 100%;
                    max-width: none !important;
                    margin-left: 0 !important;
                    margin-right: 0 !important;
                }
                .eep-moderation-admin-page .eep-moderation-queue-shell > header {
                    display: none;
                }
                @media (max-width: 900px) {
                    .eep-moderation-admin-page .eep-admin-hero {
                        grid-template-columns: 1fr;
                    }
                    .eep-moderation-admin-page .eep-admin-hero-action {
                        justify-self: start;
                    }
                }
            </style>
            <section class="eep-admin-hero">
                <div>
                    <span class="eep-admin-hero-kicker"><?php esc_html_e('Directory Operations', 'nexdirectory'); ?></span>
                    <h1><?php esc_html_e('Moderation Queue', 'nexdirectory'); ?></h1>
                    <p><?php echo esc_html(sprintf(__('Review pending %s, claim requests, and reports with fast approve/reject workflows.', 'nexdirectory'), strtolower((string) $plural_label))); ?></p>
                    <div class="eep-admin-hero-badges">
                        <span class="eep-admin-hero-badge"><span class="dashicons dashicons-yes-alt" aria-hidden="true"></span><?php esc_html_e('Bulk Actions', 'nexdirectory'); ?></span>
                        <span class="eep-admin-hero-badge"><span class="dashicons dashicons-flag" aria-hidden="true"></span><?php esc_html_e('Reports & Claims', 'nexdirectory'); ?></span>
                    </div>
                </div>
                <div class="eep-admin-hero-action">
                    <a class="button" href="<?php echo esc_url(admin_url('admin.php?page=eep-settings')); ?>">
                        <span class="dashicons dashicons-admin-settings" aria-hidden="true"></span>
                        <?php echo esc_html(sprintf(__('Back to %s Settings', 'nexdirectory'), $settings_brand_name)); ?>
                    </a>
                </div>
            </section>
            <?php echo wp_kses_post((string) $this->render_notice()); ?>
            <?php echo $this->render_moderation_queue(['pending_limit' => 30, 'reports_limit' => 30, 'admin_context' => 1]); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
        </div>
        <?php
    }


    public function render_admin_user_management_page() {
        if (!current_user_can('manage_options')) {
            return;
        }
        $this->enqueue_assets();
        $settings_brand_name = $this->get_white_label_brand_name();
        $ui_labels = method_exists($this, 'get_site_profile_ui_labels') ? (array) $this->get_site_profile_ui_labels() : [];
        $owner_plural = sanitize_text_field((string) ($ui_labels['owner_plural'] ?? __('Organizers', 'nexdirectory')));
        $plural_label = sanitize_text_field((string) ($ui_labels['plural'] ?? __('Events', 'nexdirectory')));
        ?>
        <div class="wrap eep-admin-premium eep-settings-premium eep-user-management-admin-page">
            <?php $this->render_admin_premium_shell_styles(); ?>
            <style id="eep-user-management-admin-shell">
                .eep-user-management-admin-page .eep-admin-hero {
                    display: grid;
                    grid-template-columns: minmax(0, 1fr) auto;
                    gap: 16px;
                    align-items: center;
                }
                .eep-user-management-admin-page .eep-admin-hero-badges {
                    display: flex;
                    flex-wrap: wrap;
                    gap: 8px;
                    margin-top: 10px;
                }
                .eep-user-management-admin-page .eep-admin-hero-badge {
                    display: inline-flex;
                    align-items: center;
                    gap: 6px;
                    padding: 4px 10px;
                    border-radius: 999px;
                    border: 1px solid rgba(148, 163, 184, .4);
                    background: rgba(15, 23, 42, .35);
                    color: #dbeafe;
                    font-size: 11px;
                    font-weight: 700;
                }
                .eep-user-management-admin-page .eep-admin-hero-action .button {
                    border-color: rgba(148, 163, 184, .48);
                    background: rgba(255, 255, 255, .1);
                    color: #fff;
                }
                .eep-user-management-admin-page .eep-admin-hero-action .button:hover,
                .eep-user-management-admin-page .eep-admin-hero-action .button:focus {
                    background: rgba(255, 255, 255, .16);
                    color: #fff;
                    border-color: rgba(148, 163, 184, .72);
                }
                .eep-user-management-admin-page .eep-my-events.eep-user-management {
                    max-width: none !important;
                    width: 100% !important;
                    margin: 0 !important;
                    border-radius: 0 !important;
                    padding-inline: 0 !important;
                }
                .eep-user-management-admin-page [data-eep-uniform-page="1"],
                .eep-user-management-admin-page .eep-uniform-page-gutter[data-eep-uniform-page="1"] {
                    padding-left: 0 !important;
                    padding-right: 0 !important;
                }
                .eep-user-management-admin-page .eep-user-management {
                    min-height: auto;
                    padding-bottom: 0;
                    background: transparent;
                }
                .eep-user-management-admin-page .eep-user-management-shell {
                    max-width: 100%;
                    width: 100%;
                    margin: 0;
                    padding: 0;
                }
                .eep-user-management-admin-page .eep-user-management-shell > section {
                    width: 100%;
                    max-width: none !important;
                    margin-left: 0 !important;
                    margin-right: 0 !important;
                }
                .eep-user-management-admin-page .eep-user-management-shell > header {
                    display: none;
                }
                @media (max-width: 900px) {
                    .eep-user-management-admin-page .eep-admin-hero {
                        grid-template-columns: 1fr;
                    }
                    .eep-user-management-admin-page .eep-admin-hero-action {
                        justify-self: start;
                    }
                }
            </style>
            <section class="eep-admin-hero">
                <div>
                    <span class="eep-admin-hero-kicker"><?php esc_html_e('Directory Operations', 'nexdirectory'); ?></span>
                    <h1><?php esc_html_e('User Management', 'nexdirectory'); ?></h1>
                    <p><?php echo esc_html(sprintf(__('Manage %1$s roles, trust level, and %2$s ownership actions from one control panel.', 'nexdirectory'), strtolower((string) $owner_plural), strtolower((string) $plural_label))); ?></p>
                    <div class="eep-admin-hero-badges">
                        <span class="eep-admin-hero-badge"><span class="dashicons dashicons-admin-users" aria-hidden="true"></span><?php esc_html_e('Role Controls', 'nexdirectory'); ?></span>
                        <span class="eep-admin-hero-badge"><span class="dashicons dashicons-yes-alt" aria-hidden="true"></span><?php esc_html_e('Verification Tools', 'nexdirectory'); ?></span>
                    </div>
                </div>
                <div class="eep-admin-hero-action">
                    <a class="button" href="<?php echo esc_url(admin_url('admin.php?page=eep-settings')); ?>">
                        <span class="dashicons dashicons-admin-settings" aria-hidden="true"></span>
                        <?php echo esc_html(sprintf(__('Back to %s Settings', 'nexdirectory'), $settings_brand_name)); ?>
                    </a>
                </div>
            </section>
            <?php echo wp_kses_post((string) $this->render_notice()); ?>
            <?php echo $this->render_user_management(['limit' => 100, 'admin_context' => 1]); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
        </div>
        <?php
    }


    public function handle_send_test_email() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (
            !isset($_POST['eep_send_test_email_nonce'])
            || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_send_test_email_nonce'])), 'eep_send_test_email')
        ) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }
        $to = sanitize_email((string) wp_unslash($_POST['eep_test_email_to'] ?? ''));
        if ($to === '') {
            $to = sanitize_email((string) get_option('admin_email'));
        }
        if (!is_email($to)) {
            $this->redirect_with_message(
                admin_url('admin.php?page=eep-settings#eep-tab-advanced'),
                __('Enter a valid recipient email for test delivery.', 'nexdirectory'),
                'error'
            );
        }
        $brand_name = $this->get_white_label_brand_name();
        $subject = sprintf(
            __('%1$s SMTP Test (%2$s)', 'nexdirectory'),
            $brand_name,
            wp_date('Y-m-d H:i:s')
        );
        $body = sprintf(
            __('This is a test email from %1$s on %2$s. If you received this message, SMTP delivery is working.', 'nexdirectory'),
            $brand_name,
            home_url('/')
        );
        $sent = (bool) $this->send_platform_email($to, $subject, '', [
            'fallback_text' => $body,
            'email_heading' => __('SMTP Test Email', 'nexdirectory'),
        ]);
        if ($sent) {
            $this->append_runtime_log('info', 'SMTP test email sent', ['to' => $to]);
            $this->redirect_with_message(
                admin_url('admin.php?page=eep-settings#eep-tab-advanced'),
                sprintf(__('Test email sent to %s.', 'nexdirectory'), $to),
                'success'
            );
        }
        $this->append_runtime_log('error', 'SMTP test email failed', ['to' => $to]);
        $this->redirect_with_message(
            admin_url('admin.php?page=eep-settings#eep-tab-advanced'),
            __('Test email failed. Check SMTP settings, provider restrictions, and runtime logs.', 'nexdirectory'),
            'error'
        );
    }

    public function handle_test_map_connection() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (
            !isset($_POST['eep_test_map_connection_nonce'])
            || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_test_map_connection_nonce'])), 'eep_test_map_connection')
        ) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }

        $result = $this->run_settings_map_connection_test();
        if (!empty($result['ok'])) {
            $message = sanitize_text_field((string) ($result['message'] ?? __('Map connection test passed.', 'nexdirectory')));
            $this->append_runtime_log('info', 'Settings map connection test passed', [
                'message' => $message,
            ]);
            $this->redirect_with_message(
                admin_url('admin.php?page=eep-settings#eep-tab-design-maps--layouts'),
                $message,
                'success'
            );
        }

        $message = sanitize_text_field((string) ($result['message'] ?? __('Map connection test failed.', 'nexdirectory')));
        $this->append_runtime_log('error', 'Settings map connection test failed', [
            'message' => $message,
        ]);
        $this->redirect_with_message(
            admin_url('admin.php?page=eep-settings#eep-tab-design-maps--layouts'),
            $message,
            'error'
        );
    }

    public function handle_test_captcha_connection() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (
            !isset($_POST['eep_test_captcha_connection_nonce'])
            || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_test_captcha_connection_nonce'])), 'eep_test_captcha_connection')
        ) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }

        $result = $this->run_settings_captcha_connection_test();
        if (!empty($result['ok'])) {
            $message = sanitize_text_field((string) ($result['message'] ?? __('reCAPTCHA test passed.', 'nexdirectory')));
            $this->append_runtime_log('info', 'Settings captcha connection test passed', [
                'message' => $message,
            ]);
            $this->redirect_with_message(
                admin_url('admin.php?page=eep-settings#eep-tab-apis'),
                $message,
                'success'
            );
        }

        $message = sanitize_text_field((string) ($result['message'] ?? __('reCAPTCHA test failed.', 'nexdirectory')));
        $this->append_runtime_log('error', 'Settings captcha connection test failed', [
            'message' => $message,
        ]);
        $this->redirect_with_message(
            admin_url('admin.php?page=eep-settings#eep-tab-apis'),
            $message,
            'error'
        );
    }

    public function handle_test_routing_connection() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (
            !isset($_POST['eep_test_routing_connection_nonce'])
            || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_test_routing_connection_nonce'])), 'eep_test_routing_connection')
        ) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }

        $profile_key = method_exists($this, 'get_site_profile_key')
            ? sanitize_key((string) $this->get_site_profile_key())
            : 'events';
        $this->ensure_default_pages();
        $this->sync_route_options_to_existing_pages($profile_key);
        $health = $this->get_settings_routing_health($profile_key);
        $issues = [];
        if (!empty($health['issues']) && is_array($health['issues'])) {
            foreach ((array) $health['issues'] as $issue) {
                $issue = sanitize_text_field((string) $issue);
                if ($issue !== '') {
                    $issues[] = $issue;
                }
            }
        }

        if (!empty($health['connected'])) {
            $message = sanitize_text_field((string) ($health['summary'] ?? __('Routing test passed.', 'nexdirectory')));
            $this->append_runtime_log('info', 'Settings routing connection test passed', [
                'message' => $message,
            ]);
            $this->redirect_with_message(
                admin_url('admin.php?page=eep-settings#eep-tab-routing'),
                $message,
                'success'
            );
        }

        $base_message = sanitize_text_field((string) ($health['summary'] ?? __('Routing test failed.', 'nexdirectory')));
        if (!empty($issues)) {
            $base_message .= ' ' . sprintf(
                __('Issues: %s', 'nexdirectory'),
                implode(' | ', array_slice($issues, 0, 3))
            );
        }

        $this->append_runtime_log('error', 'Settings routing connection test failed', [
            'message' => $base_message,
        ]);
        $this->redirect_with_message(
            admin_url('admin.php?page=eep-settings#eep-tab-routing'),
            $base_message,
            'error'
        );
    }


    public function handle_chatbot_test_connection() {
        if (function_exists('epw_fs') && !epw_fs()->can_use_premium_code__premium_only()) {
            $this->redirect_with_message(
                admin_url('admin.php?page=eep-settings#eep-tab-chatbot'),
                __('AI Listing Chatbot is available on premium plans only.', 'nexdirectory'),
                'error'
            );
        }
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (
            !isset($_POST['eep_chatbot_test_connection_nonce'])
            || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_chatbot_test_connection_nonce'])), 'eep_chatbot_test_connection')
        ) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }

        $result = $this->chatbot_test_connection();
        if (is_wp_error($result)) {
            $this->append_runtime_log('error', 'Chatbot OpenAI connection test failed', [
                'message' => $result->get_error_message(),
            ]);
            $this->redirect_with_message(
                admin_url('admin.php?page=eep-settings#eep-tab-chatbot'),
                sprintf(
                    __('Chatbot connection test failed: %s', 'nexdirectory'),
                    $result->get_error_message()
                ),
                'error'
            );
        }

        $test_message = sanitize_text_field((string) ($result['message'] ?? 'OK'));
        if (function_exists('mb_substr')) {
            $test_message = (string) mb_substr($test_message, 0, 140);
        } else {
            $test_message = (string) substr($test_message, 0, 140);
        }
        $dim = absint((int) ($result['embedding_dimensions'] ?? 0));
        $this->append_runtime_log('info', 'Chatbot OpenAI connection test passed', [
            'message' => $test_message,
            'embedding_dimensions' => $dim,
        ]);
        $this->redirect_with_message(
            admin_url('admin.php?page=eep-settings#eep-tab-chatbot'),
            sprintf(
                __('Chatbot OpenAI test passed. Embedding dimensions: %1$d. Response: %2$s', 'nexdirectory'),
                $dim,
                $test_message
            ),
            'success'
        );
    }


    public function handle_chatbot_reindex_now() {
        if (function_exists('epw_fs') && !epw_fs()->can_use_premium_code__premium_only()) {
            $this->redirect_with_message(
                admin_url('admin.php?page=eep-settings#eep-tab-chatbot'),
                __('AI Listing Chatbot is available on premium plans only.', 'nexdirectory'),
                'error'
            );
        }
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (
            !isset($_POST['eep_chatbot_reindex_now_nonce'])
            || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_chatbot_reindex_now_nonce'])), 'eep_chatbot_reindex_now')
        ) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }

        $summary = $this->run_chatbot_reindex(true);
        if (is_wp_error($summary)) {
            $this->append_runtime_log('error', 'Chatbot manual reindex failed', [
                'message' => $summary->get_error_message(),
            ]);
            $this->redirect_with_message(
                admin_url('admin.php?page=eep-settings#eep-tab-chatbot'),
                sprintf(
                    __('Chatbot re-index failed: %s', 'nexdirectory'),
                    $summary->get_error_message()
                ),
                'error'
            );
        }

        $summary_text = sprintf(
            'indexed=%d skipped=%d failed=%d duration_ms=%d catalog_types=%d catalog_topics=%d',
            (int) ($summary['indexed'] ?? 0),
            (int) ($summary['skipped'] ?? 0),
            (int) ($summary['failed'] ?? 0),
            (int) ($summary['duration_ms'] ?? 0),
            (int) ($summary['catalog_types'] ?? 0),
            (int) ($summary['catalog_topics'] ?? 0)
        );
        update_option('eep_chatbot_last_reindex_summary_text', $summary_text, false);
        $this->append_runtime_log('info', 'Chatbot manual reindex complete', [
            'summary' => $summary_text,
            'errors' => (array) ($summary['errors'] ?? []),
        ]);

        $error_note = '';
        $errors = is_array($summary['errors'] ?? null) ? (array) $summary['errors'] : [];
        if (!empty($errors)) {
            $error_note = ' ' . sprintf(
                __('First issue: %s', 'nexdirectory'),
                sanitize_text_field((string) $errors[0])
            );
        }
        $this->redirect_with_message(
            admin_url('admin.php?page=eep-settings#eep-tab-chatbot'),
            sprintf(
                __('Chatbot embeddings re-index complete. Indexed: %1$d, Skipped: %2$d, Failed: %3$d. Knowledge map types: %4$d, topics: %5$d.', 'nexdirectory'),
                (int) ($summary['indexed'] ?? 0),
                (int) ($summary['skipped'] ?? 0),
                (int) ($summary['failed'] ?? 0),
                (int) ($summary['catalog_types'] ?? 0),
                (int) ($summary['catalog_topics'] ?? 0)
            ) . $error_note,
            ((int) ($summary['failed'] ?? 0) > 0 ? 'error' : 'success')
        );
    }


    public function handle_chatbot_clear_index() {
        if (function_exists('epw_fs') && !epw_fs()->can_use_premium_code__premium_only()) {
            $this->redirect_with_message(
                admin_url('admin.php?page=eep-settings#eep-tab-chatbot'),
                __('AI Listing Chatbot is available on premium plans only.', 'nexdirectory'),
                'error'
            );
        }
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (
            !isset($_POST['eep_chatbot_clear_index_nonce'])
            || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_chatbot_clear_index_nonce'])), 'eep_chatbot_clear_index')
        ) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }

        $this->clear_chatbot_index();
        update_option('eep_chatbot_last_indexed_at', '', false);
        update_option('eep_chatbot_last_query_at', '', false);
        update_option('eep_chatbot_query_count', 0, false);
        $this->append_runtime_log('info', 'Chatbot embedding index cleared');
        $this->redirect_with_message(
            admin_url('admin.php?page=eep-settings#eep-tab-chatbot'),
            __('Chatbot embedding index cleared.', 'nexdirectory'),
            'success'
        );
    }


    public function handle_regenerate_extension_app_pass() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (
            !isset($_POST['eep_regenerate_extension_app_pass_nonce'])
            || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_regenerate_extension_app_pass_nonce'])), 'eep_regenerate_extension_app_pass')
        ) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }

        $new_pass = wp_generate_password(48, false, false);
        update_option('eep_extension_app_pass', $new_pass, false);
        $this->append_runtime_log('info', 'Extension app pass regenerated', [
            'user_id' => (string) get_current_user_id(),
        ]);
        $this->redirect_with_message(
            admin_url('admin.php?page=eep-settings#eep-tab-advanced--extension'),
            __('Extension App Pass regenerated. Update your Chrome extension credentials.', 'nexdirectory'),
            'success'
        );
    }


    public function handle_generate_pages() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (
            !isset($_POST['eep_generate_pages_nonce'])
            || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_generate_pages_nonce'])), 'eep_generate_pages')
        ) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }
        $redirect_url = admin_url('admin.php?page=eep-settings#eep-tab-general');
        $requested_redirect = isset($_POST['eep_redirect_to']) ? esc_url_raw((string) wp_unslash($_POST['eep_redirect_to'])) : '';
        if ($requested_redirect !== '') {
            $redirect_url = wp_validate_redirect($requested_redirect, $redirect_url);
        }
        $this->ensure_default_pages();
        $profile_key = $this->get_site_profile_key();
        $this->sync_route_options_to_existing_pages($profile_key);
        $this->redirect_with_message(
            $redirect_url,
            __('Missing pages were generated and routing URLs were refreshed for the active template. This can take up to 5 minutes to fully appear across cache/SPA states. Please be patient.', 'nexdirectory'),
            'success'
        );
    }


    public function handle_mark_onboarding_complete() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (!isset($_POST['eep_onboarding_nonce']) || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_onboarding_nonce'])), 'eep_mark_onboarding_complete')) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }
        update_option('eep_onboarding_complete', '1', false);
        $this->redirect_with_message(
            admin_url('admin.php?page=eep-onboarding'),
            __('Onboarding marked as complete.', 'nexdirectory'),
            'success'
        );
    }


    private function render_admin_premium_shell_styles() {
        ?>
        <style id="eep-admin-premium-shell">
            .eep-admin-premium { max-width: 1280px; }
            .eep-admin-premium .eep-admin-hero {
                border: 1px solid #d8deeb;
                border-radius: 16px;
                padding: 18px 20px;
                margin: 10px 0 14px;
                background: linear-gradient(130deg, #0f172a 0%, #172554 52%, #1e293b 100%);
                color: #fff;
                box-shadow: 0 12px 30px rgba(15, 23, 42, .18);
            }
            .eep-admin-premium .eep-admin-hero h1 { margin: 2px 0 8px; color: #fff; }
            .eep-admin-premium .eep-admin-hero p { margin: 0; color: rgba(255, 255, 255, .88); max-width: 920px; line-height: 1.5; }
            .eep-admin-premium .eep-admin-hero-kicker {
                display: inline-block;
                margin: 0 0 6px;
                color: #fdba74;
                text-transform: uppercase;
                letter-spacing: .08em;
                font-size: 11px;
                font-weight: 700;
            }
            .eep-admin-premium .eep-admin-panel {
                border: 1px solid #d9dfe9;
                border-radius: 14px;
                background: linear-gradient(180deg, #fff 0%, #f8faff 100%);
                padding: 14px 16px;
                box-shadow: 0 10px 24px rgba(15, 23, 42, .08);
                margin-bottom: 14px;
            }
            .eep-admin-premium .eep-admin-panel h2 {
                margin-top: 0;
                display: flex;
                align-items: center;
                gap: 8px;
            }
            .eep-admin-premium .eep-admin-panel h2 .dashicons { color: #ff5e14; }
            .eep-admin-premium .eep-admin-toolbar {
                display: flex;
                gap: 10px;
                align-items: center;
                flex-wrap: wrap;
                margin: 0 0 12px;
            }
            .eep-admin-premium .eep-admin-grid {
                display: grid;
                grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
                gap: 10px;
            }
            .eep-admin-premium .eep-admin-stat-card {
                border: 1px solid #e2e8f0;
                border-radius: 12px;
                background: #fff;
                padding: 12px 13px;
            }
            .eep-admin-premium .eep-admin-stat-card .eep-admin-stat-label {
                margin: 0 0 6px;
                color: #475569;
                font-size: 12px;
                font-weight: 600;
            }
            .eep-admin-premium .eep-admin-stat-card .eep-admin-stat-value {
                margin: 0;
                color: #0f172a;
                font-size: 24px;
                font-weight: 700;
                line-height: 1.1;
            }
            .eep-admin-premium .eep-admin-table-wrap {
                overflow-x: auto;
                border-radius: 10px;
                border: 1px solid #e2e8f0;
                background: #fff;
            }
            .eep-admin-premium .widefat {
                margin: 0;
                border: 0;
                box-shadow: none;
                background: #fff;
            }
            .eep-admin-premium .widefat thead th {
                background: #f8fafc;
                color: #0f172a;
                font-weight: 600;
            }
            .eep-admin-premium .button-primary {
                background: #ff5e14;
                border-color: #ff5e14;
            }
            .eep-admin-premium .button-primary:hover,
            .eep-admin-premium .button-primary:focus {
                background: #e04f0d;
                border-color: #e04f0d;
            }
            .eep-admin-premium .eep-onboarding-steps {
                display: flex;
                gap: 8px;
                flex-wrap: wrap;
                margin: 0;
                padding: 0;
                list-style: none;
            }
            .eep-admin-premium .eep-onboarding-step-link {
                display: inline-flex;
                align-items: center;
                justify-content: center;
                width: 32px;
                height: 32px;
                border-radius: 999px;
                color: #fff;
                font-weight: 700;
                text-decoration: none;
            }
            .eep-admin-premium .eep-onboarding-step-link.is-active { background: #ff5e14; }
            .eep-admin-premium .eep-onboarding-step-link.is-complete { background: #16a34a; }
            .eep-admin-premium .eep-onboarding-step-link.is-pending { background: #94a3b8; }
            .eep-admin-premium .eep-onboarding-step-label { font-weight: 600; color: #0f172a; }
            .eep-settings-premium .eep-settings-tabs {
                margin: 0 0 14px;
                padding-bottom: 0;
                border-bottom: 0;
                gap: 8px;
            }
            .eep-settings-premium .eep-settings-tabs .nav-tab {
                margin: 0;
                border: 1px solid #d9dfe9;
                border-radius: 999px;
                background: #fff;
                color: #334155;
                font-weight: 600;
                padding: 8px 14px;
            }
            .eep-settings-premium .eep-settings-tabs .nav-tab:hover {
                border-color: #ff5e14;
                color: #ff5e14;
            }
            .eep-settings-premium .eep-settings-tabs .nav-tab-active {
                border-color: #0f172a;
                background: #0f172a;
                color: #fff;
            }
            .eep-settings-premium .eep-settings-tabs .nav-tab-active:hover {
                border-color: #0f172a;
                color: #fff;
            }
            .eep-metrics-page .postbox {
                border: 1px solid #e2e8f0 !important;
                border-radius: 12px;
                box-shadow: none !important;
                background: #fff;
            }
            @media (max-width: 900px) {
                .eep-admin-premium .eep-admin-hero { padding: 16px; }
                .eep-admin-premium .eep-admin-panel { padding: 12px; }
                .eep-settings-premium .eep-settings-tabs .nav-tab { width: 100%; text-align: center; }
            }
        </style>
        <?php
    }

    private function render_admin_template($template_file, array $context = []) {
        $template_slug = ltrim((string) $template_file, '/');
        if ($template_slug === '') {
            return '';
        }

        $template_path = plugin_dir_path(EEP_PLUGIN_FILE) . 'templates/admin/' . $template_slug;
        if (!is_readable($template_path)) {
            return '';
        }

        ob_start();
        extract($context, EXTR_SKIP);
        include $template_path;
        return (string) ob_get_clean();
    }


    public function render_onboarding_page() {
        if (!current_user_can('manage_options')) {
            return;
        }
        $brand_name = $this->get_white_label_brand_name();
        $done = (string) get_option('eep_onboarding_complete', '0') === '1';
        $ui_labels = method_exists($this, 'get_site_profile_ui_labels') ? (array) $this->get_site_profile_ui_labels() : [];
        $singular_label = sanitize_text_field((string) ($ui_labels['singular'] ?? __('Listing', 'nexdirectory')));
        $plural_label = sanitize_text_field((string) ($ui_labels['plural'] ?? __('Listings', 'nexdirectory')));
        $step = isset($_GET['step']) ? absint((int) $_GET['step']) : 1;
        if ($step < 1 || $step > 6) {
            $step = 1;
        }
        $wizard_steps = [
            1 => [
                'title' => __('Select Platform Type', 'nexdirectory'),
                'icon' => 'fa-server',
                'description' => __('Choose how your platform operates: multi-user directory mode, or single-organisation mode.', 'nexdirectory'),
            ],
            2 => [
                'title' => __('Generate Core Pages', 'nexdirectory'),
                'icon' => 'fa-file-alt',
                'description' => sprintf(__('Create or refresh required pages for %1$s, submission, account, and routing.', 'nexdirectory'), $plural_label),
            ],
            3 => [
                'title' => __('Site Identity', 'nexdirectory'),
                'icon' => 'fa-paint-brush',
                'description' => __('Set your site name and brand accent so your UI is consistent from day one.', 'nexdirectory'),
            ],
            4 => [
                'title' => __('Import Demo Content', 'nexdirectory'),
                'icon' => 'fa-box-open',
                'description' => __('Load starter data so you can explore features quickly, then replace with your live content.', 'nexdirectory'),
            ],
            5 => [
                'title' => __('Set Homepage', 'nexdirectory'),
                'icon' => 'fa-house',
                'description' => __('Set a static homepage for your site. We recommend using What\'s New.', 'nexdirectory'),
            ],
            6 => [
                'title' => __('Launch Dashboard', 'nexdirectory'),
                'icon' => 'fa-rocket',
                'description' => __('Finish onboarding and jump straight into your admin dashboard.', 'nexdirectory'),
            ],
        ];
        $operating_mode = sanitize_key((string) get_option('eep_onboarding_operating_mode', 'user'));
        if (!in_array($operating_mode, ['user', 'single'], true)) {
            $operating_mode = 'user';
        }
        $site_name = sanitize_text_field((string) get_option('blogname', get_bloginfo('name')));
        $accent_color = sanitize_hex_color((string) get_option('eep_style_accent_color', '#4F46E5')) ?: '#4F46E5';
        $demo_limit_context = (array) $this->get_demo_limit_admin_context();
        $demo_mode_enabled = !empty($demo_limit_context['is_demo_mode']);
        $demo_limit_value = max(1, (int) ($demo_limit_context['limit'] ?? 3));
        $demo_used_value = max(0, (int) ($demo_limit_context['used'] ?? 0));
        $demo_remaining_value = max(0, (int) ($demo_limit_context['remaining'] ?? 0));
        $demo_is_at_limit = !empty($demo_limit_context['is_at_limit']);

        echo $this->render_admin_template('onboarding.php', [
            'brand_name' => $brand_name,
            'done' => $done,
            'singular_label' => $singular_label,
            'plural_label' => $plural_label,
            'step' => $step,
            'wizard_steps' => $wizard_steps,
            'operating_mode' => $operating_mode,
            'site_name' => $site_name,
            'accent_color' => $accent_color,
            'save_preferences_action' => esc_url(admin_url('admin-post.php')),
            'dashboard_url' => esc_url(admin_url('admin.php?page=eep-dashboard')),
            'is_demo_mode' => $demo_mode_enabled,
            'demo_event_limit' => $demo_limit_value,
            'demo_event_used' => $demo_used_value,
            'demo_event_remaining' => $demo_remaining_value,
            'demo_event_limit_reached' => $demo_is_at_limit,
            'upgrade_url' => (string) ($demo_limit_context['upgrade_url'] ?? 'https://nexdirectory.com/purchase'),
            'license_url' => (string) ($demo_limit_context['license_url'] ?? admin_url('admin.php?page=eep-settings#eep-tab-monetization--boost-packages')),
            'license_label' => (string) ($demo_limit_context['license_label'] ?? __('Activate License', 'nexdirectory')),
        ]);
    }

    public function handle_onboarding_save_preferences() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (!isset($_POST['eep_onboarding_save_nonce']) || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_onboarding_save_nonce'])), 'eep_onboarding_save_preferences')) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }

        $operating_mode = isset($_POST['eep_onboarding_operating_mode']) ? sanitize_key((string) wp_unslash($_POST['eep_onboarding_operating_mode'])) : 'user';
        if (!in_array($operating_mode, ['user', 'single'], true)) {
            $operating_mode = 'user';
        }
        update_option('eep_onboarding_operating_mode', $operating_mode, false);

        $site_name = isset($_POST['eep_onboarding_site_name']) ? sanitize_text_field((string) wp_unslash($_POST['eep_onboarding_site_name'])) : '';
        if ($site_name !== '') {
            update_option('blogname', $site_name);
            if (trim((string) get_option('eep_company_brand_name', '')) === '') {
                update_option('eep_company_brand_name', $site_name, false);
            }
        }

        $accent_color = isset($_POST['eep_onboarding_accent_color']) ? sanitize_hex_color((string) wp_unslash($_POST['eep_onboarding_accent_color'])) : '';
        if (is_string($accent_color) && $accent_color !== '') {
            update_option('eep_style_accent_color', $accent_color, false);
        }

        $step = isset($_POST['eep_onboarding_step']) ? absint((int) wp_unslash($_POST['eep_onboarding_step'])) : 1;
        if ($step < 1 || $step > 6) {
            $step = 1;
        }

        $this->redirect_with_message(
            eep_add_query_arg(['page' => 'eep-onboarding', 'step' => $step], admin_url('admin.php')),
            __('Onboarding preferences saved.', 'nexdirectory'),
            'success'
        );
    }

    public function handle_set_onboarding_homepage() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        if (
            !isset($_POST['eep_set_onboarding_homepage_nonce'])
            || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_set_onboarding_homepage_nonce'])), 'eep_set_onboarding_homepage')
        ) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }

        $step = isset($_POST['eep_onboarding_step']) ? absint((int) wp_unslash($_POST['eep_onboarding_step'])) : 5;
        if ($step < 1 || $step > 6) {
            $step = 5;
        }
        $redirect_url = eep_add_query_arg(['page' => 'eep-onboarding', 'step' => $step], admin_url('admin.php'));

        $whats_new_url = (string) $this->get_platform_page_url(
            'eep_page_whats_new_url',
            ['whats-new'],
            home_url('/whats-new/')
        );
        $whats_new_page_id = absint((int) url_to_postid($whats_new_url));
        if ($whats_new_page_id <= 0) {
            $whats_new_page = get_page_by_path('whats-new', OBJECT, 'page');
            if ($whats_new_page instanceof WP_Post) {
                $whats_new_page_id = absint((int) $whats_new_page->ID);
            }
        }

        if ($whats_new_page_id <= 0) {
            $this->redirect_with_message(
                $redirect_url,
                __('Could not locate the What\'s New page yet. Generate core pages first, then try again.', 'nexdirectory'),
                'error'
            );
        }

        update_option('show_on_front', 'page');
        update_option('page_on_front', $whats_new_page_id);
        if ((int) get_option('page_for_posts', 0) === $whats_new_page_id) {
            update_option('page_for_posts', 0);
        }

        $this->redirect_with_message(
            $redirect_url,
            __('Homepage set to What\'s New successfully.', 'nexdirectory'),
            'success'
        );
    }


    public function render_diagnostics_page() {
        if (!current_user_can('manage_options')) {
            return;
        }
        $brand_name = $this->get_white_label_brand_name();
        global $wpdb;
        $memory_limit = (string) ini_get('memory_limit');
        $max_execution_time = (string) ini_get('max_execution_time');
        $upload_max_filesize = (string) ini_get('upload_max_filesize');
        $post_max_size = (string) ini_get('post_max_size');
        $cron_next = wp_next_scheduled('eep_event_reminder_cron');
        $action_scheduler_available = function_exists('as_schedule_single_action') && function_exists('as_next_scheduled_action');
        $action_scheduler_enabled = (string) get_option('eep_use_action_scheduler', '0') === '1';
        $as_next = '';
        if ($action_scheduler_available && function_exists('as_next_scheduled_action')) {
            $next_action = as_next_scheduled_action('eep_event_reminder_cron', [], 'eep');
            if (!empty($next_action)) {
                $as_next = wp_date(get_option('date_format') . ' ' . get_option('time_format'), (int) $next_action);
            }
        }
        $upload_limits = $this->get_upload_limits();
        $rest_url = esc_url_raw(rest_url('eep/v1/map-events'));
        $postmeta_table = (string) $wpdb->postmeta;
        $posts_table = (string) $wpdb->posts;
        $meta_indexes = $wpdb->get_results("SHOW INDEX FROM {$postmeta_table}", ARRAY_A);
        $post_indexes = $wpdb->get_results("SHOW INDEX FROM {$posts_table}", ARRAY_A);
        $meta_index_names = array_values(array_unique(array_map(static function ($row) {
            return (string) ($row['Key_name'] ?? '');
        }, is_array($meta_indexes) ? $meta_indexes : [])));
        $post_index_names = array_values(array_unique(array_map(static function ($row) {
            return (string) ($row['Key_name'] ?? '');
        }, is_array($post_indexes) ? $post_indexes : [])));
        ?>
        <div class="wrap">
            <h1><?php echo esc_html(sprintf(__('%s Diagnostics', 'nexdirectory'), $brand_name)); ?></h1>
            <table class="widefat striped" style="max-width:980px;">
                <thead><tr><th><?php esc_html_e('Check', 'nexdirectory'); ?></th><th><?php esc_html_e('Value', 'nexdirectory'); ?></th></tr></thead>
                <tbody>
                    <tr><td><?php esc_html_e('Plugin Version', 'nexdirectory'); ?></td><td><?php echo esc_html((string) self::VERSION); ?></td></tr>
                    <tr><td><?php esc_html_e('DB Schema Version', 'nexdirectory'); ?></td><td><?php echo esc_html((string) EEP_DB_VERSION); ?></td></tr>
                    <tr><td><?php esc_html_e('WordPress Version', 'nexdirectory'); ?></td><td><?php echo esc_html((string) get_bloginfo('version')); ?></td></tr>
                    <tr><td><?php esc_html_e('PHP Version', 'nexdirectory'); ?></td><td><?php echo esc_html((string) PHP_VERSION); ?></td></tr>
                    <tr><td><?php esc_html_e('Memory Limit', 'nexdirectory'); ?></td><td><?php echo esc_html($memory_limit); ?></td></tr>
                    <tr><td><?php esc_html_e('Max Execution Time', 'nexdirectory'); ?></td><td><?php echo esc_html($max_execution_time . 's'); ?></td></tr>
                    <tr><td><?php esc_html_e('Upload Max Filesize', 'nexdirectory'); ?></td><td><?php echo esc_html($upload_max_filesize); ?></td></tr>
                    <tr><td><?php esc_html_e('Post Max Size', 'nexdirectory'); ?></td><td><?php echo esc_html($post_max_size); ?></td></tr>
                    <tr><td><?php esc_html_e('Configured Cover Upload Limit', 'nexdirectory'); ?></td><td><?php echo esc_html((string) ((int) ($upload_limits['cover_max_kb'] ?? 500)) . ' KB'); ?></td></tr>
                    <tr><td><?php esc_html_e('Configured Gallery Upload Limit', 'nexdirectory'); ?></td><td><?php echo esc_html((string) ((int) ($upload_limits['gallery_max_kb'] ?? 2000)) . ' KB'); ?></td></tr>
                    <tr><td><?php esc_html_e('Configured Gallery Max Files', 'nexdirectory'); ?></td><td><?php echo esc_html((string) ((int) ($upload_limits['gallery_max_files'] ?? 10))); ?></td></tr>
                    <tr><td><?php esc_html_e('Reminder Cron Next Run', 'nexdirectory'); ?></td><td><?php echo esc_html($cron_next ? wp_date(get_option('date_format') . ' ' . get_option('time_format'), (int) $cron_next) : __('Not scheduled', 'nexdirectory')); ?></td></tr>
                    <tr><td><?php esc_html_e('Action Scheduler Available', 'nexdirectory'); ?></td><td><?php echo esc_html($action_scheduler_available ? __('Yes', 'nexdirectory') : __('No', 'nexdirectory')); ?></td></tr>
                    <tr><td><?php esc_html_e('Action Scheduler Enabled', 'nexdirectory'); ?></td><td><?php echo esc_html($action_scheduler_enabled ? __('Yes', 'nexdirectory') : __('No', 'nexdirectory')); ?></td></tr>
                    <tr><td><?php esc_html_e('Action Scheduler Next Reminder Run', 'nexdirectory'); ?></td><td><?php echo esc_html($as_next !== '' ? $as_next : __('Not scheduled', 'nexdirectory')); ?></td></tr>
                    <tr><td><?php esc_html_e('Uninstall Data Purge', 'nexdirectory'); ?></td><td><?php echo esc_html((string) get_option('eep_uninstall_remove_data', '0') === '1' ? __('Enabled', 'nexdirectory') : __('Disabled', 'nexdirectory')); ?></td></tr>
                    <tr><td><?php esc_html_e('REST Endpoint', 'nexdirectory'); ?></td><td><code><?php echo esc_html($rest_url); ?></code></td></tr>
                    <tr><td><?php esc_html_e('Meta Indexes', 'nexdirectory'); ?></td><td><code><?php echo esc_html(implode(', ', $meta_index_names)); ?></code></td></tr>
                    <tr><td><?php esc_html_e('Posts Indexes', 'nexdirectory'); ?></td><td><code><?php echo esc_html(implode(', ', $post_index_names)); ?></code></td></tr>
                </tbody>
            </table>
            <p style="max-width:980px;margin-top:10px;"><?php esc_html_e('If moderation/import/map performance is degraded, check index rows above and review runtime logs under Settings > Logs.', 'nexdirectory'); ?></p>
        </div>
        <?php
    }


    public function render_metrics_page() {
        if (!current_user_can('manage_options')) {
            return;
        }
        echo $this->render_admin_template('metrics/page.php');
    }


    private function find_user_for_owner_transfer($identifier = '') {
        $identifier = sanitize_text_field((string) $identifier);
        if ($identifier === '') {
            return null;
        }
        if (is_numeric($identifier)) {
            $candidate = get_user_by('id', absint((int) $identifier));
            if ($candidate instanceof WP_User) {
                return $candidate;
            }
        }
        if (is_email($identifier)) {
            $candidate = get_user_by('email', sanitize_email($identifier));
            if ($candidate instanceof WP_User) {
                return $candidate;
            }
        }
        $candidate = get_user_by('login', $identifier);
        if ($candidate instanceof WP_User) {
            return $candidate;
        }
        $candidate = get_user_by('slug', eep_sanitize_title($identifier));
        if ($candidate instanceof WP_User) {
            return $candidate;
        }
        return null;
    }


    private function get_transfer_owner_admin_url($post_id) {
        $post_id = absint((int) $post_id);
        return (string) wp_nonce_url(eep_add_query_arg([
            'action' => 'eep_open_transfer_owner',
            'post_id' => $post_id,
        ], admin_url('admin-post.php')), 'eep_transfer_owner_' . $post_id);
    }


    public function handle_open_transfer_owner() {
        if (!is_admin() || !is_user_logged_in() || !current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }

        $post_id = isset($_GET['post_id']) ? absint((int) wp_unslash($_GET['post_id'])) : 0;
        if ($post_id <= 0 || get_post_type($post_id) !== self::POST_TYPE) {
            wp_die(__('Invalid listing selected.', 'nexdirectory'));
        }

        check_admin_referer('eep_transfer_owner_' . $post_id);

        require_once ABSPATH . 'wp-admin/admin-header.php';
        $this->render_transfer_owner_page();
        require_once ABSPATH . 'wp-admin/admin-footer.php';
        exit;
    }


    public function render_transfer_owner_page() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        $post_id = isset($_GET['post_id']) ? absint((int) wp_unslash($_GET['post_id'])) : 0;
        if ($post_id <= 0) {
            $post_id = isset($_GET['post']) ? absint((int) wp_unslash($_GET['post'])) : 0;
        }
        if ($post_id <= 0 || get_post_type($post_id) !== self::POST_TYPE) {
            wp_die(__('Invalid listing selected.', 'nexdirectory'));
        }

        $post = get_post($post_id);
        if (!$post instanceof WP_Post) {
            wp_die(__('Listing not found.', 'nexdirectory'));
        }
        $owner_id = (int) $post->post_author;
        $owner_user = $owner_id > 0 ? get_user_by('id', $owner_id) : null;
        $owner_name = $owner_user instanceof WP_User
            ? (string) ($owner_user->display_name ?: $owner_user->user_login)
            : ('#' . (string) $owner_id);
        $owner_email = $owner_user instanceof WP_User ? (string) $owner_user->user_email : '';
        $status = (string) get_post_status($post_id);
        $edit_frontend_url = eep_add_query_arg('edit_event_id', $post_id, $this->get_platform_page_url(
            'eep_page_submit_event_url',
            $this->get_profile_route_slugs('submit'),
            $this->get_profile_route_default_url('submit')
        ));
        $edit_backend_url = eep_add_query_arg([
            'post' => $post_id,
            'action' => 'edit',
            'eep_wp_editor' => '1',
        ], admin_url('post.php'));
        $suggested_users = get_users([
            'number' => 120,
            'orderby' => 'display_name',
            'order' => 'ASC',
            'fields' => ['ID', 'display_name', 'user_login', 'user_email'],
        ]);
        ?>
        <div class="wrap">
            <h1><?php esc_html_e('Change Listing Owner', 'nexdirectory'); ?></h1>
            <?php echo wp_kses_post((string) $this->render_notice()); ?>
            <div class="card" style="max-width:980px;padding:18px;">
                <h2 style="margin-top:0;"><?php echo esc_html((string) get_the_title($post_id)); ?></h2>
                <p>
                    <strong><?php esc_html_e('Current Owner:', 'nexdirectory'); ?></strong>
                    <?php echo esc_html($owner_name); ?>
                    <?php if ($owner_email !== '') : ?>
                        (<?php echo esc_html($owner_email); ?>)
                    <?php endif; ?>
                </p>
                <p>
                    <strong><?php esc_html_e('Status:', 'nexdirectory'); ?></strong>
                    <?php echo esc_html(ucfirst($status)); ?>
                </p>
                <p style="display:flex;gap:10px;flex-wrap:wrap;">
                    <a class="button" href="<?php echo esc_url((string) $edit_frontend_url); ?>"><?php esc_html_e('Open Frontend Edit Form', 'nexdirectory'); ?></a>
                    <a class="button" href="<?php echo esc_url((string) $edit_backend_url); ?>"><?php esc_html_e('Edit WP Page', 'nexdirectory'); ?></a>
                </p>
            </div>

            <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" class="card" style="max-width:980px;padding:18px;">
                <input type="hidden" name="action" value="eep_reassign_listing_owner">
                <input type="hidden" name="post_id" value="<?php echo esc_attr((string) $post_id); ?>">
                <input type="hidden" name="redirect_to" value="<?php echo esc_attr($this->get_transfer_owner_admin_url($post_id)); ?>">
                <?php wp_nonce_field('eep_reassign_listing_owner_' . $post_id, 'eep_reassign_listing_owner_nonce'); ?>

                <table class="form-table" role="presentation">
                    <tr>
                        <th scope="row"><label for="eep_new_owner_identifier"><?php esc_html_e('New Owner', 'nexdirectory'); ?></label></th>
                        <td>
                            <select id="eep_new_owner_identifier" name="new_owner_identifier" class="regular-text" required>
                                <option value=""><?php esc_html_e('Select a user...', 'nexdirectory'); ?></option>
                                <?php foreach ((array) $suggested_users as $user) : ?>
                                    <?php
                                    if ($user instanceof WP_User) {
                                        $user_id = (int) $user->ID;
                                        $display_name = (string) ($user->display_name ?: $user->user_login);
                                        $user_email = (string) $user->user_email;
                                    } elseif (is_object($user)) {
                                        $user_id = (int) ($user->ID ?? 0);
                                        $display_name = (string) (($user->display_name ?? '') !== '' ? $user->display_name : ($user->user_login ?? ''));
                                        $user_email = (string) ($user->user_email ?? '');
                                    } else {
                                        continue;
                                    }
                                    if ($user_id <= 0) {
                                        continue;
                                    }
                                    ?>
                                    <option value="<?php echo esc_attr((string) $user_id); ?>" <?php selected($owner_id, $user_id); ?>><?php echo esc_html($display_name . ' (' . $user_email . ')'); ?></option>
                                <?php endforeach; ?>
                            </select>
                            <p class="description"><?php esc_html_e('Select the user who should become the new owner.', 'nexdirectory'); ?></p>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><?php esc_html_e('Notify New Owner', 'nexdirectory'); ?></th>
                        <td>
                            <label><input type="checkbox" name="notify_new_owner" value="1" checked> <?php esc_html_e('Send an email notification to the new owner', 'nexdirectory'); ?></label>
                        </td>
                    </tr>
                    <tr>
                        <th scope="row"><label for="eep_new_owner_subject"><?php esc_html_e('Email Subject (optional)', 'nexdirectory'); ?></label></th>
                        <td><input type="text" id="eep_new_owner_subject" name="notify_subject" class="regular-text" placeholder="<?php esc_attr_e('You are now the owner of a listing', 'nexdirectory'); ?>"></td>
                    </tr>
                    <tr>
                        <th scope="row"><label for="eep_new_owner_message"><?php esc_html_e('Email Message (optional)', 'nexdirectory'); ?></label></th>
                        <td>
                            <textarea id="eep_new_owner_message" name="notify_message" rows="5" class="large-text" placeholder="<?php esc_attr_e('Optional custom note for the new owner.', 'nexdirectory'); ?>"></textarea>
                            <p class="description"><?php esc_html_e('If left blank, a default ownership transfer message is sent.', 'nexdirectory'); ?></p>
                        </td>
                    </tr>
                </table>

                <p>
                    <button type="submit" class="button button-primary"><?php esc_html_e('Change Owner', 'nexdirectory'); ?></button>
                    <a class="button" href="<?php echo esc_url(eep_add_query_arg(['post_type' => self::POST_TYPE, 'mode' => 'list'], admin_url('edit.php'))); ?>"><?php esc_html_e('Back to Listings', 'nexdirectory'); ?></a>
                </p>
            </form>
        </div>
        <?php
    }


    public function handle_reassign_listing_owner() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }
        $post_id = isset($_POST['post_id']) ? absint((int) wp_unslash($_POST['post_id'])) : 0;
        $redirect_to = isset($_POST['redirect_to']) ? esc_url_raw((string) wp_unslash($_POST['redirect_to'])) : '';
        if ($redirect_to === '') {
            $redirect_to = $this->get_transfer_owner_admin_url($post_id);
        }
        if ($post_id <= 0 || get_post_type($post_id) !== self::POST_TYPE) {
            $this->safe_redirect_or_fallback(eep_add_query_arg([
                'eep_notice' => rawurlencode(__('Invalid listing selected.', 'nexdirectory')),
                'eep_notice_type' => 'error',
            ], $redirect_to));
        }
        if (!isset($_POST['eep_reassign_listing_owner_nonce']) || !wp_verify_nonce(eep_sanitize_text(wp_unslash($_POST['eep_reassign_listing_owner_nonce'])), 'eep_reassign_listing_owner_' . $post_id)) {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }

        $identifier = sanitize_text_field((string) wp_unslash($_POST['new_owner_identifier'] ?? ''));
        $new_owner = $this->find_user_for_owner_transfer($identifier);
        if (!$new_owner instanceof WP_User) {
            $this->safe_redirect_or_fallback(eep_add_query_arg([
                'eep_notice' => rawurlencode(__('Could not find a user for that owner value.', 'nexdirectory')),
                'eep_notice_type' => 'error',
            ], $redirect_to));
        }
        $current_owner_id = (int) get_post_field('post_author', $post_id);
        if ($current_owner_id === (int) $new_owner->ID) {
            $this->safe_redirect_or_fallback(eep_add_query_arg([
                'eep_notice' => rawurlencode(__('This user is already the listing owner.', 'nexdirectory')),
                'eep_notice_type' => 'error',
            ], $redirect_to));
        }

        $updated = wp_update_post([
            'ID' => $post_id,
            'post_author' => (int) $new_owner->ID,
        ], true);
        if (is_wp_error($updated)) {
            $this->safe_redirect_or_fallback(eep_add_query_arg([
                'eep_notice' => rawurlencode((string) $updated->get_error_message()),
                'eep_notice_type' => 'error',
            ], $redirect_to));
        }
        if (method_exists($this, 'ensure_event_owner_team_member')) {
            $this->ensure_event_owner_team_member($post_id);
        }

        $notify_sent = false;
        $should_notify = isset($_POST['notify_new_owner']) && (string) wp_unslash($_POST['notify_new_owner']) === '1';
        if ($should_notify && is_email((string) $new_owner->user_email)) {
            $subject = sanitize_text_field((string) wp_unslash($_POST['notify_subject'] ?? ''));
            if ($subject === '') {
                $subject = sprintf(__('Listing ownership transferred: %s', 'nexdirectory'), (string) get_the_title($post_id));
            }
            $custom_message = eep_sanitize_textarea((string) wp_unslash($_POST['notify_message'] ?? ''));
            if ($custom_message === '') {
                $custom_message = sprintf(
                    __('You have been assigned as the owner of "%1$s". You can now manage it from your account dashboard.', 'nexdirectory'),
                    (string) get_the_title($post_id)
                );
            }
            $frontend_edit_url = eep_add_query_arg('edit_event_id', $post_id, $this->get_platform_page_url(
                'eep_page_submit_event_url',
                $this->get_profile_route_slugs('submit'),
                $this->get_profile_route_default_url('submit')
            ));
            $headers = [];
            $admin_user = wp_get_current_user();
            if ($admin_user instanceof WP_User && is_email((string) $admin_user->user_email)) {
                $headers[] = 'Reply-To: ' . $admin_user->display_name . ' <' . $admin_user->user_email . '>';
            }
            $fallback_text = sprintf(
                "Hello %s,\n\n%s\n\nListing: %s\nPublic URL: %s\nEdit Form: %s",
                (string) ($new_owner->display_name ?: $new_owner->user_login),
                $custom_message,
                (string) get_the_title($post_id),
                (string) get_permalink($post_id),
                (string) $frontend_edit_url
            );
            $notify_sent = $this->send_platform_email((string) $new_owner->user_email, $subject, '', [
                'fallback_text' => $fallback_text,
            ], $headers);
        }

        $notice = $should_notify
            ? ($notify_sent
                ? __('Listing owner updated and notification email sent.', 'nexdirectory')
                : __('Listing owner updated, but email could not be sent.', 'nexdirectory'))
            : __('Listing owner updated.', 'nexdirectory');
        $notice_type = (!$should_notify || $notify_sent) ? 'success' : 'error';

        $this->safe_redirect_or_fallback(eep_add_query_arg([
            'eep_notice' => rawurlencode($notice),
            'eep_notice_type' => $notice_type,
        ], $redirect_to));
    }


    private function get_ticket_purchase_admin_notice_queue() {
        $raw_queue = get_option('eep_admin_ticket_purchase_notice_queue', []);
        if (!is_array($raw_queue)) {
            return [];
        }

        $queue = [];
        foreach ($raw_queue as $entry) {
            if (!is_array($entry)) {
                continue;
            }

            $notice_id = sanitize_key((string) ($entry['id'] ?? ''));
            if ($notice_id === '') {
                continue;
            }

            $event_id = absint((int) ($entry['event_id'] ?? 0));
            $event_title = sanitize_text_field((string) ($entry['event_title'] ?? ''));
            if ($event_id <= 0 && $event_title === '') {
                continue;
            }

            $queue[] = [
                'id' => $notice_id,
                'event_id' => $event_id,
                'event_title' => $event_title,
                'buyer_name' => sanitize_text_field((string) ($entry['buyer_name'] ?? '')),
                'buyer_email' => sanitize_email((string) ($entry['buyer_email'] ?? '')),
                'status' => sanitize_key((string) ($entry['status'] ?? 'yes')),
                'ticket_uid' => sanitize_text_field((string) ($entry['ticket_uid'] ?? '')),
                'order_id' => absint((int) ($entry['order_id'] ?? 0)),
                'currency' => strtoupper(sanitize_text_field((string) ($entry['currency'] ?? ''))),
                'amount' => round(max(0, (float) ($entry['amount'] ?? 0)), 2),
                'purchased_at' => sanitize_text_field((string) ($entry['purchased_at'] ?? '')),
                'created_at' => absint((int) ($entry['created_at'] ?? 0)),
            ];
        }

        if (count($queue) > 50) {
            $queue = array_slice($queue, -50);
        }

        return array_values($queue);
    }


    private function save_ticket_purchase_admin_notice_queue(array $queue = []) {
        $queue = array_values(array_filter($queue, static function ($entry) {
            return is_array($entry) && sanitize_key((string) ($entry['id'] ?? '')) !== '';
        }));
        return update_option('eep_admin_ticket_purchase_notice_queue', $queue, false);
    }


    public function queue_admin_ticket_purchase_notice(array $payload = []) {
        $event_id = absint((int) ($payload['event_id'] ?? 0));
        if ($event_id <= 0) {
            return false;
        }

        $notice_id = sanitize_key((string) ('tkt_' . substr(str_replace('-', '', wp_generate_uuid4()), 0, 18)));
        if ($notice_id === '') {
            return false;
        }

        $event_title = sanitize_text_field((string) ($payload['event_title'] ?? get_the_title($event_id)));
        if ($event_title === '') {
            $event_title = __('Untitled event', 'nexdirectory');
        }

        $queue = $this->get_ticket_purchase_admin_notice_queue();
        $queue[] = [
            'id' => $notice_id,
            'event_id' => $event_id,
            'event_title' => $event_title,
            'buyer_name' => sanitize_text_field((string) ($payload['buyer_name'] ?? '')),
            'buyer_email' => sanitize_email((string) ($payload['buyer_email'] ?? '')),
            'status' => sanitize_key((string) ($payload['status'] ?? 'yes')),
            'ticket_uid' => sanitize_text_field((string) ($payload['ticket_uid'] ?? '')),
            'order_id' => absint((int) ($payload['order_id'] ?? 0)),
            'currency' => strtoupper(sanitize_text_field((string) ($payload['currency'] ?? ''))),
            'amount' => round(max(0, (float) ($payload['amount'] ?? 0)), 2),
            'purchased_at' => sanitize_text_field((string) ($payload['purchased_at'] ?? current_time('mysql', true))),
            'created_at' => time(),
        ];
        if (count($queue) > 50) {
            $queue = array_slice($queue, -50);
        }

        return $this->save_ticket_purchase_admin_notice_queue($queue);
    }


    public function render_admin_ticket_purchase_notices() {
        if (!is_admin() || !current_user_can('manage_options')) {
            return;
        }

        global $pagenow;
        $pagenow = is_string($pagenow) ? strtolower($pagenow) : '';
        $current_page = sanitize_key((string) wp_unslash($_GET['page'] ?? ''));
        $is_wp_dashboard = $pagenow === 'index.php';
        $is_plugin_dashboard = ($pagenow === 'admin.php' && $current_page === 'eep-dashboard');
        if (!$is_wp_dashboard && !$is_plugin_dashboard) {
            return;
        }

        $queue = $this->get_ticket_purchase_admin_notice_queue();
        if (empty($queue)) {
            return;
        }

        $recent_notices = array_slice($queue, -8);
        foreach ($recent_notices as $entry) {
            $notice_id = sanitize_key((string) ($entry['id'] ?? ''));
            if ($notice_id === '') {
                continue;
            }

            $event_id = absint((int) ($entry['event_id'] ?? 0));
            $event_title = sanitize_text_field((string) ($entry['event_title'] ?? __('Untitled event', 'nexdirectory')));
            $buyer_name = sanitize_text_field((string) ($entry['buyer_name'] ?? ''));
            $buyer_email = sanitize_email((string) ($entry['buyer_email'] ?? ''));
            $status = sanitize_key((string) ($entry['status'] ?? 'yes'));
            $status_label = $status === 'waitlist' ? __('Waitlist', 'nexdirectory') : __('Confirmed', 'nexdirectory');
            $ticket_uid = sanitize_text_field((string) ($entry['ticket_uid'] ?? ''));
            $currency = strtoupper(sanitize_text_field((string) ($entry['currency'] ?? '')));
            $amount = round(max(0, (float) ($entry['amount'] ?? 0)), 2);
            $purchased_at = sanitize_text_field((string) ($entry['purchased_at'] ?? ''));

            $amount_label = $amount > 0
                ? trim(($currency !== '' ? $currency . ' ' : '') . number_format($amount, 2, '.', ''))
                : __('Free', 'nexdirectory');
            $buyer_label = $buyer_name !== '' ? $buyer_name : $buyer_email;
            if ($buyer_label === '') {
                $buyer_label = __('Guest buyer', 'nexdirectory');
            }

            $edit_event_url = $event_id > 0 ? get_edit_post_link($event_id, '') : '';
            $view_event_url = $event_id > 0 ? get_permalink($event_id) : '';
            $dismiss_url = wp_nonce_url(
                eep_add_query_arg([
                    'action' => 'eep_dismiss_ticket_purchase_notice',
                    'notice_id' => $notice_id,
                ], admin_url('admin-post.php')),
                'eep_dismiss_ticket_purchase_notice_' . $notice_id
            );

            $ticket_meta = '';
            if ($ticket_uid !== '') {
                $ticket_meta .= sprintf(__(' Ticket: %s.', 'nexdirectory'), $ticket_uid);
            }
            if ($purchased_at !== '') {
                $ticket_meta .= ' ' . sprintf(__(' Purchased: %s.', 'nexdirectory'), $purchased_at);
            }

            echo '<div class="notice notice-success"><p>';
            echo '<strong>' . esc_html__('New ticket purchase:', 'nexdirectory') . '</strong> ';
            echo esc_html($event_title) . ' - ' . esc_html($amount_label) . ' - ';
            echo esc_html($status_label) . '. ';
            echo esc_html(sprintf(__('Buyer: %s.', 'nexdirectory'), $buyer_label));
            echo esc_html($ticket_meta);
            if ($edit_event_url !== '') {
                echo ' <a href="' . esc_url($edit_event_url) . '">' . esc_html__('Edit event', 'nexdirectory') . '</a>';
            }
            if ($view_event_url !== '') {
                echo ' | <a href="' . esc_url($view_event_url) . '" target="_blank" rel="noopener noreferrer">' . esc_html__('View event', 'nexdirectory') . '</a>';
            }
            echo ' | <a href="' . esc_url($dismiss_url) . '">' . esc_html__('Dismiss', 'nexdirectory') . '</a>';
            echo '</p></div>';
        }
    }


    public function handle_dismiss_ticket_purchase_notice() {
        if (!current_user_can('manage_options')) {
            wp_die(__('Not allowed.', 'nexdirectory'));
        }

        $notice_id = sanitize_key((string) wp_unslash($_REQUEST['notice_id'] ?? ''));
        if ($notice_id === '') {
            wp_die(__('Invalid request.', 'nexdirectory'));
        }

        check_admin_referer('eep_dismiss_ticket_purchase_notice_' . $notice_id);

        $queue = $this->get_ticket_purchase_admin_notice_queue();
        $filtered = array_values(array_filter($queue, static function ($entry) use ($notice_id) {
            return sanitize_key((string) ($entry['id'] ?? '')) !== $notice_id;
        }));
        if (count($filtered) !== count($queue)) {
            $this->save_ticket_purchase_admin_notice_queue($filtered);
        }

        $redirect = wp_get_referer();
        if (!is_string($redirect) || $redirect === '') {
            $redirect = admin_url('index.php');
        }
        $this->safe_redirect_or_fallback($redirect);
    }


    public function render_import_page() {
        if (!current_user_can('manage_options')) {
            return;
        }
        $preview_token = isset($_GET['eep_import_preview']) ? sanitize_key(wp_unslash($_GET['eep_import_preview'])) : '';
        $preview_data = null;
        if ($preview_token !== '') {
            $payload = get_transient($this->get_import_preview_transient_key($preview_token));
            if (is_array($payload) && (int) ($payload['user_id'] ?? 0) === get_current_user_id()) {
                $preview_data = $payload;
            }
        }
        $supported_fields = $this->get_import_supported_fields();
        $demo_profiles = method_exists($this, 'get_demo_profile_catalog') ? (array) $this->get_demo_profile_catalog() : [];
        if (empty($demo_profiles)) {
            $demo_profiles = [
                'events' => ['label' => __('Events', 'nexdirectory')],
            ];
        }
        $platform_mode = sanitize_key((string) get_option('eep_platform_mode', 'user_generated'));
        $is_single_org_mode = $platform_mode === 'single_organisation';
        $default_demo_profile = method_exists($this, 'get_demo_profile_key_for_platform_mode')
            ? sanitize_key((string) $this->get_demo_profile_key_for_platform_mode($platform_mode))
            : 'events';
        if ($default_demo_profile === '' || !isset($demo_profiles[$default_demo_profile])) {
            $default_demo_profile = array_key_first($demo_profiles);
        }
        if (!is_string($default_demo_profile) || $default_demo_profile === '') {
            $default_demo_profile = 'events';
        }
        $default_demo_profile_label = sanitize_text_field((string) (($demo_profiles[$default_demo_profile]['label'] ?? $default_demo_profile)));
        $ui_labels = method_exists($this, 'get_site_profile_ui_labels') ? (array) $this->get_site_profile_ui_labels() : [];
        $singular_label = sanitize_text_field((string) ($ui_labels['singular'] ?? __('Listing', 'nexdirectory')));
        $plural_label = sanitize_text_field((string) ($ui_labels['plural'] ?? __('Listings', 'nexdirectory')));
        $plural_lower = sanitize_text_field((string) ($ui_labels['plural_lower'] ?? strtolower((string) $plural_label)));
        ?>
        <div class="wrap eep-import-page">
            <style>
                .eep-import-page { max-width: 1280px; }
                .eep-import-page .eep-import-hero {
                    border: 1px solid #d8deeb;
                    border-radius: 16px;
                    padding: 16px 18px;
                    margin: 8px 0 14px;
                    background: linear-gradient(130deg, #0f172a 0%, #172554 52%, #1e293b 100%);
                    color: #fff;
                    box-shadow: 0 12px 30px rgba(15, 23, 42, .18);
                }
                .eep-import-page .eep-import-hero h1 { margin: 0 0 8px; color: #fff; }
                .eep-import-page .eep-import-hero p { margin: 0; color: rgba(255,255,255,.85); max-width: 840px; }
                .eep-import-page .eep-import-toolbar {
                    display: grid;
                    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
                    gap: 12px;
                    margin: 14px 0 18px;
                }
                .eep-import-page .eep-import-card,
                .eep-import-page .eep-import-panel {
                    border: 1px solid #d9dfe9;
                    border-radius: 14px;
                    background: linear-gradient(180deg, #fff 0%, #f8faff 100%);
                    padding: 14px 16px;
                    box-shadow: 0 10px 24px rgba(15, 23, 42, .08);
                }
                .eep-import-page .eep-import-card h2,
                .eep-import-page .eep-import-panel h2 {
                    margin: 0 0 8px;
                    font-size: 16px;
                    display: flex;
                    align-items: center;
                    gap: 8px;
                }
                .eep-import-page .eep-import-card h2 .dashicons,
                .eep-import-page .eep-import-panel h2 .dashicons { color: #ff5e14; }
                .eep-import-page .eep-import-card p,
                .eep-import-page .eep-import-panel > p {
                    margin: 0 0 12px;
                    color: #475569;
                }
                .eep-import-page .eep-import-toolbar form { margin: 0; }
                .eep-import-page .eep-import-field-grid {
                    display: grid;
                    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
                    gap: 10px;
                    align-items: end;
                }
                .eep-import-page label { font-weight: 600; display: block; margin-bottom: 4px; color: #0f172a; }
                .eep-import-page input[type="text"],
                .eep-import-page input[type="number"],
                .eep-import-page input[type="file"],
                .eep-import-page select,
                .eep-import-page textarea {
                    width: 100%;
                    max-width: 100%;
                }
                .eep-import-page .eep-import-form-table th { width: 220px; font-weight: 600; color: #0f172a; }
                .eep-import-page .eep-import-form-actions {
                    margin-top: 12px;
                    display: flex;
                    gap: 8px;
                    align-items: center;
                    flex-wrap: wrap;
                }
                .eep-import-page .eep-import-table-wrap { overflow-x: auto; border-radius: 10px; border: 1px solid #e2e8f0; }
                .eep-import-page table.eep-import-table { margin: 0; min-width: 760px; }
                .eep-import-page table.eep-import-table th { background: #f8fafc; color: #0f172a; font-weight: 600; }
                .eep-import-page .eep-import-supported code {
                    display: block;
                    padding: 10px 12px;
                    border-radius: 10px;
                    background: #f8fafc;
                    border: 1px solid #e2e8f0;
                    font-size: 12px;
                    line-height: 1.45;
                    word-break: break-word;
                }
                .eep-import-page .button-primary {
                    background: #ff5e14;
                    border-color: #ff5e14;
                }
                .eep-import-page .button-primary:hover,
                .eep-import-page .button-primary:focus {
                    background: #e04f0d;
                    border-color: #e04f0d;
                }
            </style>

            <section class="eep-import-hero">
                <h1><?php esc_html_e('Import Listing', 'nexdirectory'); ?></h1>
                <p><?php esc_html_e('Upload CSV or JSON data, preview column mapping, and import safely with duplicate controls and status handling.', 'nexdirectory'); ?></p>
            </section>

            <?php echo wp_kses_post((string) $this->render_notice()); ?>

            <section class="eep-import-toolbar">
                <form class="eep-import-card" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
                    <h2><span class="dashicons dashicons-database-export"></span><?php esc_html_e('Export Listings', 'nexdirectory'); ?></h2>
                    <p><?php echo esc_html(sprintf(__('Download all existing %s in CSV or JSON.', 'nexdirectory'), strtolower((string) $plural_label))); ?></p>
                    <input type="hidden" name="action" value="eep_export_events">
                    <?php wp_nonce_field('eep_export_events_nonce', 'eep_export_nonce'); ?>
                    <div class="eep-import-field-grid">
                        <div>
                            <label for="eep_export_format"><?php esc_html_e('Format', 'nexdirectory'); ?></label>
                            <select id="eep_export_format" name="eep_export_format">
                                <option value="csv"><?php esc_html_e('CSV', 'nexdirectory'); ?></option>
                                <option value="json"><?php esc_html_e('JSON', 'nexdirectory'); ?></option>
                            </select>
                        </div>
                        <div><?php submit_button(__('Export Data', 'nexdirectory'), 'button-secondary', 'submit', false); ?></div>
                    </div>
                </form>

                <form class="eep-import-card" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
                    <h2><span class="dashicons dashicons-media-spreadsheet"></span><?php esc_html_e('Download Demo Template', 'nexdirectory'); ?></h2>
                    <p><?php esc_html_e('Get a ready-to-fill template that matches supported import fields.', 'nexdirectory'); ?></p>
                    <input type="hidden" name="action" value="eep_export_demo_events">
                    <?php wp_nonce_field('eep_export_events_nonce', 'eep_export_nonce'); ?>
                    <div class="eep-import-field-grid">
                        <div>
                            <label for="eep_export_demo_format"><?php esc_html_e('Format', 'nexdirectory'); ?></label>
                            <select id="eep_export_demo_format" name="eep_export_format">
                                <option value="csv"><?php esc_html_e('CSV', 'nexdirectory'); ?></option>
                                <option value="json"><?php esc_html_e('JSON', 'nexdirectory'); ?></option>
                            </select>
                        </div>
                        <div><?php submit_button(__('Download Template', 'nexdirectory'), 'button-secondary', 'submit', false); ?></div>
                    </div>
                </form>

                <form class="eep-import-card" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
                    <h2><span class="dashicons dashicons-database-add"></span><?php esc_html_e('Import Demo Data', 'nexdirectory'); ?></h2>
                    <p><?php esc_html_e('Generate realistic sample listings with matching taxonomy and layout presets.', 'nexdirectory'); ?></p>
                    <p class="description"><?php esc_html_e('Demo entries are read-only on the free plan. Use Duplicate Event to create editable copies that count toward your free event limit.', 'nexdirectory'); ?></p>
                    <input type="hidden" name="action" value="eep_import_demo_events">
                    <?php if ($is_single_org_mode) : ?>
                        <input type="hidden" name="eep_demo_profile" value="<?php echo esc_attr($default_demo_profile); ?>">
                    <?php endif; ?>
                    <?php wp_nonce_field('eep_import_demo_events_nonce', 'eep_import_demo_nonce'); ?>
                    <div class="eep-import-field-grid">
                        <div>
                            <?php if ($is_single_org_mode) : ?>
                                <label><?php esc_html_e('Demo Profile (Auto)', 'nexdirectory'); ?></label>
                                <input type="text" value="<?php echo esc_attr($default_demo_profile_label); ?>" readonly>
                                <p class="description"><?php esc_html_e('Single-Organisation mode automatically uses the dedicated organisational demo dataset.', 'nexdirectory'); ?></p>
                            <?php else : ?>
                                <label for="eep_demo_profile"><?php esc_html_e('Demo Profile', 'nexdirectory'); ?></label>
                                <select id="eep_demo_profile" name="eep_demo_profile">
                                    <?php foreach ($demo_profiles as $profile_key => $profile_config) : ?>
                                        <?php
                                        $profile_key = sanitize_key((string) $profile_key);
                                        if ($profile_key === '') {
                                            continue;
                                        }
                                        $profile_label = sanitize_text_field((string) ($profile_config['label'] ?? $profile_key));
                                        ?>
                                        <option value="<?php echo esc_attr($profile_key); ?>" <?php selected($profile_key, $default_demo_profile); ?>><?php echo esc_html($profile_label); ?></option>
                                    <?php endforeach; ?>
                                </select>
                            <?php endif; ?>
                        </div>
                        <div>
                            <label for="eep_demo_count"><?php esc_html_e('Rows', 'nexdirectory'); ?></label>
                            <input type="number" id="eep_demo_count" name="eep_demo_count" value="50" min="10" max="200" step="10">
                        </div>
                        <div class="eep-import-field-grid" style="grid-column: 1 / -1;">
                            <div>
                                <input type="hidden" name="eep_demo_apply_presets" value="0">
                                <label style="display:flex;align-items:center;gap:6px;margin-bottom:0;">
                                    <input type="checkbox" name="eep_demo_apply_presets" value="1" checked>
                                    <?php esc_html_e('Apply profile design and taxonomy presets', 'nexdirectory'); ?>
                                </label>
                            </div>
                            <div><?php submit_button(__('Import Demo Data', 'nexdirectory'), 'button-primary', 'submit', false); ?></div>
                        </div>
                    </div>
                    <p class="description"><?php echo esc_html(sprintf(__('Profiles change sample %s types/tags plus map and single-page layout presets.', 'nexdirectory'), $plural_lower)); ?></p>
                </form>
            </section>

            <?php if ($preview_data) : ?>
                <?php
                $headers = array_values(array_filter(array_map('strval', (array) ($preview_data['headers'] ?? []))));
                $sample_rows = array_slice((array) ($preview_data['sample_rows'] ?? []), 0, 5);
                $mapping = is_array($preview_data['mapping'] ?? null) ? (array) $preview_data['mapping'] : [];
                $default_status = sanitize_key((string) ($preview_data['default_status'] ?? 'pending'));
                if (!in_array($default_status, ['pending', 'draft', 'publish'], true)) {
                    $default_status = 'pending';
                }
                $skip_duplicates = (string) ($preview_data['skip_duplicates'] ?? '1') === '1';
                ?>
                <section class="eep-import-panel">
                    <h2><span class="dashicons dashicons-visibility"></span><?php esc_html_e('Step 2: Preview and Column Mapping', 'nexdirectory'); ?></h2>
                    <p>
                        <?php
                        echo esc_html(
                            sprintf(
                                __('Detected %1$d rows. Map your source columns to %2$s fields before import.', 'nexdirectory'),
                                (int) ($preview_data['row_count'] ?? 0),
                                strtolower((string) $singular_label)
                            )
                        );
                        ?>
                    </p>
                    <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
                        <input type="hidden" name="action" value="eep_import_events">
                        <input type="hidden" name="eep_import_step" value="apply">
                        <input type="hidden" name="eep_import_token" value="<?php echo esc_attr($preview_token); ?>">
                        <?php wp_nonce_field('eep_import_events_nonce', 'eep_import_nonce'); ?>
                        <table class="form-table eep-import-form-table" role="presentation">
                            <tr>
                                <th scope="row"><label for="eep_import_default_status_apply"><?php esc_html_e('Default Status', 'nexdirectory'); ?></label></th>
                                <td>
                                    <select id="eep_import_default_status_apply" name="eep_import_default_status">
                                        <option value="pending" <?php selected($default_status, 'pending'); ?>><?php esc_html_e('Pending', 'nexdirectory'); ?></option>
                                        <option value="draft" <?php selected($default_status, 'draft'); ?>><?php esc_html_e('Draft', 'nexdirectory'); ?></option>
                                        <option value="publish" <?php selected($default_status, 'publish'); ?>><?php esc_html_e('Published', 'nexdirectory'); ?></option>
                                    </select>
                                </td>
                            </tr>
                            <tr>
                                <th scope="row"><?php esc_html_e('Duplicate Handling', 'nexdirectory'); ?></th>
                                <td>
                                    <label style="display:flex;align-items:center;gap:6px;margin-bottom:0;">
                                        <input type="checkbox" name="eep_import_skip_duplicates" value="1" <?php checked($skip_duplicates); ?>>
                                        <?php esc_html_e('Skip rows where title + start datetime already exist', 'nexdirectory'); ?>
                                    </label>
                                </td>
                            </tr>
                        </table>
                        <h3><?php esc_html_e('Map Source Columns', 'nexdirectory'); ?></h3>
                        <div class="eep-import-table-wrap">
                            <table class="widefat striped eep-import-table">
                                <thead>
                                    <tr>
                                        <th><?php echo esc_html(sprintf(__('%s Field', 'nexdirectory'), $singular_label)); ?></th>
                                        <th><?php esc_html_e('Source Column', 'nexdirectory'); ?></th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <?php foreach ($supported_fields as $target_field => $label) : ?>
                                        <?php $selected_header = sanitize_key((string) ($mapping[$target_field] ?? '')); ?>
                                        <tr>
                                            <td><code><?php echo esc_html($target_field); ?></code> - <?php echo esc_html($label); ?></td>
                                            <td>
                                                <select name="eep_import_map[<?php echo esc_attr($target_field); ?>]">
                                                    <option value=""><?php esc_html_e('Ignore', 'nexdirectory'); ?></option>
                                                    <?php foreach ($headers as $header) : ?>
                                                        <option value="<?php echo esc_attr($header); ?>" <?php selected($selected_header, sanitize_key($header)); ?>>
                                                            <?php echo esc_html($header); ?>
                                                        </option>
                                                    <?php endforeach; ?>
                                                </select>
                                            </td>
                                        </tr>
                                    <?php endforeach; ?>
                                </tbody>
                            </table>
                        </div>
                        <div class="eep-import-form-actions">
                            <?php submit_button(__('Run Import', 'nexdirectory'), 'primary', 'submit', false); ?>
                            <a class="button" href="<?php echo esc_url(admin_url('admin.php?page=eep-import')); ?>"><?php esc_html_e('Start Over', 'nexdirectory'); ?></a>
                        </div>
                    </form>
                    <h3><?php esc_html_e('Preview (First 5 Rows)', 'nexdirectory'); ?></h3>
                    <?php if (!empty($headers) && !empty($sample_rows)) : ?>
                        <div class="eep-import-table-wrap">
                            <table class="widefat striped eep-import-table">
                                <thead>
                                    <tr>
                                        <?php foreach ($headers as $header) : ?>
                                            <th><?php echo esc_html($header); ?></th>
                                        <?php endforeach; ?>
                                    </tr>
                                </thead>
                                <tbody>
                                    <?php foreach ($sample_rows as $sample_row) : ?>
                                        <tr>
                                            <?php foreach ($headers as $header) : ?>
                                                <?php $cell = isset($sample_row[$header]) ? (string) $sample_row[$header] : ''; ?>
                                                <td><?php echo esc_html(wp_html_excerpt($cell, 120, '...')); ?></td>
                                            <?php endforeach; ?>
                                        </tr>
                                    <?php endforeach; ?>
                                </tbody>
                            </table>
                        </div>
                    <?php else : ?>
                        <p><?php esc_html_e('No preview rows available.', 'nexdirectory'); ?></p>
                    <?php endif; ?>
                </section>
            <?php else : ?>
                <section class="eep-import-panel">
                    <h2><span class="dashicons dashicons-upload"></span><?php esc_html_e('Step 1: Upload Source File', 'nexdirectory'); ?></h2>
                    <p><?php esc_html_e('Upload a JSON array or CSV file. Step 2 will let you preview rows and map columns before import.', 'nexdirectory'); ?></p>
                    <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" enctype="multipart/form-data">
                        <input type="hidden" name="action" value="eep_import_events">
                        <input type="hidden" name="eep_import_step" value="preview">
                        <?php wp_nonce_field('eep_import_events_nonce', 'eep_import_nonce'); ?>
                        <table class="form-table eep-import-form-table" role="presentation">
                            <tr>
                                <th scope="row"><label for="eep_import_file"><?php esc_html_e('Import File', 'nexdirectory'); ?></label></th>
                                <td><input type="file" id="eep_import_file" name="eep_import_file" accept=".json,.csv,text/csv,application/json" required></td>
                            </tr>
                            <tr>
                                <th scope="row"><label for="eep_import_default_status"><?php esc_html_e('Default Status', 'nexdirectory'); ?></label></th>
                                <td>
                                    <select id="eep_import_default_status" name="eep_import_default_status">
                                        <option value="pending"><?php esc_html_e('Pending', 'nexdirectory'); ?></option>
                                        <option value="draft"><?php esc_html_e('Draft', 'nexdirectory'); ?></option>
                                        <option value="publish"><?php esc_html_e('Published', 'nexdirectory'); ?></option>
                                    </select>
                                </td>
                            </tr>
                            <tr>
                                <th scope="row"><?php esc_html_e('Duplicate Handling', 'nexdirectory'); ?></th>
                                <td>
                                    <label style="display:flex;align-items:center;gap:6px;margin-bottom:0;">
                                        <input type="checkbox" name="eep_import_skip_duplicates" value="1" checked>
                                        <?php esc_html_e('Skip rows where title + start datetime already exist', 'nexdirectory'); ?>
                                    </label>
                                </td>
                            </tr>
                        </table>
                        <?php submit_button(__('Continue To Preview', 'nexdirectory')); ?>
                    </form>
                </section>
            <?php endif; ?>

            <section class="eep-import-panel eep-import-supported">
                <h2><span class="dashicons dashicons-editor-ul"></span><?php esc_html_e('Supported Fields', 'nexdirectory'); ?></h2>
                <p><?php esc_html_e('Use these keys in your CSV header row or JSON objects.', 'nexdirectory'); ?></p>
                <code>title,description,excerpt,start,end,timezone,venue,address,city,country,lat,lng,capacity,price,external_url,contact_email,contact_phone,contact_name,cover_image_url,official_event,recurrence,recurrence_until,video_urls,gallery_urls,sessions,event_type,event_mode,event_price_range,event_tags,status</code>
                <p><?php esc_html_e('Use comma, pipe, or newline separated values for tag/type/mode/price lists and media URLs.', 'nexdirectory'); ?></p>
            </section>
        </div>
        <?php
    }

}
