<?php
/**
 * Free Settings module.
 *
 * Strict-isolation entrypoint for the Settings admin section.
 * Owns:
 * - settings section registration
 * - local Settings view + shell-manifest lazy assets
 * - sanitization of Settings-owned fields
 * - shared shell/UI strings that belong to the Settings experience
 * - preferred settings panel group ordering
 * - module-owned topbar action metadata for the shared shell
 *
 * @package Noesia_Smart_Waiter
 */

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


if ( ! class_exists( 'Noesia_Swa_Module_Settings' ) ) {
    /**
     * Free Settings module.
     */
    class Noesia_Swa_Module_Settings implements Noesia_SWA_Module_Interface {

        /**
         * Unique module identifier.
         *
         * @return string
         */
        public function get_id() {
            return 'settings';
        }

        /**
         * Human-readable module label.
         *
         * @return string
         */
        public function get_label() {
            return __( 'Settings', 'noesia-smart-waiter' );
        }

        /**
         * Module tier.
         *
         * @return string
         */
        public function get_tier() {
            return 'free';
        }

        /**
         * Whether the module is enabled.
         *
         * @return bool
         */
        public function is_enabled() {
            $enabled = true;

            /**
             * Filter whether the free Settings module is enabled.
             *
             * @param bool                       $enabled Enabled state.
             * @param Noesia_Swa_Module_Settings $module  Module instance.
             */
            $enabled = apply_filters( 'noesia_swa_module_settings_enabled', $enabled, $this );

            return (bool) $enabled;
        }

        /**
         * Register module hooks.
         *
         * @return void
         */
        public function register_hooks() {
            add_action( 'noesia_swa_register_admin_sections', array( $this, 'register_admin_section' ) );

            $this->boot_local_ajax_handlers();
            $this->boot_local_admin_post_handlers();

            add_filter( 'noesia_swa_option_defaults', array( $this, 'filter_option_defaults' ), 10, 3 );
            add_filter( 'noesia_swa_sanitize_options', array( $this, 'sanitize_settings_fields' ), 10, 4 );
            add_filter( 'noesia_swa_admin_strings', array( $this, 'filter_admin_strings' ), 10, 2 );
            add_filter( 'noesia_swa_admin_i18n', array( $this, 'filter_admin_i18n' ), 10, 2 );
            add_filter( 'noesia_swa_settings_group_order_preference', array( $this, 'filter_group_order_preference' ), 10, 2 );
            add_filter( 'noesia_swa_shell_topbar_actions', array( $this, 'filter_topbar_actions' ), 20, 4 );         

            /**
             * Fires when the Settings module is booted.
             *
             * @param Noesia_Swa_Module_Settings $this Module instance.
             */
            do_action( 'noesia_swa_module_settings_loaded', $this );
        }

        /**
         * Boot Settings-owned AJAX handlers globally.
         *
         * This runs during module bootstrap, not during section render, so any
         * Settings request handler remains available inside admin-ajax.php
         * requests where the UI is never rendered.
         *
         * @return void
         */
        private function boot_local_ajax_handlers() {
            /**
             * Allow module-local Settings AJAX handlers to register globally.
             *
             * @param Noesia_Swa_Module_Settings $this Module instance.
             */
            do_action( 'noesia_swa_settings_register_ajax_handlers', $this );
            do_action( 'noesia_swa_module_settings_register_ajax_handlers', $this );
        }

        /**
         * Boot Settings-owned admin-post handlers globally.
         *
         * This runs during module bootstrap, not during section render, so any
         * Settings form endpoint remains available inside admin-post.php
         * requests where the UI is never rendered.
         *
         * @return void
         */
        private function boot_local_admin_post_handlers() {
add_action( 'admin_post_noesia_swa_export_support_diagnostics', array( $this, 'handle_export_support_diagnostics' ) );

            /**
             * Allow module-local Settings admin-post handlers to register globally.
             *
             * @param Noesia_Swa_Module_Settings $this Module instance.
             */
            do_action( 'noesia_swa_settings_register_admin_post_handlers', $this );
            do_action( 'noesia_swa_module_settings_register_admin_post_handlers', $this );
        }
/**
 * Export a support diagnostics snapshot as JSON.
 *
 * @return void
 */
public function handle_export_support_diagnostics() {
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_die( esc_html__( 'You are not allowed to export support diagnostics.', 'noesia-smart-waiter' ) );
    }

    check_admin_referer( 'noesia_swa_export_support_diagnostics', 'noesia_swa_support_diagnostics_nonce' );

    $snapshot = $this->build_support_diagnostics_snapshot();
    $json     = wp_json_encode( $snapshot, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );

    if ( ! is_string( $json ) || '' === $json ) {
        wp_die( esc_html__( 'Support diagnostics export failed.', 'noesia-smart-waiter' ) );
    }

    $filename = sanitize_file_name( 'noesia-support-diagnostics-' . gmdate( 'Y-m-d-His' ) . '.json' );

    nocache_headers();
    header( 'Content-Type: application/json; charset=utf-8' );
    header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
    header( 'X-Content-Type-Options: nosniff' );

    echo $json; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Emits an admin-generated diagnostics JSON export.
    exit;
}

/**
 * Build the support diagnostics export payload.
 *
 * @return array<string,mixed>
 */
private function build_support_diagnostics_snapshot() {
    global $wpdb, $wp_version;

    require_once ABSPATH . 'wp-admin/includes/plugin.php';

    $options                = get_option( 'noesia_swa_options', array() );
    $upload_dir             = wp_upload_dir( null, false );
    $theme                  = wp_get_theme();
    $parent_theme           = $theme->parent();
    $current_user           = wp_get_current_user();
    $loaded_extensions      = get_loaded_extensions();
    $plugin_instance        = function_exists( 'noesia_swa' ) ? noesia_swa() : null;
    $modules_manager        = ( is_object( $plugin_instance ) && isset( $plugin_instance->modules ) && $plugin_instance->modules instanceof Noesia_SWA_Modules ) ? $plugin_instance->modules : null;
    $browser_user_agent     = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( (string) $_SERVER['HTTP_USER_AGENT'] ) ) : '';
    $browser_accept_lang    = isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ? sanitize_text_field( wp_unslash( (string) $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) : '';
    $server_software        = isset( $_SERVER['SERVER_SOFTWARE'] ) ? sanitize_text_field( wp_unslash( (string) $_SERVER['SERVER_SOFTWARE'] ) ) : '';
    $disabled_functions     = array_values( array_filter( array_map( 'trim', explode( ',', (string) ini_get( 'disable_functions' ) ) ) ) );

    sort( $loaded_extensions );
    $loaded_extensions = array_values( array_map( 'sanitize_text_field', $loaded_extensions ) );

    return array(
        'export_meta' => array(
            'format_version'     => 1,
            'generated_at_gmt'   => gmdate( 'c' ),
            'generated_at_local' => current_time( 'mysql' ),
            'generator'          => 'Noesia Smart Waiter Support Diagnostics',
        ),
        'site' => array(
            'site_name'           => get_bloginfo( 'name' ),
            'home_url'            => home_url( '/' ),
            'site_url'            => site_url( '/' ),
            'admin_url'           => admin_url(),
            'ajax_url'            => admin_url( 'admin-ajax.php' ),
            'rest_url'            => rest_url(),
            'language'            => get_bloginfo( 'language' ),
            'locale'              => function_exists( 'determine_locale' ) ? determine_locale() : get_locale(),
            'timezone'            => wp_timezone_string(),
            'gmt_offset'          => get_option( 'gmt_offset' ),
            'charset'             => get_option( 'blog_charset' ),
            'environment_type'    => function_exists( 'wp_get_environment_type' ) ? wp_get_environment_type() : 'production',
            'is_ssl'              => is_ssl(),
            'is_multisite'        => is_multisite(),
            'permalink_structure' => (string) get_option( 'permalink_structure', '' ),
        ),
        'current_request' => array(
            'current_user_roles' => ( $current_user instanceof WP_User ) ? array_values( $current_user->roles ) : array(),
            'browser_user_agent' => $browser_user_agent,
            'browser_language'   => $browser_accept_lang,
        ),
        'wordpress' => array(
            'version'             => isset( $wp_version ) ? (string) $wp_version : get_bloginfo( 'version' ),
            'db_version'          => method_exists( $wpdb, 'db_version' ) ? (string) $wpdb->db_version() : '',
            'table_prefix'        => isset( $wpdb->prefix ) ? (string) $wpdb->prefix : '',
            'object_cache'        => wp_using_ext_object_cache(),
            'wp_debug'            => defined( 'WP_DEBUG' ) && WP_DEBUG,
            'wp_debug_log'        => defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG,
            'script_debug'        => defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG,
            'savequeries'         => defined( 'SAVEQUERIES' ) && SAVEQUERIES,
            'disable_wp_cron'     => defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON,
            'alternate_wp_cron'   => defined( 'ALTERNATE_WP_CRON' ) && ALTERNATE_WP_CRON,
            'wp_memory_limit'     => defined( 'WP_MEMORY_LIMIT' ) ? (string) WP_MEMORY_LIMIT : '',
            'wp_max_memory_limit' => defined( 'WP_MAX_MEMORY_LIMIT' ) ? (string) WP_MAX_MEMORY_LIMIT : '',
        ),
        'server' => array(
            'server_software'   => $server_software,
            'php_version'       => PHP_VERSION,
            'php_sapi'          => PHP_SAPI,
            'php_os_family'     => defined( 'PHP_OS_FAMILY' ) ? PHP_OS_FAMILY : PHP_OS,
            'memory_limit'      => (string) ini_get( 'memory_limit' ),
            'max_execution_time'=> (string) ini_get( 'max_execution_time' ),
            'max_input_vars'    => (string) ini_get( 'max_input_vars' ),
            'upload_max_filesize' => (string) ini_get( 'upload_max_filesize' ),
            'post_max_size'     => (string) ini_get( 'post_max_size' ),
            'max_file_uploads'  => (string) ini_get( 'max_file_uploads' ),
            'disabled_functions'=> $disabled_functions,
            'loaded_extensions' => $loaded_extensions,
            'extension_support' => array(
                'curl'      => extension_loaded( 'curl' ),
                'json'      => extension_loaded( 'json' ),
                'mbstring'  => extension_loaded( 'mbstring' ),
                'openssl'   => extension_loaded( 'openssl' ),
                'zip'       => extension_loaded( 'zip' ),
                'gd'        => extension_loaded( 'gd' ),
                'imagick'   => extension_loaded( 'imagick' ),
                'fileinfo'  => extension_loaded( 'fileinfo' ),
                'simplexml' => extension_loaded( 'simplexml' ),
            ),
            'curl'    => $this->get_support_diagnostics_curl_summary(),
            'gd'      => $this->get_support_diagnostics_gd_summary(),
            'imagick' => $this->get_support_diagnostics_imagick_summary(),
        ),
        'filesystem' => array(
            'abspath'             => ABSPATH,
            'plugin_dir'          => defined( 'NOESIA_SWA_PLUGIN_DIR' ) ? (string) NOESIA_SWA_PLUGIN_DIR : '',
            'plugin_dir_writable' => defined( 'NOESIA_SWA_PLUGIN_DIR' ) ? wp_is_writable( NOESIA_SWA_PLUGIN_DIR ) : false,
            'temp_dir'            => function_exists( 'get_temp_dir' ) ? (string) get_temp_dir() : '',
            'uploads_basedir'     => isset( $upload_dir['basedir'] ) ? (string) $upload_dir['basedir'] : '',
            'uploads_baseurl'     => isset( $upload_dir['baseurl'] ) ? (string) $upload_dir['baseurl'] : '',
            'uploads_error'       => isset( $upload_dir['error'] ) ? (string) $upload_dir['error'] : '',
            'uploads_writable'    => ! empty( $upload_dir['basedir'] ) ? wp_is_writable( $upload_dir['basedir'] ) : false,
        ),
        'theme' => array(
            'name'           => $theme->get( 'Name' ),
            'version'        => $theme->get( 'Version' ),
            'textdomain'     => $theme->get( 'TextDomain' ),
            'template'       => $theme->get_template(),
            'stylesheet'     => $theme->get_stylesheet(),
            'is_child_theme' => is_child_theme(),
            'is_block_theme' => function_exists( 'wp_is_block_theme' ) ? wp_is_block_theme() : false,
            'parent'         => $parent_theme instanceof WP_Theme ? array(
                'name'       => $parent_theme->get( 'Name' ),
                'version'    => $parent_theme->get( 'Version' ),
                'template'   => $parent_theme->get_template(),
                'stylesheet' => $parent_theme->get_stylesheet(),
            ) : array(),
        ),
        'plugins' => array(
            'installed_count' => count( get_plugins() ),
            'active_count'    => count( (array) get_option( 'active_plugins', array() ) ),
            'active'          => $this->get_support_diagnostics_plugins_inventory( true ),
            'inactive'        => $this->get_support_diagnostics_plugins_inventory( false ),
            'must_use'        => $this->get_support_diagnostics_mu_plugins_inventory(),
            'dropins'         => $this->get_support_diagnostics_dropins_inventory(),
        ),
        'noesia' => array(
            'plugin_version'   => defined( 'NOESIA_SWA_VERSION' ) ? NOESIA_SWA_VERSION : '',
            'pro_loader_found' => class_exists( 'Noesia_SWA_Pro_Loader' ),
            'pro_enabled'      => ( is_object( $plugin_instance ) && isset( $plugin_instance->pro ) && is_object( $plugin_instance->pro ) ),
            'module_count'     => $modules_manager instanceof Noesia_SWA_Modules ? count( $modules_manager->get_modules() ) : 0,
            'modules'          => $this->get_support_diagnostics_modules_inventory( $modules_manager ),
            'discovery_paths'  => $modules_manager instanceof Noesia_SWA_Modules ? $modules_manager->get_discovery_paths() : array(),
            'settings_summary' => $this->get_support_diagnostics_settings_summary( $options ),
            'module_statuses'  => $this->get_support_diagnostics_module_statuses( $options ),
        ),
    );
}

/**
 * Get active or inactive plugins inventory.
 *
 * @param bool $only_active Whether to return active plugins only.
 * @return array<int,array<string,mixed>>
 */
private function get_support_diagnostics_plugins_inventory( $only_active = true ) {
    require_once ABSPATH . 'wp-admin/includes/plugin.php';

    $installed_plugins      = get_plugins();
    $active_plugins         = (array) get_option( 'active_plugins', array() );
    $network_active_plugins = is_multisite() ? array_keys( (array) get_site_option( 'active_sitewide_plugins', array() ) ) : array();
    $plugin_updates         = get_site_transient( 'update_plugins' );
    $inventory              = array();

    foreach ( $installed_plugins as $plugin_file => $plugin_data ) {
        $is_network_active = in_array( $plugin_file, $network_active_plugins, true );
        $is_active         = $is_network_active || in_array( $plugin_file, $active_plugins, true );

        if ( (bool) $only_active !== (bool) $is_active ) {
            continue;
        }

        $inventory[] = array(
            'file'             => (string) $plugin_file,
            'name'             => isset( $plugin_data['Name'] ) ? sanitize_text_field( (string) $plugin_data['Name'] ) : (string) $plugin_file,
            'version'          => isset( $plugin_data['Version'] ) ? sanitize_text_field( (string) $plugin_data['Version'] ) : '',
            'author'           => isset( $plugin_data['AuthorName'] ) ? sanitize_text_field( (string) $plugin_data['AuthorName'] ) : ( isset( $plugin_data['Author'] ) ? sanitize_text_field( wp_strip_all_tags( (string) $plugin_data['Author'] ) ) : '' ),
            'network_active'   => $is_network_active,
            'update_available' => ( is_object( $plugin_updates ) && isset( $plugin_updates->response[ $plugin_file ] ) ),

        );
    }

    usort(
        $inventory,
        static function ( $left, $right ) {
            return strcasecmp( (string) $left['name'], (string) $right['name'] );
        }
    );

    return $inventory;
}

/**
 * Get must-use plugins inventory.
 *
 * @return array<int,array<string,mixed>>
 */
private function get_support_diagnostics_mu_plugins_inventory() {
    require_once ABSPATH . 'wp-admin/includes/plugin.php';

    $mu_plugins = function_exists( 'get_mu_plugins' ) ? get_mu_plugins() : array();
    $inventory  = array();

    foreach ( $mu_plugins as $plugin_file => $plugin_data ) {
        $inventory[] = array(
            'file'    => (string) $plugin_file,
            'name'    => isset( $plugin_data['Name'] ) ? sanitize_text_field( (string) $plugin_data['Name'] ) : (string) $plugin_file,
            'version' => isset( $plugin_data['Version'] ) ? sanitize_text_field( (string) $plugin_data['Version'] ) : '',
            'author'  => isset( $plugin_data['AuthorName'] ) ? sanitize_text_field( (string) $plugin_data['AuthorName'] ) : ( isset( $plugin_data['Author'] ) ? sanitize_text_field( wp_strip_all_tags( (string) $plugin_data['Author'] ) ) : '' ),
        );
    }

    usort(
        $inventory,
        static function ( $left, $right ) {
            return strcasecmp( (string) $left['name'], (string) $right['name'] );
        }
    );

    return $inventory;
}

/**
 * Get WordPress drop-ins inventory.
 *
 * @return array<int,array<string,mixed>>
 */
private function get_support_diagnostics_dropins_inventory() {
    require_once ABSPATH . 'wp-admin/includes/plugin.php';

    $dropins   = function_exists( 'get_dropins' ) ? get_dropins() : array();
    $inventory = array();

    foreach ( $dropins as $file => $data ) {
        $inventory[] = array(
            'file'        => (string) $file,
            'name'        => isset( $data['Name'] ) ? sanitize_text_field( (string) $data['Name'] ) : (string) $file,
            'description' => isset( $data['Description'] ) ? sanitize_text_field( wp_strip_all_tags( (string) $data['Description'] ) ) : '',
        );
    }

    usort(
        $inventory,
        static function ( $left, $right ) {
            return strcasecmp( (string) $left['name'], (string) $right['name'] );
        }
    );

    return $inventory;
}

/**
 * Get Noesia modules inventory.
 *
 * @param mixed $modules_manager Modules manager instance.
 * @return array<int,array<string,mixed>>
 */
private function get_support_diagnostics_modules_inventory( $modules_manager ) {
    $inventory = array();

    if ( ! $modules_manager instanceof Noesia_SWA_Modules ) {
        return $inventory;
    }

    foreach ( $modules_manager->get_modules() as $module_id => $module ) {
        $inventory[] = array(
            'id'      => sanitize_key( (string) $module_id ),
            'label'   => method_exists( $module, 'get_label' ) ? sanitize_text_field( wp_strip_all_tags( (string) $module->get_label() ) ) : '',
            'tier'    => method_exists( $module, 'get_tier' ) ? sanitize_key( (string) $module->get_tier() ) : '',
            'enabled' => method_exists( $module, 'is_enabled' ) ? (bool) $module->is_enabled() : false,
            'class'   => get_class( $module ),
        );
    }

    usort(
        $inventory,
        static function ( $left, $right ) {
            return strcasecmp( (string) $left['id'], (string) $right['id'] );
        }
    );

    return $inventory;
}

/**
 * Get a compact non-sensitive Noesia settings summary.
 *
 * @param array<string,mixed> $options Saved options.
 * @return array<string,mixed>
 */
private function get_support_diagnostics_settings_summary( $options ) {
    $options               = is_array( $options ) ? $options : array();
    $bookmark_count        = 0;
    $dock_shortcuts_count  = 0;
    $dock_shortcuts_raw    = isset( $options['quick_dock_url_shortcuts_v1'] ) ? $options['quick_dock_url_shortcuts_v1'] : '[]';
    $dock_shortcuts_decoded = is_string( $dock_shortcuts_raw ) ? json_decode( $dock_shortcuts_raw, true ) : $dock_shortcuts_raw;

    for ( $i = 1; $i <= 8; $i++ ) {
        if ( ! empty( $options[ 'bookmark_' . $i . '_name' ] ) && ! empty( $options[ 'bookmark_' . $i . '_url' ] ) ) {
            $bookmark_count++;
        }
    }

    if ( is_array( $dock_shortcuts_decoded ) ) {
        $dock_shortcuts_count = count( $dock_shortcuts_decoded );
    }

    return array(
        'dashboard_world_live_data_enabled' => isset( $options['dashboard_world_live_data_enabled'] ) ? sanitize_key( (string) $options['dashboard_world_live_data_enabled'] ) : 'no',
        'dashboard_world_live_data_consented_at' => isset( $options['dashboard_world_live_data_consented_at'] ) ? sanitize_text_field( (string) $options['dashboard_world_live_data_consented_at'] ) : '',
        'dashboard_stats_source' => isset( $options['dashboard_stats_source'] ) ? sanitize_key( (string) $options['dashboard_stats_source'] ) : '',
        'news_language'          => isset( $options['news_language'] ) ? sanitize_key( (string) $options['news_language'] ) : '',
        'news_country'           => isset( $options['news_country'] ) ? sanitize_text_field( (string) $options['news_country'] ) : '',
        'weather_city'           => isset( $options['weather_city'] ) ? sanitize_text_field( (string) $options['weather_city'] ) : '',
        'weather_country'        => isset( $options['weather_country'] ) ? sanitize_text_field( (string) $options['weather_country'] ) : '',
        'weather_units'          => isset( $options['weather_units'] ) ? sanitize_key( (string) $options['weather_units'] ) : '',
        'screensaver_enabled'    => isset( $options['screensaver_enabled'] ) ? sanitize_key( (string) $options['screensaver_enabled'] ) : '',
        'screensaver_idle_minutes' => isset( $options['screensaver_idle_minutes'] ) ? absint( $options['screensaver_idle_minutes'] ) : 0,
        'screensaver_show_clock' => isset( $options['screensaver_show_clock'] ) ? sanitize_key( (string) $options['screensaver_show_clock'] ) : '',
        'screensaver_show_updates' => isset( $options['screensaver_show_updates'] ) ? sanitize_key( (string) $options['screensaver_show_updates'] ) : '',
        'bookmark_count'         => $bookmark_count,
        'quick_dock_shortcuts_count' => $dock_shortcuts_count,
    );
}

/**
 * Get module-specific non-sensitive diagnostics.
 *
 * @param array<string,mixed> $options Saved options.
 * @return array<string,mixed>
 */
private function get_support_diagnostics_module_statuses( $options ) {
    $options  = is_array( $options ) ? $options : array();
    $statuses = array();

    if ( class_exists( 'Noesia_Swa_Vision_Ocr_Service' ) ) {
        try {
            $vision_service = new Noesia_Swa_Vision_Ocr_Service();
            $vision_env     = $vision_service->get_environment();

            $statuses['vision'] = array(
                'server_ocr_available'      => ! empty( $vision_env['available'] ),
                'tesseract_binary'          => ! empty( $vision_env['binary'] ) ? (string) $vision_env['binary'] : '',
                'installed_languages'       => isset( $vision_env['languages'] ) && is_array( $vision_env['languages'] ) ? array_values( $vision_env['languages'] ) : array(),
                'default_language'          => isset( $vision_env['default_language'] ) ? (string) $vision_env['default_language'] : '',   
            );
        } catch ( Throwable $throwable ) {
            $statuses['vision'] = array(
                'diagnostics_error' => $throwable->getMessage(),
            );
        }
    }

    if ( class_exists( 'Noesia_SWA_Clinical_Workspace_Settings' ) ) {
        $statuses['clinical_workspace'] = array(
            'openai_key_configured' => ! empty( $options[ Noesia_SWA_Clinical_Workspace_Settings::OPTION_OPENAI_API_KEY ] ),
            'configured_model'      => isset( $options[ Noesia_SWA_Clinical_Workspace_Settings::OPTION_OPENAI_MODEL ] ) ? sanitize_text_field( (string) $options[ Noesia_SWA_Clinical_Workspace_Settings::OPTION_OPENAI_MODEL ] ) : '',
            'dashboard_widget_visible' => ! empty( $options[ Noesia_SWA_Clinical_Workspace_Settings::OPTION_DASHBOARD_WIDGET_VISIBLE ] ),
        );
    }

    return $statuses;
}

/**
 * Get a cURL summary.
 *
 * @return array<string,string>
 */
private function get_support_diagnostics_curl_summary() {
    if ( ! function_exists( 'curl_version' ) ) {
        return array();
    }

    $curl = curl_version();

    if ( ! is_array( $curl ) ) {
        return array();
    }

    return array(
        'version'     => isset( $curl['version'] ) ? sanitize_text_field( (string) $curl['version'] ) : '',
        'ssl_version' => isset( $curl['ssl_version'] ) ? sanitize_text_field( (string) $curl['ssl_version'] ) : '',
        'libz_version'=> isset( $curl['libz_version'] ) ? sanitize_text_field( (string) $curl['libz_version'] ) : '',
    );
}

/**
 * Get a GD summary.
 *
 * @return array<string,mixed>
 */
private function get_support_diagnostics_gd_summary() {
    if ( ! function_exists( 'gd_info' ) ) {
        return array();
    }

    $gd_info = gd_info();

    if ( ! is_array( $gd_info ) ) {
        return array();
    }

    $summary = array();

    foreach ( $gd_info as $key => $value ) {
        $normalized_key = sanitize_key( str_replace( ' ', '_', strtolower( (string) $key ) ) );
        $summary[ $normalized_key ] = is_bool( $value ) ? $value : sanitize_text_field( (string) $value );
    }

    return $summary;
}

/**
 * Get an Imagick summary.
 *
 * @return array<string,mixed>
 */
private function get_support_diagnostics_imagick_summary() {
    if ( ! class_exists( 'Imagick' ) ) {
        return array();
    }

    $version = Imagick::getVersion();

    return array(
        'version_string' => is_array( $version ) && isset( $version['versionString'] ) ? sanitize_text_field( (string) $version['versionString'] ) : '',
    );
}

        /**
         * Register the Settings admin section.
         *
         * @param mixed $registry Admin sections registry.
         * @return void
         */
        public function register_admin_section( $registry ) {
            if ( ! $registry instanceof Noesia_SWA_Admin_Sections ) {
                return;
            }

            $registry->register_section(
                array(
                    'id'          => 'settings',
                    'label'       => $this->get_label(),
                    'nav_label'   => $this->get_label(),
                    'nav_sub'     => '',
                    'icon'        => 'dashicons-admin-generic',
                    'priority'    => 100,
                    'tier'        => 'free',
                    'owner'       => 'settings',
                    'hero'        => false,
                    'is_visible'  => true,
                    'nav_visible' => true,
                    'callback'    => array( $this, 'render_admin' ),
                )
            );
        }


        /**
         * Provide Settings-owned defaults.
         *
         * @param array<string,mixed> $defaults Existing defaults.
         * @param array<string,mixed> $options  Saved options.
         * @param mixed               $admin    Admin instance.
         * @return array<string,mixed>
         */
        public function filter_option_defaults( $defaults, $options, $admin ) {
            if ( ! is_array( $defaults ) ) {
                $defaults = array();
            }

            if ( ! array_key_exists( 'quick_dock_url_shortcuts_v1', $defaults ) ) {
                $defaults['quick_dock_url_shortcuts_v1'] = '[]';
            }

            if ( ! array_key_exists( 'dashboard_world_live_data_enabled', $defaults ) ) {
                $defaults['dashboard_world_live_data_enabled'] = 'no';
            }

            if ( ! array_key_exists( 'delete_all_data_on_uninstall', $defaults ) ) {
                $defaults['delete_all_data_on_uninstall'] = 'no';
            }

            if ( ! array_key_exists( 'dashboard_world_live_data_consented_at', $defaults ) ) {
                $defaults['dashboard_world_live_data_consented_at'] = '';
            }

            if ( ! array_key_exists( 'dashboard_world_live_data_consented_by', $defaults ) ) {
                $defaults['dashboard_world_live_data_consented_by'] = 0;
            }

            return $defaults;
        }

        /**
         * Register the Settings topbar action inside the shared shell.
         *
         * Transitional ownership move:
         * - today the shell may still have default topbar actions
         * - this module now asserts ownership of the settings action metadata
         * - later, kernel defaults can be emptied safely
         *
         * @param array<int,array<string,mixed>>    $actions Existing topbar actions.
         * @param array<string,array<string,mixed>> $sections Registered admin sections.
         * @param array<string,mixed>               $options Saved options.
         * @param mixed                             $shell_data Shell data helper.
         * @return array<int,array<string,mixed>>
         */
        public function filter_topbar_actions( $actions, $sections, $options, $shell_data ) {
            if ( ! is_array( $actions ) ) {
                $actions = array();
            }

            $replacement = array(
                'id'       => 'settings',
                'type'     => 'nav',
                'target'   => 'settings',
                'icon'     => 'dashicons-admin-generic',
                'label'    => __( 'Settings', 'noesia-smart-waiter' ),
                'position' => 'left',
                'priority' => 10,
                'owner'    => 'settings',
            );

            $found = false;

            foreach ( $actions as $index => $action ) {
                if ( ! is_array( $action ) ) {
                    continue;
                }

                $action_id     = isset( $action['id'] ) ? sanitize_key( (string) $action['id'] ) : '';
                $action_target = isset( $action['target'] ) ? sanitize_key( (string) $action['target'] ) : '';

                if ( 'settings' === $action_id || 'settings' === $action_target ) {
                    $actions[ $index ] = array_merge( $action, $replacement );
                    $found             = true;
                    break;
                }
            }

            if ( ! $found ) {
                $actions[] = $replacement;
            }

            return $actions;
        }

        /**
         * Sanitize Settings-owned fields.
         *
         * @param array<string,mixed> $new_input Sanitized output so far.
         * @param array<string,mixed> $input Raw submitted input.
         * @param array<string,mixed> $existing Previously saved options.
         * @param mixed               $admin Admin instance.
         * @return array<string,mixed>
         */
        public function sanitize_settings_fields( $new_input, $input, $existing, $admin ) {
            if ( ! is_array( $new_input ) ) {
                $new_input = array();
            }

            if ( ! is_array( $input ) ) {
                return $new_input;
            }

            $text_fields = array(
                'profile_business_name',
                'profile_host_name',
                'profile_business_type',
                'profile_address',
                'profile_phone',
                'profile_tax_id',
                'profile_registration_no',
            );

            foreach ( $text_fields as $field ) {
                if ( isset( $input[ $field ] ) ) {
                    $new_input[ $field ] = sanitize_text_field( wp_unslash( (string) $input[ $field ] ) );
                }
            }

            if ( isset( $input['profile_email'] ) ) {
                $new_input['profile_email'] = sanitize_email( wp_unslash( (string) $input['profile_email'] ) );
            }

            if ( isset( $input['profile_website'] ) ) {
                $new_input['profile_website'] = esc_url_raw( wp_unslash( (string) $input['profile_website'] ) );
            }

            for ( $i = 1; $i <= 8; $i++ ) {
                $name_key = 'bookmark_' . $i . '_name';
                $url_key  = 'bookmark_' . $i . '_url';

                if ( isset( $input[ $name_key ] ) ) {
                    $new_input[ $name_key ] = sanitize_text_field( wp_unslash( (string) $input[ $name_key ] ) );
                }

                if ( isset( $input[ $url_key ] ) ) {
                    $new_input[ $url_key ] = esc_url_raw( wp_unslash( (string) $input[ $url_key ] ) );
                }
            }

            if ( isset( $input['quick_dock_url_shortcuts_v1'] ) ) {
                $new_input['quick_dock_url_shortcuts_v1'] = $this->sanitize_dock_shortcuts_payload( $input['quick_dock_url_shortcuts_v1'] );
            }

            if ( isset( $input['dashboard_world_live_data_enabled'] ) ) {
                $previous_enabled = isset( $existing['dashboard_world_live_data_enabled'] ) ? sanitize_key( (string) $existing['dashboard_world_live_data_enabled'] ) : 'no';
                $enabled          = sanitize_key( wp_unslash( (string) $input['dashboard_world_live_data_enabled'] ) );

                $new_input['dashboard_world_live_data_enabled'] = ( 'yes' === $enabled ) ? 'yes' : 'no';

                if ( 'yes' === $new_input['dashboard_world_live_data_enabled'] ) {
                    if ( 'yes' !== $previous_enabled || empty( $existing['dashboard_world_live_data_consented_at'] ) ) {
                        $new_input['dashboard_world_live_data_consented_at'] = current_time( 'mysql' );
                        $new_input['dashboard_world_live_data_consented_by'] = get_current_user_id();
                    }
                }
            }

            if ( array_key_exists( 'delete_all_data_on_uninstall', $input ) ) {
                $new_input['delete_all_data_on_uninstall'] = $this->normalize_yes_no_flag( $input['delete_all_data_on_uninstall'] );
            } elseif ( array_key_exists( 'delete_all_data_on_uninstall_control_present', $input ) ) {
                $new_input['delete_all_data_on_uninstall'] = 'no';
            }

            return $new_input;
        }

        /**
         * @param array<mixed> $value Raw array payload.
         * @return array<mixed>
         */

        private function normalize_yes_no_flag( $value ) {
            if ( is_array( $value ) ) {
                foreach ( array_reverse( $value ) as $item ) {
                    if ( 'yes' === $this->normalize_yes_no_flag( $item ) ) {
                        return 'yes';
                    }
                }

                return 'no';
            }

            $safe = sanitize_key( wp_unslash( (string) $value ) );

            return in_array( $safe, array( 'yes', '1', 'true', 'on' ), true ) ? 'yes' : 'no';
        }

        /**
         * Sanitize Dock URL shortcuts payload.
         *
         * @param mixed $value Raw submitted JSON payload.
         * @return string
         */
        private function sanitize_dock_shortcuts_payload( $value ) {
            $decoded = array();
            $allowed_presets = array(
                'custom-url',
                'chrome',
                'whatsapp',
                'gmail',
                'google-drive',
                'youtube',
                'facebook',
                'instagram',
                'tiktok',
                'github',
                'stack-overflow',
            );
            $allowed_icon_modes = array( 'builtin', 'upload' );

            if ( is_string( $value ) ) {
                $decoded = json_decode( wp_unslash( $value ), true );
            } elseif ( is_array( $value ) ) {
                $decoded = $value;
            }

            if ( ! is_array( $decoded ) ) {
                return '[]';
            }

            $sanitized = array();

            foreach ( $decoded as $index => $item ) {
                if ( ! is_array( $item ) ) {
                    continue;
                }

                $id = isset( $item['id'] ) ? sanitize_key( (string) $item['id'] ) : '';
                $label = isset( $item['label'] ) ? sanitize_text_field( wp_unslash( (string) $item['label'] ) ) : '';
                $url = isset( $item['url'] ) ? esc_url_raw( wp_unslash( (string) $item['url'] ) ) : '';
                $preset = isset( $item['preset'] ) ? sanitize_key( (string) $item['preset'] ) : 'custom-url';
                $icon_mode = isset( $item['icon_mode'] ) ? sanitize_key( (string) $item['icon_mode'] ) : 'builtin';
                $icon_key = isset( $item['icon_key'] ) ? sanitize_key( (string) $item['icon_key'] ) : $preset;
                $enabled = ! empty( $item['enabled'] );
                $icon_url = isset( $item['icon_url'] ) ? trim( (string) $item['icon_url'] ) : '';

                if ( '' === $id ) {
                    $id = 'dock-shortcut-' . $index;
                }

                if ( '' === $label || '' === $url ) {
                    continue;
                }

                if ( ! in_array( $preset, $allowed_presets, true ) ) {
                    $preset = 'custom-url';
                }

                if ( ! in_array( $icon_key, $allowed_presets, true ) ) {
                    $icon_key = $preset;
                }

                if ( ! in_array( $icon_mode, $allowed_icon_modes, true ) ) {
                    $icon_mode = 'builtin';
                }

                if ( 'upload' === $icon_mode ) {
                    if ( 0 === strpos( $icon_url, 'data:image/' ) ) {
                        $icon_url = preg_match( '#^data:image/(png|jpeg|jpg|webp|svg\+xml);base64,[A-Za-z0-9+/=
]+$#', $icon_url ) ? $icon_url : '';
                    } else {
                        $icon_url = esc_url_raw( $icon_url );
                    }
                } else {
                    $icon_url = '';
                }

                $sanitized[] = array(
                    'id' => $id,
                    'preset' => $preset,
                    'label' => $label,
                    'url' => $url,
                    'enabled' => $enabled,
                    'icon_mode' => $icon_mode,
                    'icon_key' => $icon_key,
                    'icon_url' => $icon_url,
                );
            }

            return wp_json_encode( array_values( $sanitized ) );
        }

        /**
         * Provide shared shell strings owned by the Settings experience.
         *
         * @param array<string,string> $strings Existing string payload.
         * @param mixed                $admin   Admin instance.
         * @return array<string,string>
         */
        public function filter_admin_strings( $strings, $admin ) {
            if ( ! is_array( $strings ) ) {
                $strings = array();
            }

            $strings['confirm_reset'] = __( "ARE YOU SURE?

This will permanently delete ALL data.
This action cannot be undone.", 'noesia-smart-waiter' );
            $strings['wiping']        = __( 'Wiping database...', 'noesia-smart-waiter' );
            $strings['success_reset'] = __( '✅ Success! All data wiped.', 'noesia-smart-waiter' );
            $strings['error']         = __( '❌ Error: ', 'noesia-smart-waiter' );

            return $strings;
        }

        /**
         * Provide shared shell i18n owned by the Settings experience.
         *
         * @param array<string,string> $i18n Existing i18n payload.
         * @param mixed                $admin Admin instance.
         * @return array<string,string>
         */
        public function filter_admin_i18n( $i18n, $admin ) {
            if ( ! is_array( $i18n ) ) {
                $i18n = array();
            }

            $i18n['factory_confirm_reset'] = __( 'Are you sure?', 'noesia-smart-waiter' );
            $i18n['factory_wiping']        = __( 'Wiping database...', 'noesia-smart-waiter' );
            $i18n['factory_success']       = __( 'Success', 'noesia-smart-waiter' );
            $i18n['factory_unknown_error'] = __( 'Unknown error', 'noesia-smart-waiter' );
            $i18n['factory_error_prefix']  = __( 'Error: ', 'noesia-smart-waiter' );
            $i18n['factory_server_error']  = __( 'Server Error', 'noesia-smart-waiter' );

            $i18n['menu_visibility_title']   = __( 'Enable or disable boxes from menu', 'noesia-smart-waiter' );
            $i18n['menu_visibility_visible'] = __( 'Visible in menu', 'noesia-smart-waiter' );
            $i18n['menu_visibility_hidden']  = __( 'Hidden from menu', 'noesia-smart-waiter' );
            $i18n['menu_visibility_save']    = __( 'Save', 'noesia-smart-waiter' );
            $i18n['menu_visibility_cancel']  = __( 'Cancel', 'noesia-smart-waiter' );
            $i18n['menu_visibility_show']    = __( 'Show in menu', 'noesia-smart-waiter' );
            $i18n['menu_visibility_hide']    = __( 'Hide from menu', 'noesia-smart-waiter' );

            return $i18n;
        }

        /**
         * Provide preferred group ordering for the Settings UI.
         *
         * This moves deterministic group ordering out of the kernel.
         *
         * @param array<int,string>    $groups Existing preference.
         * @param mixed                $helper Settings section data helper.
         * @return array<int,string>
         */
        public function filter_group_order_preference( $groups, $helper ) {
            return array(
                'general',
                'profile',
                'morning-briefing',
                'automation',
                'ui',
                'integrations',
                'advanced',
                'pro',
            );
        }

        /**
         * Render the module-local Settings admin view.
         *
         * @return void
         */
        public function render_admin() {
            $module_view = trailingslashit( __DIR__ ) . 'views/admin.php';
            $legacy_view = NOESIA_SWA_PLUGIN_DIR . 'admin/partials/sections/settings.php';

            /**
             * Fires before the Settings admin module view renders.
             *
             * @param Noesia_Swa_Module_Settings $this Module instance.
             */
            do_action( 'noesia_swa_before_render_settings_admin', $this );

            if ( file_exists( $module_view ) ) {
                include $module_view;

                /**
                 * Fires after the Settings admin module view renders.
                 *
                 * @param Noesia_Swa_Module_Settings $this Module instance.
                 */
                do_action( 'noesia_swa_after_render_settings_admin', $this );
                return;
            }

            if ( file_exists( $legacy_view ) ) {
                include $legacy_view;

                /**
                 * Fires after the Settings legacy fallback view renders.
                 *
                 * @param Noesia_Swa_Module_Settings $this Module instance.
                 */
                do_action( 'noesia_swa_after_render_settings_admin', $this );
                return;
            }

            echo '<div class="noesia-swa-card noesia-swa-card--span2">';
            echo '<div class="noesia-swa-card-header"><div>';
            echo '<h3>' . esc_html__( 'Settings', 'noesia-smart-waiter' ) . '</h3>';
            echo '<p class="noesia-swa-muted">' . esc_html__( 'Module view missing.', 'noesia-smart-waiter' ) . '</p>';
            echo '</div></div>';
            echo '</div>';

            /**
             * Fires after the Settings missing-view fallback renders.
             *
             * @param Noesia_Swa_Module_Settings $this Module instance.
             */
            do_action( 'noesia_swa_after_render_settings_admin', $this );
        }

    }
}
