<?php
/**
 * Widget Renderer for UltraGuard Pro Security Suite
 *
 * This file contains the WidgetRenderer class which handles rendering of all
 * widget components in the UltraGuard Pro dashboard. It provides optimized
 * rendering methods for various widget types including stat cards, data tables,
 * security scores, vulnerability scanners, and other security-related widgets.
 *
 * @package    UltraguardPro\renderers
 * @author     UltraGuard Pro Team <support@ultraguardpro.com>
 * @copyright  2024 UltraGuard Pro Security Solutions
 * @license    GPL-3.0-or-later
 * @version    1.0.0
 * @link       https://ultraguardpro.com/docs/widgets
 */

namespace UltraguardPro\view;

defined( 'ABSPATH' ) || exit;

/**
 * Widget Renderer Class - Optimized Version
 *
 * Handles rendering of all widget components with proper CSS classes, caching,
 * and performance optimizations. Extends BaseRenderer to provide common
 * rendering functionality while adding specialized widget rendering methods.
 *
 * This class implements extensive caching mechanisms for scheme defaults,
 * trend icons, security score levels, and instance management to ensure
 * maximum performance in dashboard rendering. All rendering methods are
 * optimized for speed and include proper capability checks.
 *
 * @package    UltraguardPro\view
 * @author     UltraGuard Pro Team
 * @version    1.0.0
 * @since      1.0.0
 * @see        \UltraguardPro\view\BaseRenderer
 * @see        \UltraguardPro\view\DataLoader
 *
 * @example
 * // Render a stat card widget
 * $stat_card = WidgetRenderer::render_stat_card([
 *     'title' => 'Total Threats',
 *     'value' => 42,
 *     'icon' => 'dashicons-shield-alt',
 *     'trend' => [
 *         'direction' => 'down',
 *         'value' => '12%'
 *     ]
 * ], []);
 */
class WidgetRenderer extends BaseRenderer {

    /**
     * Singleton instance cache for performance optimization
     *
     * Stores a single instance of WidgetRenderer to prevent multiple
     * instantiations and reduce memory usage.
     *
     * @var self|null
     * @access private
     * @static
     */
    private static $instance_cache = null;

    /**
     * Default scheme configurations cache
     *
     * Stores pre-defined scheme configurations for various widget types
     * to avoid repeated array construction and parsing.
     *
     * @var array<string, array>
     * @access private
     * @static
     */
    private static $default_schemes = [];

    /**
     * Trend icon HTML cache
     *
     * Caches rendered trend icon HTML strings by direction to prevent
     * repeated icon generation for similar trend indicators.
     *
     * @var array<string, string>
     * @access private
     * @static
     */
    private static $trend_icons = [];

    /**
     * Security score level definitions cache
     *
     * Stores security score level information (label, color, category)
     * by score value to avoid repeated calculations for the same scores.
     *
     * @var array<string, array{level: string, label: string, color: string}>
     * @access private
     * @static
     */
    private static $security_levels = [];

    /**
     * Get cached singleton instance
     *
     * Returns the singleton instance of WidgetRenderer, creating it
     * if it doesn't exist. This ensures only one instance exists
     * throughout the application lifecycle.
     *
     * @return self  Singleton instance of WidgetRenderer
     * @access private
     * @static
     */
    private static function get_cached_instance() {
        if ( self::$instance_cache === null ) {
            self::$instance_cache = new self();
        }
        return self::$instance_cache;
    }

    /**
     * Get default scheme configuration for widget type
     *
     * Retrieves cached default scheme configuration for a specific widget
     * type. If not cached, creates and caches the default configuration
     * based on the widget type.
     *
     * @param  string $type  Widget type identifier
     * @return array<string, mixed>  Default scheme configuration
     * @access private
     * @static
     *
     * @example
     * $default_scheme = WidgetRenderer::get_default_scheme('stat_card');
     */
    private static function get_default_scheme( $type ) {
        if ( ! isset( self::$default_schemes[ $type ] ) ) {
            switch ( $type ) {
                case 'stat_card':
                    self::$default_schemes[ $type ] = [
                        'class' => '',
                        'title' => '',
                        'description' => '',
                        'icon' => '',
                        'value' => 0,
                        'format' => 'string',
                        'default_value' => '0',
                        'trend' => [
                            'direction' => 'neutral',
                            'value' => '',
                            'text' => ''
                        ]
                    ];
                    break;

                case 'data_table':
                    self::$default_schemes[ $type ] = [
                        'id' => 'table-' . wp_generate_password( 8, false ),
                        'title' => '',
                        'columns' => [],
                        'data' => [],
                        'bulk_actions' => [],
                        'pagination' => [
                            'enabled' => false,
                            'page_size' => 10,
                            'total_items' => 0
                        ],
                        'empty_state' => [
                            'message' => __( 'No data available', 'ultraguard-security-suite' ),
                            'icon' => 'dashicons-database',
                            'loading' => false
                        ]
                    ];
                    break;

                case 'list':
                    self::$default_schemes[ $type ] = [
                        'list_type' => 'ul',
                        'title' => '',
                        'items' => [],
                        'empty_state' => [
                            'message' => __( 'No items available', 'ultraguard-security-suite' ),
                            'icon' => 'dashicons-list-view',
                            'loading' => false
                        ]
                    ];
                    break;

                case 'progress':
                    self::$default_schemes[ $type ] = [
                        'value' => 0,
                        'max' => 100,
                        'progress_type' => 'bar',
                        'status' => 'primary',
                        'animated' => false,
                        'striped' => false,
                        'title' => '',
                        'label' => '',
                        'show_value' => false
                    ];
                    break;

                case 'timeline':
                    self::$default_schemes[ $type ] = [
                        'events' => [],
                        'orientation' => 'vertical',
                        'title' => '',
                        'date_format' => 'M j, Y',
                        'empty_state' => [
                            'message' => __( 'No events available', 'ultraguard-security-suite' ),
                            'icon' => 'dashicons-backup',
                            'loading' => false
                        ]
                    ];
                    break;

                case 'card_grid':
                    self::$default_schemes[ $type ] = [
                        'cards' => [],
                        'columns' => 3,
                        'title' => '',
                        'empty_state' => [
                            'message' => __( 'No cards available', 'ultraguard-security-suite' ),
                            'icon' => 'dashicons-grid-view',
                            'loading' => false
                        ]
                    ];
                    break;

                case 'metric_panel':
                    self::$default_schemes[ $type ] = [
                        'metrics' => [],
                        'title' => '',
                        'empty_state' => [
                            'message' => __( 'No metrics available', 'ultraguard-security-suite' ),
                            'icon' => 'dashicons-chart-bar',
                            'loading' => false
                        ]
                    ];
                    break;

                case 'alert_box':
                    self::$default_schemes[ $type ] = [
                        'alert_type' => 'info',
                        'dismissible' => false,
                        'icon'        => '',
                        'title'       => '',
                        'message'     => '',
                        'actions'     => [],
                    ];
                    break;

                case 'info_panel':
                    self::$default_schemes[ $type ] = [
                        'icon' => '',
                        'title' => '',
                        'description' => '',
                        'actions' => []
                    ];
                    break;

                case 'modal':
                    self::$default_schemes[ $type ] = [
                        'id' => 'modal-' . uniqid(),
                        'title' => '',
                        'content' => '',
                        'footer' => '',
                        'size' => 'medium',
                        'trigger_selector' => ''
                    ];
                    break;

                case 'dropdown':
                    self::$default_schemes[ $type ] = [
                        'trigger' => [],
                        'items' => [],
                        'position' => 'right'
                    ];
                    break;

                case 'terminal':
                    self::$default_schemes[ $type ] = [
                        'title' => 'System Logs',
                        'logs' => [],
                        'height' => '400px',
                        'empty_state' => [
                            'message' => __( 'No logs available', 'ultraguard-security-suite' ),
                            'loading' => false
                        ]
                    ];
                    break;

                case 'security_score':
                    self::$default_schemes[ $type ] = [
                        'value' => 0,
                        'previous_score' => null,
                        'style' => 'circular',
                        'size' => 'medium',
                        'title' => '',
                        'categories' => [],
                        'class' => ''
                    ];
                    break;

                case 'vulnerability_scanner':
                    self::$default_schemes[ $type ] = [
                        'vulnerabilities' => [],
                        'last_scan' => '',
                        'scan_in_progress' => false,
                        'title' => '',
                        'actions' => []
                    ];
                    break;

                case 'login_monitor':
                    self::$default_schemes[ $type ] = [
                        'login_data' => [],
                        'timeframe' => '24h',
                        'title' => ''
                    ];
                    break;

                case 'threat_heatmap':
                    self::$default_schemes[ $type ] = [
                        'threat_data' => [],
                        'period' => '30days',
                        'max_threats' => 0,
                        'title' => ''
                    ];
                    break;

                case 'card':
                    self::$default_schemes[ $type ] = [
                        'class' => '',
                        'title' => '',
                        'icon' => '',
                        'badge' => [
                            'text' => '',
                            'type' => 'info'
                        ],
                        'actions' => [],
                        'data' => [],
                        'content' => '',
                        'footer' => ''
                    ];
                    break;

                default:
                    self::$default_schemes[ $type ] = [];
            }
        }

        return self::$default_schemes[ $type ];
    }

    /**
     * Get cached trend icon HTML
     *
     * Returns HTML for trend direction icons with caching to prevent
     * repeated generation of identical icon markup.
     *
     * @param  string $direction  Trend direction: 'up', 'down', or 'neutral'
     * @return string             HTML markup for trend icon
     * @access private
     * @static
     */
    private static function get_trend_icon_cached( $direction ) {
        $direction = sanitize_key( $direction );

        if ( ! isset( self::$trend_icons[ $direction ] ) ) {
            $instance = self::get_cached_instance();
            switch ( $direction ) {
                case 'up':
                    self::$trend_icons[ $direction ] = $instance->render_ui_icon( 'dashicons-arrow-up' );
                    break;

                case 'down':
                    self::$trend_icons[ $direction ] = $instance->render_ui_icon( 'dashicons-arrow-down' );
                    break;

                case 'neutral':
                default:
                    self::$trend_icons[ $direction ] = $instance->render_ui_icon( 'dashicons-minus' );
                    break;
            }
        }

        return self::$trend_icons[ $direction ];
    }

    /**
     * Shared gathering-state markup.
     *
     * @param string $wrapper_class Wrapper class
     * @param string $min_height    Minimum height
     * @param string $message       Main message
     * @param string $sub_message   Secondary message
     * @return string
     */
    private static function render_gathering_empty(
        string $wrapper_class = '',
        string $min_height = '120px',
        string $message = '',
        string $sub_message = ''
    ): string {
        $instance = self::get_cached_instance();
        $msg      = $message ?: __( 'Gathering data…', 'ultraguard-security-suite' );
        $sub      = $sub_message ?: __( 'Data is being collected. Check back shortly.', 'ultraguard-security-suite' );
        $classes  = trim( 'ultraguard-gathering-empty ' . $wrapper_class );

        return sprintf(
            '<div class="%s" style="min-height:%s;display:flex;align-items:center;'
            . 'justify-content:center;padding:24px 16px;text-align:center;">'
            . '<div style="color:#94a3b8;">'
            . '%s'
            . '<p style="font-size:13px;font-weight:600;margin:0 0 4px;color:#64748b;">%s</p>'
            . '<p style="font-size:12px;margin:0;color:#94a3b8;">%s</p>'
            . '</div></div>',
            esc_attr( $classes ),
            esc_attr( $min_height ),
            $instance->render_ui_icon(
                'dashicons-update',
                'ultraguard-spin-icon',
                [ 'style' => 'font-size:28px;width:28px;height:28px;display:block;margin:0 auto 10px;animation:ultraguard-spin 1.5s linear infinite;' ]
            ),
            esc_html( $msg ),
            esc_html( $sub )
        );
    }


    /**
     * Common capability check for widget rendering
     *
     * Checks if the current user has the required capability to view
     * the widget content. Defaults to 'read' capability.
     *
     * @param  string $capability  Required WordPress capability
     * @return bool                True if user has capability, false otherwise
     * @access private
     * @static
     */
    private static function check_capability( $capability = 'read' ) {
        return 'manage_options' === $capability
            ? \UltraguardPro\ultraguard_current_user_can_manage()
            : current_user_can( $capability );
    }

    /**
     * Render stat card widget - OPTIMIZED
     *
     * Renders a statistics card widget with optional icon, trend indicator,
     * title, and description. Supports various value formats and caching.
     *
     * @param  array<string, mixed> $scheme   Stat card configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered HTML for stat card
     * @access public
     * @static
     *
     * @example
     * $html = WidgetRenderer::render_stat_card([
     *     'title' => 'Active Threats',
     *     'value' => 23,
     *     'format' => 'number',
     *     'icon' => 'dashicons-shield',
     *     'trend' => ['direction' => 'down', 'value' => '5']
     * ], $context);
     */
    public static function render_stat_card( $scheme, $context ) {
        if ( ! self::check_capability() ) {
            return '';
        }

        $instance = self::get_cached_instance();
        $scheme = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, self::get_default_scheme( 'stat_card' ) );

        // Only apply filter if there are listeners
        if ( has_filter( 'ultraguard_stat_card_scheme' ) ) {
            $scheme = apply_filters( 'ultraguard_stat_card_scheme', $scheme, $context );
        }

        // Build class
        $scheme['class'] = ! empty( $scheme['class'] )
            ? $scheme['class'] . ' ultraguard-stat-card'
            : 'ultraguard-stat-card';

        $value = $instance->get_value( $scheme, $context );
        $formatted_value = $instance->format_value( $value, $scheme );

        // Ensure formatted_value is always a string
        if ( is_array( $formatted_value ) || is_object( $formatted_value ) ) {
            // Component array passed as value — extract displayable scalar
            $formatted_value = is_array( $formatted_value )
                ? ( $formatted_value['content'] ?? $formatted_value['text'] ?? $formatted_value['value'] ?? esc_html( wp_json_encode( $formatted_value ) ) )
                : (string) $formatted_value;
        }
        if ( ! is_string( $formatted_value ) ) {
            $formatted_value = (string) $formatted_value;
        }
        // Show gathering overlay if stat value is empty/zero and no trend data exists
        $stat_raw = $scheme['value'] ?? null;
        if ( ( $stat_raw === 0 || $stat_raw === '0' || $stat_raw === null || $stat_raw === '' )
             && empty( $scheme['trend'] )
             && empty( $scheme['force_zero'] ) ) {
            $stat_title_html = ! empty( $scheme['title'] )
                ? '<div class="ultraguard-stat-title">' . esc_html( is_array( $scheme['title'] ) ? (string)( $scheme['title']['text'] ?? $scheme['title']['content'] ?? '' ) : (string) $scheme['title'] ) . '</div>'
                : '';
            return '<div class="ultraguard-stat-card ' . esc_attr( $scheme['class'] ?? '' ) . '">'
                . $stat_title_html
                . self::gathering_empty_html( 'ultraguard-stat-gathering', '80px' )
                . '</div>';
        }

        // Trend indicator - optimized
        $trend_html = '';
        if ( ! empty( $scheme['trend'] ) && is_array( $scheme['trend'] ) ) {
            $trend = wp_parse_args( $scheme['trend'], [
                'direction' => 'neutral',
                'value' => '',
                'text' => ''
            ] );

            $trend_direction = sanitize_key( $trend['direction'] );
            $trend_class = 'ultraguard-trend-' . $trend_direction;
            $trend_icon = self::get_trend_icon_cached( $trend_direction );

            $trend_content = '';

            // Handle trend value
            if ( ! empty( $trend['value'] ) ) {
                $trend_value = $trend['value'];

                if ( is_numeric( $trend_value ) ) {
                    $trend_value_num = (float) $trend_value;
                    $trend_value_formatted = (string) $trend_value_num;

                    if ( 'up' === $trend_direction && $trend_value_num > 0 ) {
                        $trend_value_formatted = '+' . $trend_value_formatted;
                    } elseif ( 'down' === $trend_direction && $trend_value_num > 0 ) {
                        $trend_value_formatted = '-' . $trend_value_formatted;
                    }

                    $trend_content .= '<span class="ultraguard-trend-value">' . esc_html( $trend_value_formatted ) . '</span>';
                } else {
                    $trend_content .= '<span class="ultraguard-trend-value">' . esc_html( $trend_value ) . '</span>';
                }
            }

            if ( ! empty( $trend['text'] ) ) {
                if ( ! empty( $trend_content ) ) {
                    $trend_content .= ' ';
                }
                $trend_content .= '<span class="ultraguard-trend-text">' . esc_html( is_array( $trend['text'] ) ? (string)( $trend['text']['text'] ?? $trend['text']['content'] ?? wp_json_encode( $trend['text'] ) ) : (string)( $trend['text'] ) ) . '</span>';
            }

            if ( ! empty( $trend_content ) ) {
                $trend_html = '<div class="ultraguard-stat-trend ' . esc_attr( $trend_class ) . '">' .
                             $trend_icon . $trend_content . '</div>';
            }
        }

        $icon_html = '';
        if ( ! empty( $scheme['icon'] ) ) {
            $icon_html = '<div class="ultraguard-stat-icon">' . $instance->render_ui_icon( $scheme['icon'] ) . '</div>';
        }

        $title_html = '';
        if ( ! empty( $scheme['title'] ) ) {
            $title_html = '<div class="ultraguard-stat-title">' . esc_html( is_array( $scheme['title'] ) ? (string)( $scheme['title']['text'] ?? $scheme['title']['content'] ?? wp_json_encode( $scheme['title'] ) ) : (string)( $scheme['title'] ) ) . '</div>';
        }

        $description_html = '';
        if ( ! empty( $scheme['description'] ) ) {
            $description_html = '<div class="ultraguard-stat-description">' . esc_html( is_array( $scheme['description'] ) ? (string)( $scheme['description']['text'] ?? $scheme['description']['content'] ?? wp_json_encode( $scheme['description'] ) ) : (string)( $scheme['description'] ) ) . '</div>';
        }

        // Build data-rt attribute for realtime targeting
        $rt_attr = '';
        if ( ! empty( $scheme['realtime'] ) && is_string( $scheme['realtime'] ) ) {
            $rt_attr = ' data-rt="' . esc_attr( $scheme['realtime'] ) . '"';
        }

        // data_attributes['rt'] → outer card wrapper data-rt (for realtime stat updates)
        if ( ! empty( $scheme['data_attributes']['rt'] ) ) {
            $scheme['attributes'] = array_merge(
                is_array( $scheme['attributes'] ?? null ) ? $scheme['attributes'] : [],
                [ 'data-rt' => $scheme['data_attributes']['rt'] ]
            );
        }

        $content = $icon_html .
                  '<div class="ultraguard-stat-content">' .
                  $title_html .
                  '<div class="ultraguard-stat-value"' . $rt_attr . '>' . esc_html( $formatted_value ) . $trend_html . '</div>' .
                  $description_html .
                  '</div>';

        $output = $instance->render_wrapper( $content, $scheme, $context );
        $output = $instance->after_render( $output, $scheme, $context );

        return $output;
    }

    /**
     * Render data table widget - OPTIMIZED
     *
     * Renders a data table with configurable columns, sorting, pagination,
     * and bulk actions. Supports complex data types and empty states.
     *
     * @param  array<string, mixed> $scheme   Data table configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered HTML for data table
     * @access public
     * @static
     *
     * @throws \Exception  When table columns configuration is invalid
     *
     * @example
     * $html = WidgetRenderer::render_data_table([
     *     'title' => 'Security Events',
     *     'columns' => [
     *         'date' => ['title' => 'Date', 'sortable' => true],
     *         'event' => ['title' => 'Event'],
     *         'severity' => ['title' => 'Severity']
     *     ],
     *     'data' => [
     *         ['date' => '2024-01-01', 'event' => 'Brute Force Attempt', 'severity' => 'High']
     *     ]
     * ], $context);
     */
        /**
         * Render data table widget - SERVER-SIDE PAGINATION VERSION
         *
         * Renders a data table with configurable columns, sorting, pagination,
         * and bulk actions. Supports server-side pagination with static links.
         *
         * @param  array<string, mixed> $scheme   Data table configuration scheme
         * @param  array<string, mixed> $context  Rendering context data
         * @return string                         Rendered HTML for data table
         * @access public
         * @static
         */
        public static function render_data_table( $scheme, $context ) {
            if ( ! self::check_capability() ) {
                return '';
            }

            $instance = self::get_cached_instance();
            $scheme = $instance->before_render( $scheme, $context );

            $scheme = wp_parse_args( $scheme, self::get_default_scheme( 'data_table' ) );

            // Only apply filter if there are listeners
            if ( has_filter( 'ultraguard_data_table_scheme' ) ) {
                $scheme = apply_filters( 'ultraguard_data_table_scheme', $scheme, $context );
            }

            $table_id = sanitize_key( $scheme['id'] );

            $title_html = '';
            if ( ! empty( $scheme['title'] ) ) {
                $title_html = '<h4 class="ultraguard-table-title">' . esc_html( is_array( $scheme['title'] ) ? (string)( $scheme['title']['text'] ?? $scheme['title']['content'] ?? wp_json_encode( $scheme['title'] ) ) : (string)( $scheme['title'] ) ) . '</h4>';
            }

            // Validate columns
            if ( empty( $scheme['columns'] ) || ! is_array( $scheme['columns'] ) ) {
                return $instance->render_error(
                    __( 'Invalid table configuration: columns are required', 'ultraguard-security-suite' ),
                    'invalid_columns'
                );
            }

            // Get all data
            $all_data = $scheme['data'];
            $total_items = is_array( $all_data ) ? count( $all_data ) : 0;

            // Handle pagination - SERVER SIDE
            $pagination_enabled = ! empty( $scheme['pagination'] ) && $scheme['pagination']['enabled'];
            $current_page = 1;
            $page_size = 10;
            $total_pages = 1;
            $display_data = [];

            if ( $pagination_enabled && is_array( $all_data ) ) {
                // Get pagination parameters
                $page_size = absint( $scheme['pagination']['page_size'] ?? 10 );

                // Get current page from URL parameters (check multiple possible names)
                $current_page = absint( isset( $_GET['paged'] ) ? $_GET['paged'] : ( isset( $_GET['page'] ) ? $_GET['page'] : ( $context['current_page'] ?? 1 ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only pagination state from current admin URL.

                // Calculate total pages
                $total_pages = $page_size > 0 ? max( 1, ceil( $total_items / $page_size ) ) : 1;

                // Ensure current page is within bounds
                $current_page = max( 1, min( $current_page, $total_pages ) );

                // Slice data for current page - SERVER SIDE SLICING
                if ( $total_items > 0 && $page_size > 0 ) {
                    $start_index = ( $current_page - 1 ) * $page_size;
                    $display_data = array_slice( $all_data, $start_index, $page_size );
                }

                // Update pagination config with calculated values
                $scheme['pagination']['total_items'] = $total_items;
                $scheme['pagination']['current_page'] = $current_page;
                $scheme['pagination']['total_pages'] = $total_pages;
                $scheme['pagination']['page_size'] = $page_size;
            } else {
                // No pagination, show all data
                $display_data = is_array( $all_data ) ? $all_data : [];
            }

            // Build base URL for pagination links
            // Get current admin URL with all parameters
            $current_url = self_admin_url( 'admin.php' );

            // Start with base parameters
            $base_params = [
                'page'    => isset( $_GET['page']    ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : 'ultraguard-security-suite-dashboard', // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only URL state preservation.
                'ug_page' => isset( $_GET['ug_page'] ) ? sanitize_key( wp_unslash( $_GET['ug_page'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only URL state preservation.
            ];

            // Add other parameters except pagination ones — sanitize each value
            foreach ( $_GET as $key => $value ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only query parameter preservation for navigation links.
                if ( in_array( $key, ['paged', 'page', 's', 'sort', 'order', 'page_size'], true ) ) {
                    continue;
                }
                $safe_key = sanitize_key( $key );
                $base_params[ $safe_key ] = is_array( $value )
                    ? array_map( 'sanitize_text_field', $value )
                    : sanitize_text_field( (string) $value );
            }

            $current_url = add_query_arg( $base_params, $current_url );

            // Table header
            $header_html = '';
            // Filter out meta/layout keys that are not real columns
            $non_column_keys = [ 'empty_state', 'pagination', 'filters', 'bulk_actions',
                                 'toolbar', 'search', 'footer', 'title', 'description' ];
            $column_keys = array_diff( array_keys( $scheme['columns'] ), $non_column_keys );
            foreach ( $column_keys as $column_key ) {
                $column_config = $scheme['columns'][ $column_key ];
                $column_config = wp_parse_args( $column_config, [
                    'title' => '',
                    'sortable' => false,
                    'sort_direction' => 'asc',
                    'width' => ''
                ] );

                // Build sort URL if sortable
                $sort_url = '';
                $sort_class = '';
                if ( $column_config['sortable'] ) {
                    $current_sort  = isset( $_GET['sort']  ) ? sanitize_key( wp_unslash( $_GET['sort'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only sort state from URL.
                    $current_order = isset( $_GET['order'] ) ? sanitize_key( wp_unslash( $_GET['order'] ) ) : 'asc'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only sort state from URL.

                    if ( $current_sort === $column_key ) {
                        $sort_class = ' ultraguard-sortable-active';
                        $new_order = $current_order === 'asc' ? 'desc' : 'asc';

                        // Build sort URL with all current parameters
                        $sort_params = $base_params;
                        $sort_params['sort'] = $column_key;
                        $sort_params['order'] = $new_order;
                        $sort_params['paged'] = $current_page; // Keep current page when sorting

                    $sort_url = add_query_arg( $sort_params, self_admin_url( 'admin.php' ) );

                        $sort_class .= ' ultraguard-sort-' . $current_order;
                    } else {
                        // Build sort URL for new sort
                        $sort_params = $base_params;
                        $sort_params['sort'] = $column_key;
                        $sort_params['order'] = 'asc';
                        $sort_params['paged'] = $current_page; // Keep current page when sorting

                    $sort_url = add_query_arg( $sort_params, self_admin_url( 'admin.php' ) );
                    }
                }

                $style_attr = ! empty( $column_config['width'] ) ? ' style="width:' . esc_attr( $column_config['width'] ) . ';"' : '';

                $header_html .= '<th class="ultraguard-column-' . esc_attr( sanitize_key( $column_key ) ) .
                               ( $column_config['sortable'] ? ' ultraguard-sortable' . $sort_class : '' ) .
                               '" data-column="' . esc_attr( $column_key ) . '"' . $style_attr . '>';

                if ( $column_config['sortable'] && $sort_url ) {
                    $header_html .= '<a href="' . esc_url( $sort_url ) . '" class="ultraguard-sort-link">';
                }

                $header_html .= esc_html( is_array( $column_config['title'] ) ? (string)( $column_config['title']['text'] ?? $column_config['title']['content'] ?? wp_json_encode( $column_config['title'] ) ) : (string)( $column_config['title'] ) );

                if ( $column_config['sortable'] ) {
                    $sort_indicator = '';
                    if ( $sort_class ) {
                        if ( strpos( $sort_class, 'ultraguard-sort-asc' ) !== false ) {
                            $sort_indicator = '&uarr;';
                        } elseif ( strpos( $sort_class, 'ultraguard-sort-desc' ) !== false ) {
                            $sort_indicator = '&darr;';
                        }
                    }
                    $header_html .= '<span class="ultraguard-sort-indicator">' . $sort_indicator . '</span>';
                }

                if ( $column_config['sortable'] && $sort_url ) {
                    $header_html .= '</a>';
                }

                $header_html .= '</th>';
            }

            // Table body
            $body_html = '';
            $has_data = ! empty( $display_data ) && is_array( $display_data );

            if ( $has_data ) {
                foreach ( $display_data as $index => $row ) {
                    if ( ! is_array( $row ) ) {
                        continue;
                    }

                    $row_html = '';

                    foreach ( $column_keys as $column_key ) {
                        $cell_value = $row[ $column_key ] ?? '';
                        $cell_content = '';

                        if ( is_array( $cell_value ) ) {
                            if ( isset( $cell_value['type'] ) ) {
                                // Full component schema — delegate to render engine
                                $cell_content = $instance->engine->render( $cell_value, $context );

                            } elseif ( isset( $cell_value[0] ) && is_array( $cell_value[0] ) && isset( $cell_value[0]['type'] ) ) {
                                // Array of component schemas
                                foreach ( $cell_value as $component ) {
                                    $cell_content .= $instance->engine->render( $component, $context );
                                }

                            } elseif ( array_key_exists( 'content', $cell_value ) ) {
                                // Shorthand cell: ['id' => '...', 'content' => '...|array', 'class' => '...']
                                // Used widely by page classes as the standard cell-value convention.
                                $raw_content = $cell_value['content'];
                                $cell_class  = isset( $cell_value['class'] )
                                ? ' ' . esc_attr( is_array( $cell_value['class'] ) ? implode( ' ', array_map( 'sanitize_html_class', $cell_value['class'] ) ) : sanitize_html_class( $cell_value['class'] ) )
                                : '';

                                if ( is_array( $raw_content ) ) {
                                    // Nested component or array of components
                                    if ( isset( $raw_content['type'] ) ) {
                                        // Full component schema (badge, button, etc.)
                                        $inner = $instance->engine->render( $raw_content, $context );
                                    } elseif ( isset( $raw_content['badge_type'] ) ) {
                                        // Inline badge shorthand: ['badge_type'=>'danger','content'=>'Malicious']
                                        $inner = sprintf(
                                            '<span class="ultraguard-badge ultraguard-badge-%s">%s</span>',
                                            esc_attr( sanitize_key( $raw_content['badge_type'] ) ),
                                            esc_html( is_scalar( $raw_content['content'] ?? '' ) ? (string)( $raw_content['content'] ?? '' ) : '' )
                                        );
                                    } elseif ( isset( $raw_content[0] ) && is_array( $raw_content[0] ) && isset( $raw_content[0]['type'] ) ) {
                                        $inner = '';
                                        foreach ( $raw_content as $sub ) {
                                            $inner .= $instance->engine->render( $sub, $context );
                                        }
                                    } else {
                                        $inner = esc_html( wp_json_encode( $raw_content ) );
                                    }
                                } else {
                                    // Scalar — may contain safe HTML (e.g. action buttons rendered as HTML)
                                    $inner = wp_kses_post( (string) $raw_content );
                                }

                                $cell_id_attr = isset( $cell_value['id'] ) ? ' id="' . esc_attr( $cell_value['id'] ) . '"' : '';
                                $cell_content = '<span' . $cell_id_attr . ' class="ultraguard-cell-inner' . $cell_class . '">' . $inner . '</span>';

                            } elseif ( isset( $cell_value['text'] ) ) {
                                // Badge/label shorthand: ['text' => '...', 'badge_type' => '...']
                                $badge_type   = sanitize_key( $cell_value['badge_type'] ?? 'secondary' );
                                $cell_content = sprintf(
                                    '<span class="ultraguard-badge ultraguard-badge-%s">%s</span>',
                                    esc_attr( $badge_type ),
                                    esc_html( is_array( $cell_value['text'] ) ? (string)( $cell_value['text']['text'] ?? $cell_value['text']['content'] ?? wp_json_encode( $cell_value['text'] ) ) : (string)( $cell_value['text'] ) )
                                );

                            } elseif ( isset( $cell_value['label'] ) ) {
                                // Simple label shorthand
                                $cell_content = esc_html( is_array( $cell_value['label'] ) ? (string)( $cell_value['label']['text'] ?? $cell_value['label']['content'] ?? wp_json_encode( $cell_value['label'] ) ) : (string)( $cell_value['label'] ) );

                            } elseif ( isset( $cell_value['html'] ) ) {
                                // Raw-HTML shorthand: ['html' => '<...>']
                                $cell_content = is_array( $cell_value['html'] ) ? esc_html( wp_json_encode( $cell_value['html'] ) ) : wp_kses_post( (string) $cell_value['html'] );

                            } elseif ( isset( $cell_value['message'] ) ) {
                                // 'message' key — used by many page classes as the cell content holder
                                $msg = $cell_value['message'];
                                $cell_id_attr = isset( $cell_value['id'] ) ? ' id="' . esc_attr( $cell_value['id'] ) . '"' : '';
                                if ( is_array( $msg ) && isset( $msg['type'] ) ) {
                                    // Component schema inside message (e.g. badge)
                                    $cell_content = $instance->engine->render( $msg, $context );
                                } elseif ( is_array( $msg ) && isset( $msg['badge_type'] ) ) {
                                    // Inline badge shorthand: ['badge_type'=>'danger', 'content'=>'Malicious']
                                    $cell_content = sprintf(
                                        '<span class="ultraguard-badge ultraguard-badge-%s">%s</span>',
                                        esc_attr( sanitize_key( $msg['badge_type'] ) ),
                                        esc_html( is_scalar( $msg['content'] ?? '' ) ? (string)( $msg['content'] ?? '' ) : '' )
                                    );
                                } elseif ( is_string( $msg ) ) {
                                    $cell_content = $cell_id_attr
                                        ? '<span' . $cell_id_attr . '>' . wp_kses_post( $msg ) . '</span>'
                                        : wp_kses_post( $msg );
                                } else {
                                    $cell_content = esc_html( wp_json_encode( $msg ) );
                                }
                            } else {
                                // Unrecognised array — render as readable JSON (never show raw [Complex Data])
                                $cell_content = '<code class="ultraguard-cell-json">'
                                    . esc_html( wp_json_encode( $cell_value, JSON_PRETTY_PRINT ) )
                                    . '</code>';
                            }
                        } elseif ( is_object( $cell_value ) ) {
                            $cell_content = '<code class="ultraguard-cell-json">'
                                . esc_html( wp_json_encode( $cell_value ) )
                                . '</code>';
                        } else {
                            // Scalar — allow safe HTML (buttons, badges rendered by page classes)
                            $scalar_content = wp_kses_post( (string) $cell_value );
                            if ( false === strpos( $scalar_content, '<' ) ) {
                                $cell_content = '<span class="ultraguard-cell-inner">' . $scalar_content . '</span>';
                            } else {
                                $cell_content = $scalar_content;
                            }
                        }

                        $row_html .= '<td class="ultraguard-cell-' . esc_attr( sanitize_key( $column_key ) ) . '">' .
                                    $cell_content . '</td>';
                    }

                    // Apply row-level id and data-* attributes to the <tr>
                    $tr_attrs = 'class="ultraguard-table-row"';
                    if ( ! empty( $row['id'] ) ) {
                        $tr_attrs .= ' id="' . esc_attr( $row['id'] ) . '"';
                    }
                    foreach ( $row as $rk => $rv ) {
                        if ( str_starts_with( (string)$rk, 'data-' ) && is_scalar( $rv ) ) {
                            $tr_attrs .= ' ' . esc_attr( $rk ) . '="' . esc_attr( (string)$rv ) . '"';
                        }
                    }
                    $body_html .= '<tr ' . $tr_attrs . '>' . $row_html . '</tr>';
                }
            } else {
                // Use filtered column count to match actual rendered columns
                $colspan = count( array_diff( array_keys( $scheme['columns'] ), [ 'empty_state', 'pagination', 'filters', 'bulk_actions', 'toolbar', 'search', 'footer', 'title', 'description' ] ) );
                $empty_state = wp_parse_args( $scheme['empty_state'], [
                    'title' => __( 'No data available', 'ultraguard-security-suite' ),
                    'description' => '',
                    'icon' => 'dashicons-database',
                    'loading' => false
                ] );

                // Show gathering overlay if data is empty (respects custom message from empty_state)
                $custom_title = $empty_state['title'] ?? '';
                $custom_desc  = $empty_state['description'] ?? '';
                $is_default_msg = ( $custom_title === __( 'No data available', 'ultraguard-security-suite' ) || empty( $custom_title ) );
                $gathering_html = self::gathering_empty_html(
                    'ultraguard-table-gathering',
                    '120px',
                    $is_default_msg ? '' : ( is_array( $custom_title ) ? ( $custom_title['text'] ?? '' ) : (string) $custom_title ),
                    $is_default_msg ? '' : ( is_array( $custom_desc ) ? ( $custom_desc['text'] ?? '' ) : (string) $custom_desc )
                );
                $body_html = '<tr><td colspan="' . absint( $colspan ) . '" style="padding:0;border:none;">' .
                             $gathering_html . '</td></tr>';
            }

            // Bulk actions
            $bulk_actions_html = '';
            if ( $has_data && ! empty( $scheme['bulk_actions'] ) && is_array( $scheme['bulk_actions'] ) ) {
                $bulk_options = '<option value="">' . esc_html__( 'Bulk Actions', 'ultraguard-security-suite' ) . '</option>';
                foreach ( $scheme['bulk_actions'] as $action_value => $action_label ) {
                    // action_label may be a plain string or an array {'label':..., 'ajax':...}
                    $label_text = is_array( $action_label )
                        ? ( $action_label['label'] ?? $action_label['text'] ?? $action_value )
                        : $action_label;
                    $bulk_options .= '<option value="' . esc_attr( $action_value ) . '">' . esc_html( (string)$label_text ) . '</option>';
                }

                $bulk_actions_html = '<div class="ultraguard-bulk-actions">' .
                                    '<select class="ultraguard-bulk-action-select">' . $bulk_options . '</select>' .
                                    '<button type="button" class="button ultraguard-bulk-action-apply">' .
                                    esc_html__( 'Apply', 'ultraguard-security-suite' ) . '</button>' .
                                    '<button type="button" class="button ultraguard-bulk-action-select-all">' .
                                    esc_html__( 'Select All', 'ultraguard-security-suite' ) . '</button>' .
                                    '</div>';
            }

            // Search box with server-side search
            $search_html = '';
            if ( ! empty( $scheme['searchable'] ) ) {
                $search_placeholder = ! empty( $scheme['search_placeholder'] ) ?
                    esc_attr( $scheme['search_placeholder'] ) :
                    __( 'Search...', 'ultraguard-security-suite' );

                $current_search = sanitize_text_field( wp_unslash( $_GET['s'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only search state from URL.
                $search_value = esc_attr( $current_search );

                // Build search form URL
                $search_params = $base_params;
                if ( $current_search ) {
                    $search_params['s'] = $current_search;
                }
                $search_params['paged'] = 1; // Reset to page 1 when searching

                $search_form_url = add_query_arg( $search_params, self_admin_url( 'admin.php' ) );
                $clear_search_url = add_query_arg( $base_params, self_admin_url( 'admin.php' ) );

                $search_html = '<div class="ultraguard-table-search">' .
                              '<form method="get" action="' . esc_url( self_admin_url( 'admin.php' ) ) . '" class="ultraguard-search-form">' .
                              '<input type="hidden" name="page" value="' . esc_attr( $base_params['page'] ) . '" />' .
                              '<input type="hidden" name="ug_page" value="' . esc_attr( $base_params['ug_page'] ) . '" />' .
                              $instance->get_hidden_inputs_except( ['page', 'ug_page', 's', 'paged', 'page_size'] ) .
                              '<input type="search" name="s" class="ultraguard-search-input" ' .
                              'placeholder="' . $search_placeholder . '" value="' . $search_value . '" ' .
                              'autocomplete="off" spellcheck="false" />' .
                              '<button type="submit" class="button ultraguard-search-button">' .
                              $instance->render_ui_icon( 'dashicons-search', '', [ 'style' => 'font-size:15px;width:15px;height:15px;margin:0;vertical-align:middle;' ] ) .
                              ' ' . esc_html__( 'Search', 'ultraguard-security-suite' ) . '</button>';

                if ( $current_search ) {
                    $search_html .= '<a href="' . esc_url( $clear_search_url ) . '" class="button ultraguard-search-clear" title="' . esc_attr__( 'Clear search', 'ultraguard-security-suite' ) . '">' .
                                   $instance->render_ui_icon( 'dashicons-no-alt', '', [ 'style' => 'font-size:15px;width:15px;height:15px;margin:0;' ] ) .
                                   ' ' . esc_html__( 'Clear', 'ultraguard-security-suite' ) . '</a>';
                }

                $search_html .= '</form></div>';
            }

            // Pagination HTML (Server-side with static links)
            $pagination_html = '';
            if ( $pagination_enabled && $total_pages > 1 ) {
                $pagination_html = $instance->render_server_side_pagination( $current_page, $total_pages, $total_items, $table_id, $base_params );
            }

            // Page info
            $page_info_html = '';
            if ( $pagination_enabled && $total_items > 0 ) {
                $start_item = ( $current_page - 1 ) * $page_size + 1;
                $end_item = min( $current_page * $page_size, $total_items );

                $page_info_html = '<div class="ultraguard-page-info">' .
                                 sprintf(
                                     /* translators: Placeholder values are inserted into this string. */
                                     __( 'Showing %1$d-%2$d of %3$d items', 'ultraguard-security-suite' ),
                                     $start_item,
                                     $end_item,
                                     $total_items
                                 ) .
                                 '</div>';
            }

            // Only render toolbar if there's something to put in it
            $has_toolbar = ! empty( $bulk_actions_html ) || ! empty( $search_html );
            $toolbar_html = $has_toolbar
                ? '<div class="ultraguard-table-toolbar">' . $bulk_actions_html . $search_html . '</div>'
                : '';

            $content = $title_html .
                      '<div class="ultraguard-table-wrapper">' .
                      $toolbar_html .
                      '<div class="ultraguard-table-container">' .
                      '<table id="' . esc_attr( $table_id ) . '" class="ultraguard-data-table">' .
                      '<thead><tr>' . $header_html . '</tr></thead>' .
                      '<tbody>' . $body_html . '</tbody>' .
                      '</table>' .
                      '</div>' .
                      '<div class="ultraguard-table-footer">' .
                      $page_info_html .
                      $pagination_html .
                      '</div>' .
                      '</div>';

            $output = $instance->render_wrapper( $content, $scheme, $context );
            $output = $instance->after_render( $output, $scheme, $context );

            return $output;
        }

/**
 * Render server-side pagination with static links
 *
 * @param  int    $current_page  Current page number
 * @param  int    $total_pages   Total number of pages
 * @param  int    $total_items   Total number of items
 * @param  string $table_id      Table ID
 * @param  array  $base_params   Base parameters for URLs
 * @return string               Rendered pagination HTML
 * @access protected
 */
protected function render_server_side_pagination( $current_page, $total_pages, $total_items, $table_id, $base_params ) {
    if ( $total_pages <= 1 ) {
        return '';
    }

    $pagination_html = '<div class="ultraguard-pagination ultraguard-pagination-server">';

    // Previous button
    if ( $current_page > 1 ) {
        $prev_params = $base_params;
        $prev_params['paged'] = $current_page - 1;
                    $prev_url = add_query_arg( $prev_params, self_admin_url( 'admin.php' ) );
        $pagination_html .= '<a href="' . esc_url( $prev_url ) . '" class="ultraguard-pagination-prev button">' .
                           '&laquo; ' . esc_html__( 'Previous', 'ultraguard-security-suite' ) . '</a>';
    } else {
        $pagination_html .= '<span class="ultraguard-pagination-prev button disabled">' .
                           '&laquo; ' . esc_html__( 'Previous', 'ultraguard-security-suite' ) . '</span>';
    }

    // Page numbers
    $max_pages_to_show = 7;
    $start_page = max( 1, $current_page - floor( $max_pages_to_show / 2 ) );
    $end_page = min( $total_pages, $start_page + $max_pages_to_show - 1 );

    // Adjust start page if we're near the end
    if ( $end_page - $start_page + 1 < $max_pages_to_show ) {
        $start_page = max( 1, $end_page - $max_pages_to_show + 1 );
    }

    // First page
    if ( $start_page > 1 ) {
        $first_params = $base_params;
        $first_params['paged'] = 1;
                    $first_url = add_query_arg( $first_params, self_admin_url( 'admin.php' ) );
        $pagination_html .= '<a href="' . esc_url( $first_url ) . '" class="ultraguard-pagination-page button" title="' .
                           esc_attr__( 'First page', 'ultraguard-security-suite' ) . '">1</a>';

        if ( $start_page > 2 ) {
            $pagination_html .= '<span class="ultraguard-pagination-ellipsis">...</span>';
        }
    }

    // Page numbers
    for ( $i = $start_page; $i <= $end_page; $i++ ) {
        if ( $i === $current_page ) {
            $pagination_html .= '<span class="ultraguard-pagination-page button active">' . absint( $i ) . '</span>';
        } else {
            $page_params = $base_params;
            $page_params['paged'] = $i;
                    $page_url = add_query_arg( $page_params, self_admin_url( 'admin.php' ) );
            $pagination_html .= '<a href="' . esc_url( $page_url ) . '" class="ultraguard-pagination-page button" title="' .
                               esc_attr__( 'Page ', 'ultraguard-security-suite' ) . absint( $i ) . '">' . absint( $i ) . '</a>';
        }
    }

    // Last page
    if ( $end_page < $total_pages ) {
        if ( $end_page < $total_pages - 1 ) {
            $pagination_html .= '<span class="ultraguard-pagination-ellipsis">...</span>';
        }

        $last_params = $base_params;
        $last_params['paged'] = $total_pages;
                    $last_url = add_query_arg( $last_params, self_admin_url( 'admin.php' ) );
        $pagination_html .= '<a href="' . esc_url( $last_url ) . '" class="ultraguard-pagination-page button" title="' .
                           esc_attr__( 'Last page', 'ultraguard-security-suite' ) . '">' . absint( $total_pages ) . '</a>';
    }

    // Next button
    if ( $current_page < $total_pages ) {
        $next_params = $base_params;
        $next_params['paged'] = $current_page + 1;
                    $next_url = add_query_arg( $next_params, self_admin_url( 'admin.php' ) );
        $pagination_html .= '<a href="' . esc_url( $next_url ) . '" class="ultraguard-pagination-next button">' .
                           esc_html__( 'Next', 'ultraguard-security-suite' ) . ' &raquo;</a>';
    } else {
        $pagination_html .= '<span class="ultraguard-pagination-next button disabled">' .
                           esc_html__( 'Next', 'ultraguard-security-suite' ) . ' &raquo;</span>';
    }

    $pagination_html .= '</div>';

    // Page size selector (will trigger page reload)
    $current_page_size = isset( $_GET['page_size'] ) ? absint( $_GET['page_size'] ) : 10; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only page size state from URL.
    $page_sizes = [10, 25, 50, 100];

    $page_size_options = '';
    foreach ( $page_sizes as $size ) {
        $selected = $size === $current_page_size ? ' selected' : '';
        $page_size_options .= '<option value="' . absint( $size ) . '"' . $selected . '>' . absint( $size ) . '</option>';
    }

    // Page size form - reset to page 1 when changing page size
    $page_size_params = $base_params;
    $page_size_params['paged'] = 1;
                $page_size_form_url = add_query_arg( $page_size_params, self_admin_url( 'admin.php' ) );

    $pagination_html .= '<div class="ultraguard-page-size-form">' .
                                '<form method="get" action="' . esc_url( self_admin_url( 'admin.php' ) ) . '" class="ultraguard-page-size-form-inline">' .
                       '<input type="hidden" name="page" value="' . esc_attr( $base_params['page'] ) . '" />' .
                       '<input type="hidden" name="ug_page" value="' . esc_attr( $base_params['ug_page'] ) . '" />' .
                       '<input type="hidden" name="paged" value="1" />' . // Always reset to page 1
                       $this->get_hidden_inputs_except( ['page', 'ug_page', 'paged', 'page_size'] ) .
                       '</form>' .
                       '</div>';

    return $pagination_html;
}

/**
 * Get hidden inputs for forms (preserve query parameters except excluded ones)
 *
 * @param  array $exclude  Parameters to exclude from hidden inputs
 * @return string          Hidden input HTML
 * @access protected
 */
protected function get_hidden_inputs_except( $exclude = [] ) {
    $hidden_html = '';

    foreach ( $_GET as $key => $value ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only query parameter preservation for forms.
        // Skip excluded parameters
        if ( in_array( $key, $exclude ) ) {
            continue;
        }

        // Skip empty values
        if ( empty( $value ) && $value !== '0' ) {
            continue;
        }

        if ( is_array( $value ) ) {
            foreach ( $value as $val ) {
                $hidden_html .= '<input type="hidden" name="' . esc_attr( $key ) . '[]" value="' . esc_attr( $val ) . '" />';
            }
        } else {
            $hidden_html .= '<input type="hidden" name="' . esc_attr( $key ) . '" value="' . esc_attr( $value ) . '" />';
        }
    }

    return $hidden_html;
}
    /**
     * Get hidden inputs for forms (preserve query parameters)
     *
     * @param  array $exclude  Parameters to exclude from hidden inputs
     * @return string          Hidden input HTML
     * @access protected
     */
    protected function get_hidden_inputs( $exclude = [] ) {
        $hidden_html = '';
        $exclude = array_merge( $exclude, ['s', 'page_size', 'paged', 'page', 'sort', 'order'] );

        foreach ( $_GET as $key => $value ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only query parameter preservation for forms.
            if ( in_array( $key, $exclude ) ) {
                continue;
            }

            if ( is_array( $value ) ) {
                foreach ( $value as $val ) {
                    $hidden_html .= '<input type="hidden" name="' . esc_attr( $key ) . '[]" value="' . esc_attr( $val ) . '" />';
                }
            } else {
                $hidden_html .= '<input type="hidden" name="' . esc_attr( $key ) . '" value="' . esc_attr( $value ) . '" />';
            }
        }

        return $hidden_html;
    }
    /**
     * Render list widget - OPTIMIZED
     *
     * Renders an ordered or unordered list with optional icons and badges.
     * Supports empty states and loading indicators.
     *
     * @param  array<string, mixed> $scheme   List configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered HTML for list
     * @access public
     * @static
     *
     * @example
     * $html = WidgetRenderer::render_list([
     *     'list_type' => 'ul',
     *     'title' => 'Security Rules',
     *     'items' => [
     *         ['icon' => 'dashicons-yes', 'text' => 'Firewall Enabled', 'badge' => 'Active'],
     *         ['icon' => 'dashicons-no', 'text' => 'Brute Force Protection', 'badge' => 'Disabled']
     *     ]
     * ], $context);
     */
    public static function render_list( $scheme, $context ) {
        if ( ! self::check_capability() ) {
            return '';
        }

        $instance = self::get_cached_instance();
        $scheme = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, self::get_default_scheme( 'list' ) );

        // Only apply filter if there are listeners
        if ( has_filter( 'ultraguard_list_scheme' ) ) {
            $scheme = apply_filters( 'ultraguard_list_scheme', $scheme, $context );
        }

        $list_type = sanitize_key( $scheme['list_type'] );
        $items = $scheme['items'];

        $title_html = '';
        if ( ! empty( $scheme['title'] ) ) {
            $title_html = '<h4 class="ultraguard-list-title">' . esc_html( is_array( $scheme['title'] ) ? (string)( $scheme['title']['text'] ?? $scheme['title']['content'] ?? wp_json_encode( $scheme['title'] ) ) : (string)( $scheme['title'] ) ) . '</h4>';
        }

        $items_html = '';
        $has_items = false;

        if ( is_array( $items ) && ! empty( $items ) ) {
            foreach ( $items as $item ) {
                if ( ! is_array( $item ) ) {
                    continue;
                }

                $item = wp_parse_args( $item, [
                    'icon' => '',
                    'badge' => '',
                    'text' => ''
                ] );

                $icon_html = '';
                if ( ! empty( $item['icon'] ) ) {
                    $icon_html = $instance->render_ui_icon( $item['icon'] );
                }

                $badge_html = '';
                if ( ! empty( $item['badge'] ) ) {
                    if ( is_array( $item['badge'] ) ) {
                        $badge_text = $item['badge']['text'] ?? $item['badge']['content'] ?? '';
                        $badge_type = $item['badge']['badge_type'] ?? '';
                        $badge_html = sprintf(
                            '<span class="ultraguard-list-badge ultraguard-badge-%s">%s</span>',
                            esc_attr( sanitize_key( $badge_type ) ),
                            esc_html( is_scalar( $badge_text ) ? (string) $badge_text : '' )
                        );
                    } else {
                        $badge_html = '<span class="ultraguard-list-badge">' . esc_html( (string) $item['badge'] ) . '</span>';
                    }
                }

                $item_text = is_array( $item['text'] ) ? esc_html( (string) ( $item['text']['text'] ?? $item['text']['content'] ?? wp_json_encode( $item['text'] ) ) ) : esc_html( (string) $item['text'] );
                $text_html = '<span class="ultraguard-list-item-text">' . $item_text . '</span>';

                // Optional badge_type on the item itself (separate from badge field)
                $item_class = 'ultraguard-list-item';

                // Render per-item actions
                $actions_html_li = '';
                if ( ! empty( $item['actions'] ) && is_array( $item['actions'] ) ) {
                    $actions_out = '';
                    foreach ( $item['actions'] as $action ) {
                        if ( is_array( $action ) ) {
                            $actions_out .= $instance->engine->render( $action, $context );
                        }
                    }
                    if ( $actions_out ) {
                        $actions_html_li = '<span class="ultraguard-list-item-actions">' . $actions_out . '</span>';
                    }
                }

                $items_html .= '<li class="' . esc_attr( $item_class ) . '">' . $icon_html . $text_html . $badge_html . $actions_html_li . '</li>';
                $has_items = true;
            }
        }

        // Handle empty state
        if ( ! $has_items ) {
            $empty_state = wp_parse_args( $scheme['empty_state'], [
                'message' => __( 'No items available', 'ultraguard-security-suite' ),
                'icon' => 'dashicons-list-view',
                'loading' => false
            ] );

            // Show gathering overlay when no list data available
        $custom_title = $empty_state['title'] ?? '';
        $custom_desc  = $empty_state['description'] ?? '';
        $items_html = self::gathering_empty_html(
            'ultraguard-list-gathering',
            '80px',
            empty( $custom_title ) ? '' : ( is_array( $custom_title ) ? ( $custom_title['text'] ?? '' ) : (string) $custom_title ),
            empty( $custom_desc  ) ? '' : ( is_array( $custom_desc  ) ? ( $custom_desc['text']  ?? '' ) : (string) $custom_desc  )
        );
        }

        $content = $title_html .
                  '<' . $list_type . ' class="ultraguard-list">' . $items_html . '</' . $list_type . '>';

        $output = $instance->render_wrapper( $content, $scheme, $context );
        $output = $instance->after_render( $output, $scheme, $context );

        return $output;
    }

    /**
     * Render progress widget - OPTIMIZED
     *
     * Renders a progress bar or circle with configurable styling, animation,
     * and value display. Supports both linear and circular progress indicators.
     *
     * @param  array<string, mixed> $scheme   Progress configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered HTML for progress widget
     * @access public
     * @static
     *
     * @example
     * $html = WidgetRenderer::render_progress([
     *     'title' => 'Security Scan Progress',
     *     'value' => 75,
     *     'max' => 100,
     *     'progress_type' => 'bar',
     *     'status' => 'success',
     *     'animated' => true,
     *     'label' => 'Scanning files...'
     * ], $context);
     */
    public static function render_progress( $scheme, $context ) {
        if ( ! self::check_capability() ) {
            return '';
        }

        $instance = self::get_cached_instance();
        $scheme = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, self::get_default_scheme( 'progress' ) );

        // Only apply filter if there are listeners
        if ( has_filter( 'ultraguard_progress_scheme' ) ) {
            $scheme = apply_filters( 'ultraguard_progress_scheme', $scheme, $context );
        }

        $value = (float) $scheme['value'];
        $max = (float) $scheme['max'];
        $percentage = $max > 0 ? ( $value / $max ) * 100 : 0;
        // Show gathering overlay when both value and max are 0 (no data yet)
        if ( $value === 0.0 && $max === 0.0 && empty( $scheme['force_zero'] ) ) {
            $prog_title = ! empty( $scheme['title'] )
                ? '<div class="ultraguard-security-suitegress-title">' . esc_html( is_array( $scheme['title'] ) ? (string)( $scheme['title']['text'] ?? '' ) : (string) $scheme['title'] ) . '</div>'
                : '';
            return $prog_title . self::gathering_empty_html( 'ultraguard-security-suitegress-gathering', '60px' );
        }

        $progress_type = sanitize_key( $scheme['progress_type'] );
        $status = sanitize_key( $scheme['status'] );
        $animated = (bool) $scheme['animated'];
        $striped = (bool) $scheme['striped'];

        // Build CSS classes - optimized
        $progress_classes = array( 'ultraguard-security-suitegress' );
        $bar_classes = array( 'ultraguard-security-suitegress-bar' );

        if ( $status ) {
            $bar_classes[] = 'ultraguard-security-suitegress-' . $status;
        }

        if ( $animated && 'bar' === $progress_type ) {
            $progress_classes[] = 'ultraguard-security-suitegress-animated';
        }

        if ( $striped && 'bar' === $progress_type ) {
            $progress_classes[] = 'ultraguard-security-suitegress-striped';
        }

        $title_html = '';
        if ( ! empty( $scheme['title'] ) ) {
            $title_html = '<div class="ultraguard-security-suitegress-header">' .
                         '<h4 class="ultraguard-security-suitegress-title">' . esc_html( is_array( $scheme['title'] ) ? (string)( $scheme['title']['text'] ?? $scheme['title']['content'] ?? wp_json_encode( $scheme['title'] ) ) : (string)( $scheme['title'] ) ) . '</h4>' .
                         '</div>';
        }

        $label_html = '';
        if ( ! empty( $scheme['label'] ) ) {
            $label_html = '<div class="ultraguard-security-suitegress-label">' . esc_html( is_array( $scheme['label'] ) ? (string)( $scheme['label']['text'] ?? $scheme['label']['content'] ?? wp_json_encode( $scheme['label'] ) ) : (string)( $scheme['label'] ) ) . '</div>';
        }

        $content = '';
        // Build data-rt attributes for realtime targeting
        $rt_key      = $scheme['data_attributes']['rt']      ?? '';
        $rt_wrap_key = $scheme['data_attributes']['rt-progress-wrap'] ?? ( $rt_key ? 'true' : '' );
        $rt_bar_attr  = $rt_key      ? ' data-rt="'           . esc_attr( $rt_key )      . '"' : '';
        $rt_wrap_attr = $rt_wrap_key ? ' data-rt-progress-wrap="' . esc_attr( $rt_wrap_attr_val = $rt_key ?: 'true' ) . '"' : '';

        if ( 'bar' === $progress_type ) {
            $bar_html = '<div class="' . esc_attr( implode( ' ', $bar_classes ) ) .
                       '" style="width: ' . esc_attr( $percentage ) . '%;"'
                       . ' aria-valuenow="' . esc_attr( $percentage ) . '"'
                       . ' aria-valuemin="0" aria-valuemax="100"'
                       . $rt_bar_attr
                       . ' data-percentage="' . esc_attr( $percentage ) . '"></div>';

            $value_label_html = '';
            if ( ! empty( $scheme['show_value'] ) ) {
                $value_label_html = '<span data-rt-progress-label>' . esc_html( round( $percentage, 1 ) ) . '%</span>';
            }

            $content = $title_html .
                      '<div class="ultraguard-security-suitegress-container"' . $rt_wrap_attr . '>' .
                      $label_html .
                      '<div class="' . esc_attr( implode( ' ', $progress_classes ) ) . '">' . $bar_html . '</div>' .
                      $value_label_html .
                      '</div>';
        } elseif ( 'circle' === $progress_type ) {
            $circle_progress = $instance->render_circle_progress( $percentage, $scheme );

            $circle_value_html = '';
            if ( $scheme['show_value'] ) {
                $circle_value_html = '<div class="ultraguard-security-suitegress-circle-value">' . esc_html( $percentage ) . '%</div>';
            }

            $circle_label_html = '';
            if ( ! empty( $scheme['label'] ) ) {
                $circle_label_html = '<div class="ultraguard-security-suitegress-circle-label">' . esc_html( is_array( $scheme['label'] ) ? (string)( $scheme['label']['text'] ?? $scheme['label']['content'] ?? wp_json_encode( $scheme['label'] ) ) : (string)( $scheme['label'] ) ) . '</div>';
            }

            $circle_content = '<div class="ultraguard-security-suitegress-circle-wrapper">' .
                             $circle_progress .
                             '<div class="ultraguard-security-suitegress-circle-content">' .
                             $circle_value_html .
                             $circle_label_html .
                             '</div>' .
                             '</div>';

            $content = $title_html .
                      '<div class="ultraguard-security-suitegress-container ultraguard-security-suitegress-circle-container">' .
                      $circle_content .
                      '</div>';
        } else {
            // Fallback to bar
            $bar_html = '<div class="' . esc_attr( implode( ' ', $bar_classes ) ) .
                       '" style="width: ' . esc_attr( $percentage ) . '%;" data-percentage="' .
                       esc_attr( $percentage ) . '"></div>';

            $content = $title_html .
                      '<div class="ultraguard-security-suitegress-container">' .
                      $label_html .
                      '<div class="' . esc_attr( implode( ' ', $progress_classes ) ) . '">' . $bar_html . '</div>' .
                      '</div>';
        }

        // Note: data-rt is now on the bar element directly (above), not the wrapper
        $output = $instance->render_wrapper( $content, $scheme, $context );
        $output = $instance->after_render( $output, $scheme, $context );

        return $output;
    }

    /**
     * Render bar widget (alias for progress) - OPTIMIZED
     *
     * Alias method that renders a progress bar specifically. Sets the
     * progress_type to 'bar' and delegates to render_progress().
     *
     * @param  array<string, mixed> $scheme   Bar configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered HTML for bar widget
     * @access public
     * @static
     *
     * @see WidgetRenderer::render_progress()
     */
    public static function render_bar( $scheme, $context ) {
        $scheme['progress_type'] = 'bar';
        return self::render_progress( $scheme, $context );
    }

    /**
     * Render timeline widget - OPTIMIZED
     *
     * Renders a vertical or horizontal timeline of events with dates,
     * icons, and descriptions. Supports empty states and custom date formats.
     *
     * @param  array<string, mixed> $scheme   Timeline configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered HTML for timeline
     * @access public
     * @static
     *
     * @example
     * $html = WidgetRenderer::render_timeline([
     *     'title' => 'Security Events Timeline',
     *     'orientation' => 'vertical',
     *     'date_format' => 'F j, Y',
     *     'events' => [
     *         [
     *             'date' => '2024-01-01',
     *             'icon' => 'dashicons-warning',
     *             'title' => 'Security Update Installed',
     *             'description' => 'Critical security patch applied'
     *         ]
     *     ]
     * ], $context);
     */
    public static function render_timeline( $scheme, $context ) {
        if ( ! self::check_capability() ) {
            return '';
        }

        $instance = self::get_cached_instance();
        $scheme = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, self::get_default_scheme( 'timeline' ) );

        // Only apply filter if there are listeners
        if ( has_filter( 'ultraguard_timeline_scheme' ) ) {
            $scheme = apply_filters( 'ultraguard_timeline_scheme', $scheme, $context );
        }

        $events = $scheme['events'];
        $orientation = sanitize_key( $scheme['orientation'] );

        $title_html = '';
        if ( ! empty( $scheme['title'] ) ) {
            $title_html = '<h4 class="ultraguard-timeline-title">' . esc_html( is_array( $scheme['title'] ) ? (string)( $scheme['title']['text'] ?? $scheme['title']['content'] ?? wp_json_encode( $scheme['title'] ) ) : (string)( $scheme['title'] ) ) . '</h4>';
        }

        $events_html = '';
        $has_events = false;

        if ( is_array( $events ) && ! empty( $events ) ) {
            foreach ( $events as $event ) {
                $event = wp_parse_args( $event, [
                    'icon' => '',
                    'color' => '',
                    'date' => '',
                    'title' => '',
                    'description' => ''
                ] );

                $icon_html = '';
                if ( ! empty( $event['icon'] ) ) {
                    $color_class = ! empty( $event['color'] ) ? ' ultraguard-timeline-icon-' . sanitize_key( $event['color'] ) : '';
                    $icon_html = '<div class="ultraguard-timeline-icon' . esc_attr( $color_class ) .
                                '">' . $instance->render_ui_icon( $event['icon'] ) . '</div>';
                }

                $date_html = '';
                if ( ! empty( $event['date'] ) ) {
                    $date_format = sanitize_text_field( $scheme['date_format'] );
                    $formatted_date = date_i18n( $date_format, strtotime( $event['date'] ) );
                    $date_html = '<div class="ultraguard-timeline-date">' . esc_html( $formatted_date ) . '</div>';
                }

                $title_html_event = '';
                if ( ! empty( $event['title'] ) ) {
                    $title_html_event = '<h4 class="ultraguard-timeline-event-title">' . esc_html( is_array( $event['title'] ) ? (string)( $event['title']['text'] ?? $event['title']['content'] ?? wp_json_encode( $event['title'] ) ) : (string)( $event['title'] ) ) . '</h4>';
                }

                $description_html = '';
                if ( ! empty( $event['description'] ) ) {
                    $description_html = '<div class="ultraguard-timeline-description">' . esc_html( is_array( $event['description'] ) ? (string)( $event['description']['text'] ?? $event['description']['content'] ?? wp_json_encode( $event['description'] ) ) : (string)( $event['description'] ) ) . '</div>';
                }

                $events_html .= '<div class="ultraguard-timeline-event">' .
                               $icon_html .
                               '<div class="ultraguard-timeline-content">' .
                               $date_html . $title_html_event . $description_html .
                               '</div>' .
                               '</div>';
                $has_events = true;
            }
        }

        // Handle empty state
        if ( ! $has_events ) {
            $empty_state = wp_parse_args( $scheme['empty_state'], [
                'message' => __( 'No events available', 'ultraguard-security-suite' ),
                'icon' => 'dashicons-backup',
                'loading' => false
            ] );

            // Show gathering overlay when no timeline data available
        $custom_title = $empty_state['title'] ?? '';
        $custom_desc  = $empty_state['description'] ?? '';
        $events_html = self::gathering_empty_html(
            'ultraguard-timeline-gathering',
            '100px',
            empty( $custom_title ) ? '' : ( is_array( $custom_title ) ? ( $custom_title['text'] ?? '' ) : (string) $custom_title ),
            empty( $custom_desc  ) ? '' : ( is_array( $custom_desc  ) ? ( $custom_desc['text']  ?? '' ) : (string) $custom_desc  )
        );
        }

        $content = $title_html .
                  '<div class="ultraguard-timeline ultraguard-timeline-' . esc_attr( $orientation ) . '">' .
                  $events_html . '</div>';

        $output = $instance->render_wrapper( $content, $scheme, $context );
        $output = $instance->after_render( $output, $scheme, $context );

        return $output;
    }

    /**
     * Render card grid widget - OPTIMIZED
     *
     * Renders a responsive grid of cards with configurable columns and
     * individual card content. Supports empty states and loading indicators.
     *
     * @param  array<string, mixed> $scheme   Card grid configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered HTML for card grid
     * @access public
     * @static
     *
     * @example
     * $html = WidgetRenderer::render_card_grid([
     *     'title' => 'Security Status',
     *     'columns' => 3,
     *     'cards' => [
     *         [
     *             'icon' => 'dashicons-shield',
     *             'title' => 'Firewall',
     *             'content' => 'Active',
     *             'footer' => 'Last updated: Today'
     *         ]
     *     ]
     * ], $context);
     */
    public static function render_card_grid( $scheme, $context ) {
        if ( ! self::check_capability() ) {
            return '';
        }

        $instance = self::get_cached_instance();
        $scheme = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, self::get_default_scheme( 'card_grid' ) );

        // Only apply filter if there are listeners
        if ( has_filter( 'ultraguard_card_grid_scheme' ) ) {
            $scheme = apply_filters( 'ultraguard_card_grid_scheme', $scheme, $context );
        }

        $cards = $scheme['cards'];
        $columns = absint( $scheme['columns'] );

        $title_html = '';
        if ( ! empty( $scheme['title'] ) ) {
            $title_html = '<h4 class="ultraguard-card-grid-title">' . esc_html( is_array( $scheme['title'] ) ? (string)( $scheme['title']['text'] ?? $scheme['title']['content'] ?? wp_json_encode( $scheme['title'] ) ) : (string)( $scheme['title'] ) ) . '</h4>';
        }

        $cards_html = '';
        $has_cards = false;

        if ( is_array( $cards ) && ! empty( $cards ) ) {
            foreach ( $cards as $card ) {
                $cards_html .= $instance->render_single_card( $card, $context );
                $has_cards = true;
            }
        }

        // Handle empty state
        if ( ! $has_cards ) {
            $empty_state = wp_parse_args( $scheme['empty_state'], [
                'message' => __( 'No cards available', 'ultraguard-security-suite' ),
                'icon' => 'dashicons-grid-view',
                'loading' => false
            ] );
            // Show gathering overlay when no card data available
            $cards_html = self::gathering_empty_html( 'ultraguard-card-grid-gathering', '100px' );
        }

        $grid_style = 'grid-template-columns: repeat(' . $columns . ', minmax(0, 1fr));';

        $content = $title_html .
                  '<div class="ultraguard-card-grid" style="' . esc_attr( $grid_style ) . '">' . $cards_html . '</div>';

        $output = $instance->render_wrapper( $content, $scheme, $context );
        $output = $instance->after_render( $output, $scheme, $context );

        return $output;
    }

    /**
     * Render metric panel widget - OPTIMIZED
     *
     * Renders a panel of multiple metrics with icons, values, and labels.
     * Supports various value formats and empty states.
     *
     * @param  array<string, mixed> $scheme   Metric panel configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered HTML for metric panel
     * @access public
     * @static
     *
     * @example
     * $html = WidgetRenderer::render_metric_panel([
     *     'title' => 'Performance Metrics',
     *     'metrics' => [
     *         [
     *             'icon' => 'dashicons-dashboard',
     *             'label' => 'Response Time',
     *             'value' => '125ms',
     *             'format' => 'string'
     *         ]
     *     ]
     * ], $context);
     */
    public static function render_metric_panel( $scheme, $context ) {
        if ( ! self::check_capability() ) {
            return '';
        }

        $instance = self::get_cached_instance();
        $scheme = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, self::get_default_scheme( 'metric_panel' ) );

        // Only apply filter if there are listeners
        if ( has_filter( 'ultraguard_metric_panel_scheme' ) ) {
            $scheme = apply_filters( 'ultraguard_metric_panel_scheme', $scheme, $context );
        }

        $metrics = $scheme['metrics'];

        // Simple single-value mode: scheme has 'value' directly (no 'metrics' array)
        // Auto-promote to a single-item metrics array so the renderer works uniformly
        if ( empty( $metrics ) && ( isset( $scheme['value'] ) || ! empty( $scheme['icon'] ) ) ) {
            $metrics = [
                [
                    'value'  => $scheme['value']  ?? 0,
                    'icon'   => $scheme['icon']   ?? '',
                    'label'  => $scheme['label']  ?? '',
                    'format' => $scheme['format'] ?? 'string',
                    'suffix' => $scheme['suffix'] ?? '',
                ]
            ];
        }

        $title_html = '';
        if ( ! empty( $scheme['title'] ) ) {
            $title_html = '<h4 class="ultraguard-metric-panel-title">' . esc_html( is_array( $scheme['title'] ) ? (string)( $scheme['title']['text'] ?? $scheme['title']['content'] ?? wp_json_encode( $scheme['title'] ) ) : (string)( $scheme['title'] ) ) . '</h4>';
        }

        $metrics_html = '';
        $has_metrics = false;

        if ( is_array( $metrics ) && ! empty( $metrics ) ) {
            foreach ( $metrics as $metric ) {
                $metric = wp_parse_args( $metric, [
                    'icon' => '',
                    'label' => '',
                    'value' => 0,
                    'format' => 'string'
                ] );

                $value = $instance->get_value( $metric, $context );
                $formatted_value = $instance->format_value( $value, $metric );

                $icon_html = '';
                if ( ! empty( $metric['icon'] ) ) {
                    $icon_html = $instance->render_ui_icon( $metric['icon'] );
                }

                // If this is a single-metric panel with data-rt, tag the value div
                $metric_rt_attr = '';
                if ( ! empty( $scheme['data_attributes']['rt'] ) ) {
                    $metric_rt_attr = ' data-rt="' . esc_attr( $scheme['data_attributes']['rt'] ) . '"';
                }

                $metrics_html .= '<div class="ultraguard-metric">' .
                                $icon_html .
                                '<div class="ultraguard-metric-value"' . $metric_rt_attr . '>' . esc_html( $formatted_value ) . '</div>' .
                                '<div class="ultraguard-metric-label">' . esc_html( is_array( $metric['label'] ) ? (string)( $metric['label']['text'] ?? $metric['label']['content'] ?? wp_json_encode( $metric['label'] ) ) : (string)( $metric['label'] ) ) . '</div>' .
                                '</div>';
                $has_metrics = true;
            }
        }

        // Handle empty state
        if ( ! $has_metrics ) {
            $empty_state = wp_parse_args( $scheme['empty_state'], [
                'message' => __( 'No metrics available', 'ultraguard-security-suite' ),
                'icon' => 'dashicons-chart-bar',
                'loading' => false
            ] );

            // Show gathering overlay when no metric-panel data available
        $custom_title = $empty_state['title'] ?? '';
        $custom_desc  = $empty_state['description'] ?? '';
        $metrics_html = self::gathering_empty_html(
            'ultraguard-metric-panel-gathering',
            '80px',
            empty( $custom_title ) ? '' : ( is_array( $custom_title ) ? ( $custom_title['text'] ?? '' ) : (string) $custom_title ),
            empty( $custom_desc  ) ? '' : ( is_array( $custom_desc  ) ? ( $custom_desc['text']  ?? '' ) : (string) $custom_desc  )
        );
        }

        // data_attributes['rt'] → data-rt on wrapper for container-level targeting
        $rt_panel = $scheme['data_attributes']['rt'] ?? '';
        if ( $rt_panel ) {
            $scheme['attributes'] = array_merge(
                is_array( $scheme['attributes'] ?? null ) ? $scheme['attributes'] : [],
                [ 'data-rt' => $rt_panel ]
            );
        }


        $content = $title_html .
                  '<div class="ultraguard-metric-panel">' . $metrics_html . '</div>';

        $output = $instance->render_wrapper( $content, $scheme, $context );
        $output = $instance->after_render( $output, $scheme, $context );

        return $output;
    }

    /**
     * Render alert box widget - OPTIMIZED
     *
     * Renders a dismissible alert box with configurable type, icon, message,
     * and optional action buttons. Supports multiple alert types (info,
     * success, warning, error).
     *
     * @param  array<string, mixed> $scheme   Alert box configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered HTML for alert box
     * @access public
     * @static
     *
     * @example
     * $html = WidgetRenderer::render_alert_box([
     *     'alert_type' => 'warning',
     *     'dismissible' => true,
     *     'icon' => 'dashicons-warning',
     *     'message' => 'Security scan detected potential threats.',
     *     'actions' => [
     *         ['type' => 'button', 'label' => 'View Details', 'action' => 'show_details']
     *     ]
     * ], $context);
     */
    public static function render_alert_box( $scheme, $context ) {
        if ( ! self::check_capability() ) {
            return '';
        }

        $instance = self::get_cached_instance();
        $scheme = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, self::get_default_scheme( 'alert_box' ) );

        // Only apply filter if there are listeners
        if ( has_filter( 'ultraguard_alert_box_scheme' ) ) {
            $scheme = apply_filters( 'ultraguard_alert_box_scheme', $scheme, $context );
        }

        $type = sanitize_key( $scheme['alert_type'] );
        $dismissible = (bool) $scheme['dismissible'];

        $icon_html = '';
        if ( ! empty( $scheme['icon'] ) ) {
            $icon_html = $instance->render_ui_icon( $scheme['icon'] );
        }

        $dismiss_html = '';
        if ( $dismissible ) {
            $dismiss_html = '<button type="button" class="ultraguard-alert-dismiss">&times;</button>';
        }

        $actions_html = '';
        if ( ! empty( $scheme['actions'] ) && is_array( $scheme['actions'] ) ) {
            $actions_content = '';
            foreach ( $scheme['actions'] as $action ) {
                $actions_content .= $instance->engine->render( $action, $context );
            }
            $actions_html = '<div class="ultraguard-alert-actions">' . $actions_content . '</div>';
        }

        // Build title HTML
        $title_html = '';
        if ( ! empty( $scheme['title'] ) ) {
            $title_text = is_array( $scheme['title'] )
                ? (string) ( $scheme['title']['text'] ?? $scheme['title']['content'] ?? '' )
                : (string) $scheme['title'];
            if ( $title_text !== '' ) {
                $title_html = '<div class="ultraguard-alert-title">' . esc_html( $title_text ) . '</div>';
            }
        }

        // Build message HTML
        $message_text = is_array( $scheme['message'] )
            ? (string) ( $scheme['message']['text'] ?? $scheme['message']['content'] ?? wp_json_encode( $scheme['message'] ) )
            : (string) $scheme['message'];
        $message_html = $message_text !== '' ? '<div class="ultraguard-alert-message">' . esc_html( $message_text ) . '</div>' : '';

        // Actions go INSIDE .ultraguard-alert-content so they stack below the text
        $content = '<div class="ultraguard-alert ultraguard-alert-' . esc_attr( $type ) . '">' .
                  $icon_html .
                  '<div class="ultraguard-alert-content">' .
                      $title_html .
                      $message_html .
                      $actions_html .
                  '</div>' .
                  $dismiss_html .
                  '</div>';

        $output = $instance->render_wrapper( $content, $scheme, $context );
        $output = $instance->after_render( $output, $scheme, $context );

        return $output;
    }

    /**
     * Render info panel widget - OPTIMIZED
     *
     * Renders an informational panel with icon, title, description,
     * and optional action buttons. Useful for displaying help text,
     * instructions, or contextual information.
     *
     * @param  array<string, mixed> $scheme   Info panel configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered HTML for info panel
     * @access public
     * @static
     *
     * @example
     * $html = WidgetRenderer::render_info_panel([
     *     'icon' => 'dashicons-info',
     *     'title' => 'Security Tips',
     *     'description' => 'Regularly update your plugins and themes.',
     *     'actions' => [
     *         ['type' => 'button', 'label' => 'Learn More', 'url' => 'https://example.com']
     *     ]
     * ], $context);
     */
    public static function render_info_panel( $scheme, $context ) {
        if ( ! self::check_capability() ) {
            return '';
        }

        $instance = self::get_cached_instance();
        $scheme = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, self::get_default_scheme( 'info_panel' ) );

        // Only apply filter if there are listeners
        if ( has_filter( 'ultraguard_info_panel_scheme' ) ) {
            $scheme = apply_filters( 'ultraguard_info_panel_scheme', $scheme, $context );
        }

        $icon_html = '';
        if ( ! empty( $scheme['icon'] ) ) {
            $icon_html = '<div class="ultraguard-info-icon">' . $instance->render_ui_icon( $scheme['icon'] ) . '</div>';
        }

        $title_html = '';
        if ( ! empty( $scheme['title'] ) ) {
            $title_html = '<h3 class="ultraguard-info-title">' . esc_html( is_array( $scheme['title'] ) ? (string)( $scheme['title']['text'] ?? $scheme['title']['content'] ?? wp_json_encode( $scheme['title'] ) ) : (string)( $scheme['title'] ) ) . '</h3>';
        }

        $description_html = '';
        if ( ! empty( $scheme['description'] ) ) {
            $description_html = '<div class="ultraguard-info-description">' . esc_html( is_array( $scheme['description'] ) ? (string)( $scheme['description']['text'] ?? $scheme['description']['content'] ?? wp_json_encode( $scheme['description'] ) ) : (string)( $scheme['description'] ) ) . '</div>';
        }

        $actions_html = '';
        if ( ! empty( $scheme['actions'] ) && is_array( $scheme['actions'] ) ) {
            $actions_content = '';
            foreach ( $scheme['actions'] as $action ) {
                $actions_content .= $instance->engine->render( $action, $context );
            }
            $actions_html = '<div class="ultraguard-info-actions">' . $actions_content . '</div>';
        }

        $content = $icon_html .
                  '<div class="ultraguard-info-content">' .
                  $title_html . $description_html . $actions_html .
                  '</div>';

        $output = $instance->render_wrapper( $content, $scheme, $context );
        $output = $instance->after_render( $output, $scheme, $context );

        return $output;
    }

    /**
     * Render modal window widget - OPTIMIZED
     *
     * Renders a modal dialog window with header, body content, and optional
     * footer. Supports different sizes and includes close functionality.
     *
     * @param  array<string, mixed> $scheme   Modal configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered HTML for modal window
     * @access public
     * @static
     *
     * @example
     * $html = WidgetRenderer::render_modal([
     *     'id' => 'threat-details-modal',
     *     'title' => 'Threat Details',
     *     'size' => 'large',
     *     'content' => [
     *         ['type' => 'text', 'content' => 'Detailed threat information...']
     *     ],
     *     'footer' => [
     *         ['type' => 'button', 'label' => 'Close', 'action' => 'close_modal']
     *     ]
     * ], $context);
     */
    public static function render_modal( $scheme, $context ) {
        $instance = self::get_cached_instance();
        $scheme = $instance->before_render( $scheme, $context );
        $scheme = wp_parse_args( $scheme, self::get_default_scheme( 'modal' ) );
        // Get render engine and collect modal
        $engine = RenderEngine::get_instance();
        return $engine->collect_modal_for_footer( $scheme, $context );
    }

    /**
     * Render modal HTML - Used by RenderEngine for footer output
     *
     * @param  array $scheme  Modal configuration
     * @param  array $context Rendering context
     * @return string         Rendered modal HTML
     * @access public
     * @static
     */
    public static function render_modal_html( $scheme, $context ) {
        $instance = self::get_cached_instance();

        $scheme = wp_parse_args( $scheme, [
            'id'      => 'ultraguard-modal-' . uniqid(),
            'size'    => 'medium',
            'title'   => '',
            'content' => [],
            'footer'  => [],
            'buttons' => [],
            'class'   => '',
        ] );

        $modal_id   = esc_attr( $scheme['id'] );
        $size_class = 'ultraguard-modal-' . sanitize_key( $scheme['size'] );

        // Build content
        $body_content = $instance->render_children( $scheme['content'], $context );

        // Build footer
        $footer_html = '';
        if ( ! empty( $scheme['footer'] ) ) {
            $footer_content = $instance->render_children( $scheme['footer'], $context );
            $footer_html = '<div class="ultraguard-modal-footer">' . $footer_content . '</div>';
        }

        // Modal is hidden by default (display:none)
        $content = '<div class="ultraguard-modal-overlay" id="' . $modal_id . '" role="dialog" aria-modal="true" style="display:none;">' .
                  '<div class="ultraguard-modal ' . esc_attr( $size_class ) . '">' .
                  '<div class="ultraguard-modal-header">' .
                  '<h3 class="ultraguard-modal-title">' . esc_html( is_array( $scheme['title'] ) ? (string)( $scheme['title']['text'] ?? $scheme['title']['content'] ?? wp_json_encode( $scheme['title'] ) ) : (string)( $scheme['title'] ) ) . '</h3>' .
                  '<button class="ultraguard-modal-close" aria-label="' . esc_attr__( 'Close', 'ultraguard-security-suite' ) . '">&times;</button>' .
                  '</div>' .
                  '<div class="ultraguard-modal-body">' . $body_content . '</div>' .
                  $footer_html .
                  '</div>' .
                  '</div>';

        return $content;
    }

    /**
     * Render dropdown menu widget - OPTIMIZED
     *
     * Renders a dropdown menu with trigger button and menu items.
     * Supports dividers, headers, and danger items. Configurable position.
     *
     * @param  array<string, mixed> $scheme   Dropdown configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered HTML for dropdown menu
     * @access public
     * @static
     *
     * @example
     * $html = WidgetRenderer::render_dropdown([
     *     'trigger' => [
     *         'type' => 'button',
     *         'label' => 'Actions',
     *         'icon' => 'dashicons-arrow-down'
     *     ],
     *     'items' => [
     *         ['label' => 'Edit', 'icon' => 'dashicons-edit', 'action' => 'edit'],
     *         ['type' => 'divider'],
     *         ['label' => 'Delete', 'icon' => 'dashicons-trash', 'action' => 'delete', 'danger' => true]
     *     ],
     *     'position' => 'right'
     * ], $context);
     */
    public static function render_dropdown( $scheme, $context ) {
        $instance = self::get_cached_instance();
        $scheme = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, self::get_default_scheme( 'dropdown' ) );

        // Render trigger button
        $trigger_html = $instance->engine->render( $scheme['trigger'], $context );

        // Render items
        $items_html = '';
        $has_items = false;

        if ( ! empty( $scheme['items'] ) && is_array( $scheme['items'] ) ) {
            foreach ( $scheme['items'] as $item ) {
                if ( isset( $item['type'] ) && $item['type'] === 'divider' ) {
                    $items_html .= '<div class="ultraguard-dropdown-divider"></div>';
                    continue;
                }

                if ( isset( $item['type'] ) && $item['type'] === 'header' ) {
                    $items_html .= '<div class="ultraguard-dropdown-header">' . esc_html( is_array( $item['text'] ) ? (string)( $item['text']['text'] ?? $item['text']['content'] ?? wp_json_encode( $item['text'] ) ) : (string)( $item['text'] ) ) . '</div>';
                    continue;
                }

                // Regular item
                $item = wp_parse_args( $item, [ 'label' => '', 'icon' => '', 'action' => '', 'danger' => false ] );
                $icon_html = ! empty( $item['icon'] ) ? $instance->render_ui_icon( $item['icon'] ) : '';
                $class = 'ultraguard-dropdown-item' . ( $item['danger'] ? ' danger' : '' );

                $items_html .= '<a href="#" class="' . esc_attr( $class ) . '" data-action="' . esc_attr( $item['action'] ) . '">' .
                              $icon_html . ' ' . esc_html( is_array( $item['label'] ) ? (string)( $item['label']['text'] ?? $item['label']['content'] ?? wp_json_encode( $item['label'] ) ) : (string)( $item['label'] ) ) . '</a>';
                $has_items = true;
            }
        }

        // Handle empty state
        if ( ! $has_items ) {
            $items_html = self::gathering_empty_html( 'ultraguard-dropdown-gathering', '60px' );
        }

        $position_class = 'ultraguard-dropdown-' . sanitize_key( $scheme['position'] );

        return '<div class="ultraguard-dropdown-container">' .
               $trigger_html .
               '<div class="ultraguard-dropdown-menu ' . esc_attr( $position_class ) . '">' . $items_html . '</div>' .
               '</div>';
    }

    /**
     * Render terminal / log viewer widget - OPTIMIZED
     *
     * Renders a terminal-style log viewer with colored log levels,
     * timestamps, and messages. Supports empty states and loading indicators.
     *
     * @param  array<string, mixed> $scheme   Terminal configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered HTML for terminal
     * @access public
     * @static
     *
     * @example
     * $html = WidgetRenderer::render_terminal([
     *     'title' => 'Security Logs',
     *     'height' => '500px',
     *     'logs' => [
     *         [
     *             'time' => '14:30:22',
     *             'level' => 'INFO',
     *             'message' => 'Firewall rule applied',
     *             'ip' => '192.168.1.1'
     *         ]
     *     ]
     * ], $context);
     */
    public static function render_terminal( $scheme, $context ) {
        $instance = self::get_cached_instance();
        $scheme = wp_parse_args( $scheme, self::get_default_scheme( 'terminal' ) );

        $log_lines = '';
        $has_logs = false;

        if ( ! empty( $scheme['logs'] ) && is_array( $scheme['logs'] ) ) {
            foreach ( $scheme['logs'] as $log ) {
                $log = wp_parse_args( $log, [ 'time' => '', 'level' => 'info', 'message' => '', 'ip' => '' ] );
                $log_lines .= '<div class="ultraguard-log-line">' .
                            '<span class="ultraguard-log-time">' . esc_html( $log['time'] ) . '</span>' .
                            '<span class="ultraguard-log-level ' . esc_attr( strtolower( $log['level'] ) ) . '">' . esc_html( $log['level'] ) . '</span>' .
                            '<span class="ultraguard-log-message">' . esc_html( is_array( $log['message'] ) ? (string)( $log['message']['text'] ?? $log['message']['content'] ?? wp_json_encode( $log['message'] ) ) : (string)( $log['message'] ) ) . '</span>' .
                            '<span class="ultraguard-log-ip">' . esc_html( $log['ip'] ) . '</span>' .
                            '</div>';
                $has_logs = true;
            }
        }

        // Handle empty state
        if ( ! $has_logs ) {
            $empty_state = wp_parse_args( $scheme['empty_state'], [
                'message' => __( 'No logs available', 'ultraguard-security-suite' ),
                'loading' => false
            ] );
            // Show gathering overlay when no terminal log data available
            $log_lines = self::gathering_empty_html( 'ultraguard-terminal-gathering', '60px' );
        }

        return '<div class="ultraguard-terminal" style="height:' . esc_attr( $scheme['height'] ) . '">' .
               '<div class="ultraguard-terminal-header">' .
               '<div class="ultraguard-terminal-dot red"></div>' .
               '<div class="ultraguard-terminal-dot yellow"></div>' .
               '<div class="ultraguard-terminal-dot green"></div>' .
               '<div class="ultraguard-terminal-title">' . esc_html( is_array( $scheme['title'] ) ? (string)( $scheme['title']['text'] ?? $scheme['title']['content'] ?? wp_json_encode( $scheme['title'] ) ) : (string)( $scheme['title'] ) ) . '</div>' .
               '</div>' .
               '<div class="ultraguard-terminal-body">' . $log_lines . '</div>' .
               '</div>';
    }

    /**
     * Render skeleton loader widget - OPTIMIZED
     *
     * Renders a skeleton loading placeholder with configurable variant,
     * width, and height. Used to indicate loading states for widgets.
     *
     * @param  array<string, mixed> $scheme  Skeleton configuration scheme
     * @return string                        Rendered HTML for skeleton loader
     * @access public
     * @static
     *
     * @example
     * $html = WidgetRenderer::render_skeleton([
     *     'variant' => 'text',
     *     'width' => '200px',
     *     'height' => '20px'
     * ]);
     */
    public static function render_skeleton( $scheme ) {
        $type = $scheme['variant'] ?? 'text';
        $class = 'ultraguard-skeleton ultraguard-skeleton-' . $type;
        $style = isset( $scheme['width'] ) ? 'width:' . esc_attr( $scheme['width'] ) . ';' : '';
        $style .= isset( $scheme['height'] ) ? 'height:' . esc_attr( $scheme['height'] ) . ';' : '';

        return '<div class="' . esc_attr( $class ) . '" style="' . $style . '"></div>';
    }

    /**
     * Render card widget - OPTIMIZED
     *
     * Renders a generic card widget with header, body, and footer sections.
     * Supports icons, badges, actions, and various content types.
     *
     * @param  array<string, mixed> $scheme   Card configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered HTML for card widget
     * @access public
     * @static
     *
     * @example
     * $html = WidgetRenderer::render_card([
     *     'title' => 'Firewall Status',
     *     'icon' => 'dashicons-shield',
     *     'badge' => ['text' => 'Active', 'type' => 'success'],
     *     'content' => 'Firewall is actively blocking threats.',
     *     'actions' => [
     *         ['type' => 'button', 'label' => 'Configure', 'action' => 'configure_firewall']
     *     ],
     *     'footer' => 'Last updated: Today'
     * ], $context);
     */
    public static function render_card( $scheme, $context ) {
        if ( ! self::check_capability() ) {
            return '';
        }

        $instance = self::get_cached_instance();
        $scheme = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, self::get_default_scheme( 'card' ) );

        // Only apply filter if there are listeners
        if ( has_filter( 'ultraguard_card_scheme' ) ) {
            $scheme = apply_filters( 'ultraguard_card_scheme', $scheme, $context );
        }

        // Add proper card classes
        $scheme['class'] = ! empty( $scheme['class'] )
            ? $scheme['class'] . ' ultraguard-card'
            : 'ultraguard-card';

        // Card header
        $header_html = '';
        if ( ! empty( $scheme['title'] ) || ! empty( $scheme['actions'] ) ) {
            $title_html = '';
            if ( ! empty( $scheme['title'] ) ) {
                $icon_html = '';
                if ( ! empty( $scheme['icon'] ) ) {
                    $icon_html = $instance->render_ui_icon( $scheme['icon'] );
                }
                $badge_html = '';
                if ( ! empty( $scheme['badge'] ) && is_array( $scheme['badge'] ) && ! empty( $scheme['badge']['text'] ) ) {
                    $badge_type = $scheme['badge']['type'] ?? $scheme['badge']['badge_type'] ?? 'info'; // badge_type alias
                    $badge_html = '<span class="ultraguard-badge ultraguard-badge-' .
                                 esc_attr( sanitize_key( $badge_type ) ) . '">' .
                                 esc_html( $scheme['badge']['text'] ) . '</span>';
                }

                $title_html = '<h3 class="ultraguard-card-title">' . $icon_html .
                             esc_html( is_array( $scheme['title'] ) ? (string)( $scheme['title']['text'] ?? $scheme['title']['content'] ?? wp_json_encode( $scheme['title'] ) ) : (string)( $scheme['title'] ) ) . $badge_html . '</h3>';
            }

            $actions_html = '';
            if ( ! empty( $scheme['actions'] ) && is_array( $scheme['actions'] ) ) {
                $actions_content = '';
                foreach ( $scheme['actions'] as $action ) {
                    $actions_content .= $instance->engine->render( $action, $context );
                }
                $actions_html = '<div class="ultraguard-card-actions">' . $actions_content . '</div>';
            }

            $header_html = '<div class="ultraguard-card-header">' . $title_html . $actions_html . '</div>';
        }

        // Card body
        $body_html = '';
        if ( ! empty( $scheme['data'] ) ) {
            $body_content = $instance->render_children( $scheme['data'], $context );
            $body_html = '<div class="ultraguard-card-body">' . $body_content . '</div>';
        } elseif ( ! empty( $scheme['content'] ) ) {
            // content may be a string, a single component array, or an indexed array of components
            $content_val = $scheme['content'];
            if ( is_array( $content_val ) ) {
                if ( isset( $content_val['type'] ) ) {
                    $body_content = $instance->engine->render( $content_val, $context );
                } elseif ( isset( $content_val[0] ) ) {
                    $body_content = $instance->render_children( $content_val, $context );
                } else {
                    $body_content = wp_kses_post( $content_val['html'] ?? $content_val['message'] ?? wp_json_encode( $content_val ) );
                }
            } else {
                $body_content = wp_kses_post( (string) $content_val );
            }
            $body_html = '<div class="ultraguard-card-body">' . $body_content . '</div>';
        }

        // Card footer
        $footer_html = '';
        if ( ! empty( $scheme['footer'] ) ) {
            $footer_content = '';
            if ( is_array( $scheme['footer'] ) && isset( $scheme['footer']['type'] ) ) {
                $footer_content = $instance->engine->render( $scheme['footer'], $context );
            } else {
                $footer_content = esc_html( $scheme['footer'] );
            }
            $footer_html = '<div class="ultraguard-card-footer">' . $footer_content . '</div>';
        }

        $content = $header_html . $body_html . $footer_html;

        $output = $instance->render_wrapper( $content, $scheme, $context );
        $output = $instance->after_render( $output, $scheme, $context );

        return $output;
    }

    /**
     * Get value from scheme with source resolution - OPTIMIZED
     *
     * Retrieves the value for a widget from the scheme, with support for
     * direct values, data source loading, and default fallbacks.
     *
     * @param  array<string, mixed> $scheme   Widget configuration scheme
     * @param  array<string, mixed> $context  Rendering context data
     * @return mixed                          Resolved widget value
     * @access protected
     *
     * @throws \Exception  When data loader fails and debug mode is enabled
     */
    protected function get_value( $scheme, $context ) {
        $scheme = wp_parse_args( $scheme, [
            'value' => '',
            'default' => '',
            'source' => ''
        ] );

        // Direct value takes precedence
        if ( isset( $scheme['value'] ) && '' !== $scheme['value'] ) {
            return $scheme['value'];
        }

        // Try loading from source
        if ( ! empty( $scheme['source'] ) ) {
            try {
                $data_loader = DataLoader::get_instance();

                if ( method_exists( $data_loader, 'load' ) ) {
                    $loaded_value = $data_loader->load( $scheme['source'], $context );

                    if ( ! is_null( $loaded_value ) && false !== $loaded_value ) {
                        return $loaded_value;
                    }
                }
            } catch ( \Exception $e ) {
                // Log error but continue to default
                if ( function_exists( 'error_log' ) ) {
                    \UltraguardPro\core\Logger::error( 'DataLoader error: ' . $e->getMessage() );
                }
            }
        }

        return $scheme['default'];
    }

    /**
     * Format value according to specified format - OPTIMIZED
     *
     * Formats numeric or string values according to specified format types
     * including percentage, currency, filesize, time, number, and string.
     * Applies filters for custom formatting.
     *
     * @param  mixed                $value  Value to format
     * @param  array<string, mixed> $scheme Widget configuration scheme
     * @return string                       Formatted value string
     * @access protected
     */
    protected function format_value( $value, $scheme ) {
        $scheme = wp_parse_args( $scheme, [
            'format' => 'string',
            'currency' => 'USD',
            'default_value' => '0'
        ] );

        $format = sanitize_key( $scheme['format'] );

        // Handle null/empty values first
        if ( is_null( $value ) || '' === $value ) {
            return $scheme['default_value'];
        }

        // Handle array values
        if ( is_array( $value ) ) {
            if ( isset( $value['data'] ) && is_array( $value['data'] ) ) {
                $numeric_data = array_filter( $value['data'], 'is_numeric' );
                if ( ! empty( $numeric_data ) ) {
                    $value = array_sum( $numeric_data ) / count( $numeric_data );
                } else {
                    return $scheme['default_value'];
                }
            } else {
                return $scheme['default_value'];
            }
        }

        // Handle object values
        if ( is_object( $value ) ) {
            return $scheme['default_value'];
        }

        // Only apply filter if there are listeners
        if ( has_filter( 'ultraguard_format_value' ) ) {
            $value = apply_filters( 'ultraguard_format_value', $value, $scheme, $format );
        }

        switch ( $format ) {
            case 'percentage':
                if ( is_numeric( $value ) ) {
                    return sprintf( '%.1f%%', (float) $value );
                }
                return $scheme['default_value'];

            case 'currency':
                if ( is_numeric( $value ) ) {
                    $currency = sanitize_text_field( $scheme['currency'] );
                    $symbol = 'USD' === $currency ? '$' : $currency . ' ';
                    return $symbol . sprintf( '%.2f', (float) $value );
                }
                return $scheme['default_value'];

            case 'filesize':
                if ( is_numeric( $value ) && $value > 0 ) {
                    return size_format( $value );
                }
                return $scheme['default_value'];

            case 'time':
                if ( is_numeric( $value ) && $value > 0 ) {
                    return human_time_diff( $value ) . ' ' . esc_html__( 'ago', 'ultraguard-security-suite' );
                }
                return $scheme['default_value'];

            case 'number':
                if ( is_numeric( $value ) ) {
                    return number_format_i18n( (float) $value );
                }
                return $scheme['default_value'];

            case 'string':
            default:
                if ( is_string( $value ) ) {
                    return $value;
                }
                if ( is_numeric( $value ) ) {
                    return (string) $value;
                }
                return $scheme['default_value'];
        }
    }

    /**
     * Render circle progress visualization - OPTIMIZED
     *
     * Renders an SVG circle progress visualization with configurable
     * radius, stroke, and status-based styling.
     *
     * @param  float                $percentage  Progress percentage (0-100)
     * @param  array<string, mixed> $scheme      Progress scheme configuration
     * @return string                           Rendered SVG circle progress HTML
     * @access protected
     */
    protected function render_circle_progress( $percentage, $scheme ) {
        $scheme = wp_parse_args( $scheme, [
            'status' => 'primary'
        ] );

        $radius = 50;
        $circumference = 2 * M_PI * $radius;
        $stroke_dasharray = $circumference;
        $stroke_dashoffset = $circumference - ( $percentage / 100 ) * $circumference;

        $status = sanitize_key( $scheme['status'] );
        $fill_class = 'ultraguard-security-suitegress-circle-fill ultraguard-security-suitegress-' . $status;

        return '<svg class="ultraguard-security-suitegress-circle" viewBox="0 0 120 120">' .
               '<circle class="ultraguard-security-suitegress-circle-bg" cx="60" cy="60" r="' . absint( $radius ) . '"></circle>' .
               '<circle class="' . esc_attr( $fill_class ) . '" cx="60" cy="60" r="' . absint( $radius ) . '" ' .
               'stroke-dasharray="' . esc_attr( $stroke_dasharray ) . '" stroke-dashoffset="' . esc_attr( $stroke_dashoffset ) . '"></circle>' .
               '</svg>';
    }

    /**
     * Render single card within a grid - OPTIMIZED
     *
     * Renders an individual card component for use within card grids.
     * Supports icon, title, content, and footer sections.
     *
     * @param  array<string, mixed> $card     Card configuration
     * @param  array<string, mixed> $context  Rendering context data
     * @return string                         Rendered card HTML
     * @access protected
     */
    protected function render_single_card( $card, $context ) {
        $card = wp_parse_args( $card, [
            'icon' => '',
            'title' => '',
            'content' => '',
            'footer' => ''
        ] );

        $icon_html = '';
        if ( ! empty( $card['icon'] ) ) {
            $icon_html = '<div class="ultraguard-card-icon">' . $this->render_ui_icon( $card['icon'] ) . '</div>';
        }

        $title_html = '';
        if ( ! empty( $card['title'] ) ) {
            $title_html = '<h3 class="ultraguard-card-title">' . esc_html( is_array( $card['title'] ) ? (string)( $card['title']['text'] ?? $card['title']['content'] ?? wp_json_encode( $card['title'] ) ) : (string)( $card['title'] ) ) . '</h3>';
        }

        $content_html = '';
        if ( ! empty( $card['content'] ) ) {
            $content_html = '<div class="ultraguard-card-content">' . esc_html( is_array( $card['content'] ) ? (string)( $card['content']['text'] ?? $card['content']['content'] ?? wp_json_encode( $card['content'] ) ) : (string)( $card['content'] ) ) . '</div>';
        }

        $footer_html = '';
        if ( ! empty( $card['footer'] ) ) {
            $footer_content = '';
            if ( is_array( $card['footer'] ) && isset( $card['footer']['type'] ) ) {
                $footer_content = $this->engine->render( $card['footer'], $context );
            } else {
                $footer_content = esc_html( $card['footer'] );
            }
            $footer_html = '<div class="ultraguard-card-footer">' . $footer_content . '</div>';
        }

        return '<div class="ultraguard-card">' .
               $icon_html .
               '<div class="ultraguard-card-body">' .
               $title_html . $content_html .
               '</div>' .
               $footer_html .
               '</div>';
    }

    /**
     * Render pagination controls - OPTIMIZED
     *
     * Renders pagination controls for data tables and other paginated
     * widgets. Supports previous/next buttons and numbered page links.
     *
     * @param  array<string, mixed> $pagination_config  Pagination configuration
     * @return string                                   Rendered pagination HTML
     * @access protected
     */
    protected function render_pagination( $pagination_config ) {
        $pagination_config = wp_parse_args( $pagination_config, [
            'page_size' => 10,
            'total_items' => 0
        ] );

        $page_size = absint( $pagination_config['page_size'] );
        $total_items = absint( $pagination_config['total_items'] );
        $total_pages = $page_size > 0 ? ceil( $total_items / $page_size ) : 0;

        if ( $total_pages <= 1 ) {
            return '';
        }

        $pagination_html = '<div class="ultraguard-pagination">';

        // Previous button
        $pagination_html .= '<button class="ultraguard-pagination-prev" disabled>&laquo; ' .
                           esc_html__( 'Previous', 'ultraguard-security-suite' ) . '</button>';

        // Page numbers
        $max_pages_to_show = min( $total_pages, 5 );
        for ( $i = 1; $i <= $max_pages_to_show; $i++ ) {
            $active_class = $i === 1 ? ' ultraguard-pagination-active' : '';
            $pagination_html .= '<button class="ultraguard-pagination-page' . esc_attr( $active_class ) .
                               '">' . absint( $i ) . '</button>';
        }

        // Next button
        $pagination_html .= '<button class="ultraguard-pagination-next">' .
                           esc_html__( 'Next', 'ultraguard-security-suite' ) . ' &raquo;</button>';

        $pagination_html .= '</div>';

        return $pagination_html;
    }

    /**
     * Render child components recursively - OPTIMIZED
     *
     * Recursively renders child components within a parent widget.
     * Supports arrays of child components and single component objects.
     *
     * @param  mixed                $children  Child components data
     * @param  array<string, mixed> $context   Rendering context data
     * @return string                         Rendered child components HTML
     * @access protected
     */

    /**
     * Generate a "Gathering data…" placeholder for any empty widget.
     *
     * Used as the default empty state for tables, lists, timelines, heatmaps,
     * and other widgets when no data is available yet, indicating collection
     * is in progress rather than leaving the area blank.
     *
     * @param  string $wrapper_class  CSS class on the wrapping div.
     * @param  string $min_height     Minimum height for the placeholder (CSS value).
     * @param  string $message        Optional override for the heading text.
     * @param  string $sub_message    Optional override for the sub-line text.
     * @return string                 HTML for the gathering placeholder.
     */
    protected static function gathering_empty_html(
        string $wrapper_class = '',
        string $min_height    = '120px',
        string $message       = '',
        string $sub_message   = ''
    ): string {
        return self::render_gathering_empty( $wrapper_class, $min_height, $message, $sub_message );
    }

    protected function render_children( $children, $context ) {
        if ( is_array( $children ) ) {
            $output = '';
            foreach ( $children as $child ) {
                if ( is_array( $child ) && isset( $child['type'] ) ) {
                    $output .= $this->engine->render( $child, $context );
                }
            }
            return $output;
        }
        return is_string( $children ) ? $children : '';
    }

    /**
     * Render circular gauge for security score - OPTIMIZED
     *
     * Renders a circular gauge visualization for security scores with
     * configurable radius, stroke properties, and level-based styling.
     *
     * @param  float                             $score  Security score (0-100)
     * @param  array{level: string, label: string, color: string} $level  Score level information
     * @param  string                            $size   Gauge size (small, medium, large)
     * @return string                                    Rendered gauge SVG HTML
     * @access protected
     */
    protected function render_circular_gauge( $score, $level, $size = 'medium' ) {
        $radius = 50;
        $circumference = 2 * M_PI * $radius;
        $stroke_dasharray = $circumference;
        $stroke_dashoffset = $circumference - ( $score / 100 ) * $circumference;

        return '<svg class="ultraguard-security-gauge ultraguard-gauge-' . esc_attr( $size ) . '" viewBox="0 0 120 120">' .
               '<circle class="ultraguard-gauge-bg" cx="60" cy="60" r="' . absint( $radius ) . '"></circle>' .
               '<circle class="ultraguard-gauge-fill ultraguard-gauge-' . esc_attr( $level['level'] ) .
               '" cx="60" cy="60" r="' . absint( $radius ) . '" ' .
               'stroke-dasharray="' . esc_attr( $stroke_dasharray ) . '" stroke-dashoffset="' . esc_attr( $stroke_dashoffset ) . '"></circle>' .
               '</svg>';
    }

    /**
     * Render semi-circular gauge for security score - OPTIMIZED
     *
     * Renders a semi-circular gauge visualization for security scores
     * with rotation-based fill and level-based styling.
     *
     * @param  float                             $score  Security score (0-100)
     * @param  array{level: string, label: string, color: string} $level  Score level information
     * @param  string                            $size   Gauge size (small, medium, large)
     * @return string                                    Rendered gauge HTML
     * @access protected
     */
    protected function render_semi_circular_gauge( $score, $level, $size = 'medium' ) {
        $rotation = ( $score / 100 ) * 180;

        return '<div class="ultraguard-semi-gauge ultraguard-gauge-' . esc_attr( $size ) .
               ' ultraguard-gauge-' . esc_attr( $level['level'] ) . '">' .
               '<div class="ultraguard-semi-gauge-fill" style="transform: rotate(' . esc_attr( $rotation ) . 'deg);"></div>' .
               '</div>';
    }

    /**
     * Render heatmap calendar visualization - OPTIMIZED
     *
     * Renders a calendar-style heatmap visualization of threat data
     * over time with intensity-based coloring and tooltips.
     *
     * @param  array<string, int> $threat_data   Threat counts by date
     * @param  int                $max_threats   Maximum threats for scaling
     * @param  string             $period        Time period (30days, 90days)
     * @return string                           Rendered heatmap HTML
     * @access protected
     */
    protected function render_heatmap_calendar( $threat_data, $max_threats, $period = '30days' ) {
        $days = ( '90days' === $period ) ? 90 : 30;

        $today = current_time( 'timestamp' );
        $months = array();

        $calendar_days_html = '';
        for ( $i = $days - 1; $i >= 0; $i-- ) {
            $date = wp_date( 'Y-m-d', strtotime( "-{$i} days", $today ) );
            $count = $threat_data[ $date ] ?? 0;
            $count = absint( $count );
            $month = wp_date( 'M', strtotime( $date ) );
            $year_month = wp_date( 'Y-m', strtotime( $date ) );

            if ( ! isset( $months[ $year_month ] ) ) {
                $months[ $year_month ] = $month;
            }

            // Calculate intensity level (0-4) with proper scaling
            $intensity = 0;
            if ( $count > 0 ) {
                if ( $max_threats > 0 ) {
                    // Use logarithmic scale for better distribution
                    $ratio = $count / $max_threats;
                    if ( $ratio >= 0.75 ) {
                        $intensity = 4; // Critical
                    } elseif ( $ratio >= 0.5 ) {
                        $intensity = 3; // High
                    } elseif ( $ratio >= 0.25 ) {
                        $intensity = 2; // Medium
                    } else {
                        $intensity = 1; // Low
                    }
                } else {
                    $intensity = 1;
                }
            }

            $tooltip = sprintf(
                '%s: %d %s',
                date_i18n( 'M j, Y', strtotime( $date ) ),
                $count,
                _n( 'threat', 'threats', $count, 'ultraguard-security-suite' )
            );

            $day_name = wp_date( 'D', strtotime( $date ) );
            $day_number = wp_date( 'j', strtotime( $date ) );

            $calendar_days_html .= '<div class="ultraguard-heatmap-day ultraguard-heatmap-intensity-' . absint( $intensity ) .
                                  '" title="' . esc_attr( $tooltip ) . '" data-date="' . esc_attr( $date ) .
                                  '" data-count="' . absint( $count ) . '" data-day="' . esc_attr( $day_name ) . '">' .
                                  '<span class="ultraguard-heatmap-date">' . absint( $day_number ) . '</span>' .
                                  '</div>';
        }

        $smart_month_header = $this->generate_smart_month_header( $months );

        // Generate day of week labels (Mon, Tue, Wed, etc.)
        $day_names = array( 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' );
        $day_names_html = '';
        foreach ( $day_names as $day ) {
            $day_names_html .= '<div class="ultraguard-heatmap-dayname">' . esc_html( $day ) . '</div>';
        }

        $heatmap_html = '<div class="ultraguard-heatmap-calendar-wrapper">' .
                       '<div class="ultraguard-heatmap-smart-header">' . esc_html( $smart_month_header ) . '</div>' .
                       '<div class="ultraguard-heatmap-daynames">' . $day_names_html . '</div>' .
                       '<div class="ultraguard-heatmap-grid" style="grid-template-columns: repeat(auto-fill, minmax(30px, 1fr));">' .
                       $calendar_days_html . '</div>' .
                       '</div>';

        return $heatmap_html;
    }

    /**
     * Generate smart month header based on date range - OPTIMIZED
     *
     * Generates an intelligent month header string based on the date
     * range covered by the heatmap. Handles single months, multiple
     * months, and ranges efficiently.
     *
     * @param  array<string, string> $months  Array of months in the date range
     * @return string                        Smart month header string
     * @access protected
     */
    protected function generate_smart_month_header( $months ) {
        $month_count = count( $months );

        if ( $month_count === 0 ) {
            return '';
        }

        $month_names = array_values( $months );

        if ( $month_count === 1 ) {
            // Single month: "Nov"
            return $month_names[0];
        }

        if ( $month_count === 2 ) {
            // Two months: "Oct-Nov"
            return $month_names[0] . '-' . $month_names[1];
        }

        // Multiple months
        $first_month = $month_names[0];
        $last_month = end( $month_names );

        if ( $month_count <= 4 ) {
            // For 3-4 months, show all: "Oct-Nov-Dec"
            return implode( '-', $month_names );
        } else {
            // For more than 4 months, show range: "Oct-Jan"
            return $first_month . '-' . $last_month;
        }
    }

    /**
 * Get current URL with query parameters
 *
 * @return string Current URL
 * @access private
 */
private function get_current_url() {
    $protocol = isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
    $host = sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ?? '' ) );
    $uri  = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ?? '' ) );

    return $protocol . '://' . $host . $uri;
}

/**
 * Remove query argument from URL
 *
 * @param  string $url    URL to modify
 * @param  string $arg    Argument to remove
 * @return string        Modified URL
 * @access private
 */
private function remove_query_arg( $arg, $url = null ) {
    if ( is_null( $url ) ) {
        $url = $this->get_current_url();
    }

    // Parse URL
    $url_parts = wp_parse_url( $url );

    if ( ! isset( $url_parts['query'] ) ) {
        return $url;
    }

    // Parse query string
    parse_str( $url_parts['query'], $query_params );

    // Remove the argument
    unset( $query_params[ $arg ] );

    // Rebuild URL
    $new_query = http_build_query( $query_params );
    $url_parts['query'] = $new_query ?: null;

    return $this->build_url( $url_parts );
}

/**
 * Add query argument to URL
 *
 * @param  array  $args  Arguments to add
 * @param  string $url   URL to modify
 * @return string       Modified URL
 * @access private
 */
private function add_query_arg( $args, $url = null ) {
    if ( is_null( $url ) ) {
        $url = $this->get_current_url();
    }

    // Parse URL
    $url_parts = wp_parse_url( $url );

    // Get existing query params
    $query_params = [];
    if ( isset( $url_parts['query'] ) ) {
        parse_str( $url_parts['query'], $query_params );
    }

    // Merge new args
    $query_params = array_merge( $query_params, $args );

    // Rebuild URL
    $new_query = http_build_query( $query_params );
    $url_parts['query'] = $new_query;

    return $this->build_url( $url_parts );
}

/**
 * Build URL from parts
 *
 * @param  array $parts URL parts
 * @return string      Built URL
 * @access private
 */
private function build_url( $parts ) {
    $url = '';

    if ( isset( $parts['scheme'] ) ) {
        $url .= $parts['scheme'] . '://';
    }

    if ( isset( $parts['host'] ) ) {
        $url .= $parts['host'];
    }

    if ( isset( $parts['port'] ) ) {
        $url .= ':' . $parts['port'];
    }

    if ( isset( $parts['path'] ) ) {
        $url .= $parts['path'];
    }

    if ( isset( $parts['query'] ) ) {
        $url .= '?' . $parts['query'];
    }

    if ( isset( $parts['fragment'] ) ) {
        $url .= '#' . $parts['fragment'];
    }

    return $url;
}

    /**
     * Render ssl-status widget
     * Displays SSL certificate status, expiry, and issuer information.
     */
    public static function render_ssl_status( $scheme, $context ) {
        if ( ! self::check_capability() ) {
            return '';
        }

        $instance = self::get_cached_instance();
        $scheme   = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, [
            'title'        => __( 'SSL Certificate', 'ultraguard-security-suite' ),
            'status'       => 'valid',
            'status_label' => __( 'Valid', 'ultraguard-security-suite' ),
            'domain'       => '',
            'issuer'       => '',
            'expires'      => '',
            'days_left'    => null,
            'icon'         => 'dashicons-lock',
            'id'           => '',
            'class'        => '',
        ] );

        $status  = sanitize_key( $scheme['status'] );

        $days_html = '';
        if ( $scheme['days_left'] !== null ) {
            $days = (int) $scheme['days_left'];
            $days_class = $days > 30 ? 'success' : ( $days > 7 ? 'warning' : 'danger' );
            $days_html = sprintf(
                '<div class="ultraguard-ssl-days"><span class="ultraguard-badge ultraguard-badge-%s">%s</span></div>',
                esc_attr( $days_class ),
                /* translators: %1$d: number of days */
                sprintf( esc_html__( '%1$d days remaining', 'ultraguard-security-suite' ), $days )
            );
        }

        $id_attr = $scheme['id'] ? ' id="' . esc_attr( $scheme['id'] ) . '"' : '';

        return sprintf(
            '<div%s class="ultraguard-ssl-status ultraguard-card %s">'
            . '<div class="ultraguard-card-header">'
            . '<h3 class="ultraguard-card-title">%s %s</h3>'
            . '<span class="ultraguard-badge ug-badge-%s">%s</span>'
            . '</div>'
            . '<div class="ultraguard-card-body">'
            . '<dl class="ultraguard-ssl-details">'
            . ( $scheme['domain']  ? '<dt>' . esc_html__( 'Domain', 'ultraguard-security-suite' ) . '</dt><dd>' . esc_html( $scheme['domain'] )  . '</dd>' : '' )
            . ( $scheme['issuer']  ? '<dt>' . esc_html__( 'Issuer', 'ultraguard-security-suite' ) . '</dt><dd>' . esc_html( $scheme['issuer'] )  . '</dd>' : '' )
            . ( $scheme['expires'] ? '<dt>' . esc_html__( 'Expires', 'ultraguard-security-suite' ) . '</dt><dd>' . esc_html( $scheme['expires'] ) . '</dd>' : '' )
            . '</dl>'
            . $days_html
            . '</div>'
            . '</div>',
            $id_attr,
            esc_attr( $scheme['class'] ),
            $instance->render_ui_icon( $scheme['icon'], 'ultraguard-ssl-status-icon ultraguard-ssl-status-icon-' . $status ),
            esc_html( $scheme['title'] ),
            esc_attr( $status ),
            esc_html( $scheme['status_label'] )
        );
    }

    /**
     * Render file-integrity widget
     * Shows file integrity check summary with change count and status.
     */
    public static function render_file_integrity( $scheme, $context ) {
        if ( ! self::check_capability() ) {
            return '';
        }

        $instance = self::get_cached_instance();
        $scheme   = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, [
            'title'           => __( 'File Integrity', 'ultraguard-security-suite' ),
            'status'          => 'clean',
            'status_label'    => __( 'Clean', 'ultraguard-security-suite' ),
            'total_files'     => 0,
            'modified_files'  => 0,
            'added_files'     => 0,
            'deleted_files'   => 0,
            'last_scan'       => '',
            'id'              => '',
            'class'           => '',
        ] );

        $has_changes = ( (int) $scheme['modified_files'] + (int) $scheme['added_files'] + (int) $scheme['deleted_files'] ) > 0;
        $status_class = $has_changes ? 'warning' : 'success';

        $id_attr = $scheme['id'] ? ' id="' . esc_attr( $scheme['id'] ) . '"' : '';

        return sprintf(
            '<div%s class="ultraguard-file-integrity ultraguard-card %s">'
            . '<div class="ultraguard-card-header">'
            . '<h3 class="ultraguard-card-title">%s %s</h3>'
            . '<span class="ultraguard-badge ug-badge-%s">%s</span>'
            . '</div>'
            . '<div class="ultraguard-card-body">'
            . '<div class="ultraguard-integrity-stats">'
            . '<div class="ultraguard-integrity-stat"><strong class="ultraguard-integrity-value">%s</strong><small>%s</small></div>'
            . '<div class="ultraguard-integrity-stat"><strong class="ultraguard-integrity-value ultraguard-integrity-value-%s">%s</strong><small>%s</small></div>'
            . '<div class="ultraguard-integrity-stat"><strong class="ultraguard-integrity-value ultraguard-integrity-value-%s">%s</strong><small>%s</small></div>'
            . '</div>'
            /* translators: %s: text */
            . ( $scheme['last_scan'] ? '<p class="ultraguard-last-scan">' . sprintf( esc_html__( 'Last scan: %s', 'ultraguard-security-suite' ), esc_html( $scheme['last_scan'] ) ) . '</p>' : '' )
            . '</div>'
            . '</div>',
            $id_attr,
            esc_attr( $scheme['class'] ),
            $instance->render_ui_icon( 'dashicons-media-code' ),
            esc_html( $scheme['title'] ),
            $status_class,
            esc_html( $scheme['status_label'] ),
            esc_html( number_format_i18n( (int) $scheme['total_files'] ) ),
            esc_html__( 'Total Files', 'ultraguard-security-suite' ),
            esc_attr( $has_changes ? 'warning' : 'success' ),
            esc_html( number_format_i18n( (int) $scheme['modified_files'] ) ),
            esc_html__( 'Modified', 'ultraguard-security-suite' ),
            esc_attr( ( (int) $scheme['deleted_files'] > 0 ) ? 'danger' : 'success' ),
            esc_html( number_format_i18n( (int) $scheme['deleted_files'] + (int) $scheme['added_files'] ) ),
            esc_html__( 'Added/Deleted', 'ultraguard-security-suite' )
        );
    }

    /**
     * Render backup-status widget
     * Shows latest backup state, age, and size.
     */
    public static function render_backup_status( $scheme, $context ) {
        if ( ! self::check_capability() ) {
            return '';
        }

        $instance = self::get_cached_instance();
        $scheme   = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, [
            'title'        => __( 'Backup Status', 'ultraguard-security-suite' ),
            'status'       => 'unknown',
            'status_label' => __( 'Unknown', 'ultraguard-security-suite' ),
            'last_backup'  => '',
            'backup_size'  => '',
            'backup_type'  => '',
            'next_backup'  => '',
            'id'           => '',
            'class'        => '',
        ] );

        $status_map = [ 'ok' => 'success', 'warning' => 'warning', 'error' => 'danger', 'unknown' => 'secondary' ];
        $badge_type = $status_map[ $scheme['status'] ] ?? 'secondary';
        $id_attr    = $scheme['id'] ? ' id="' . esc_attr( $scheme['id'] ) . '"' : '';

        $rows = '';
        $fields = [
            'last_backup' => __( 'Last Backup', 'ultraguard-security-suite' ),
            'backup_size' => __( 'Size', 'ultraguard-security-suite' ),
            'backup_type' => __( 'Type', 'ultraguard-security-suite' ),
            'next_backup' => __( 'Next Backup', 'ultraguard-security-suite' ),
        ];
        foreach ( $fields as $key => $label ) {
            if ( ! empty( $scheme[ $key ] ) ) {
                $rows .= sprintf( '<dt>%s</dt><dd>%s</dd>', esc_html( $label ), esc_html( $scheme[ $key ] ) );
            }
        }

        return sprintf(
            '<div%s class="ultraguard-backup-status ultraguard-card %s">'
            . '<div class="ultraguard-card-header">'
            . '<h3 class="ultraguard-card-title">%s %s</h3>'
            . '<span class="ultraguard-badge ultraguard-badge-%s">%s</span>'
            . '</div>'
            . '<div class="ultraguard-card-body"><dl class="ultraguard-backup-details">%s</dl></div>'
            . '</div>',
            $id_attr, esc_attr( $scheme['class'] ),
            $instance->render_ui_icon( 'dashicons-backup' ),
            esc_html( $scheme['title'] ),
            $badge_type, esc_html( $scheme['status_label'] ),
            $rows
        );
    }

    /**
     * Render performance-impact widget
     * Displays plugin performance metrics — query count, memory, load time.
     */
    public static function render_performance_impact( $scheme, $context ) {
        if ( ! self::check_capability() ) {
            return '';
        }

        $instance = self::get_cached_instance();
        $scheme   = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, [
            'title'        => __( 'Performance Impact', 'ultraguard-security-suite' ),
            'rating'       => 'good',
            'rating_label' => __( 'Low Impact', 'ultraguard-security-suite' ),
            'memory_usage' => '',
            'query_count'  => '',
            'load_time'    => '',
            'metrics'      => [],
            'id'           => '',
            'class'        => '',
        ] );

        $id_attr = $scheme['id'] ? ' id="' . esc_attr( $scheme['id'] ) . '"' : '';

        // Build metrics grid
        $builtin_metrics = [];
        if ( $scheme['memory_usage'] ) $builtin_metrics[] = [ 'label' => __( 'Memory', 'ultraguard-security-suite' ),     'value' => $scheme['memory_usage'] ];
        if ( $scheme['query_count']  ) $builtin_metrics[] = [ 'label' => __( 'DB Queries', 'ultraguard-security-suite' ), 'value' => $scheme['query_count'] ];
        if ( $scheme['load_time']    ) $builtin_metrics[] = [ 'label' => __( 'Load Time', 'ultraguard-security-suite' ),  'value' => $scheme['load_time'] ];

        $all_metrics = array_merge( $builtin_metrics, is_array( $scheme['metrics'] ) ? $scheme['metrics'] : [] );
        $metrics_html = '';
        foreach ( $all_metrics as $m ) {
            $m = wp_parse_args( $m, [ 'label' => '', 'value' => '' ] );
            $metrics_html .= sprintf(
                '<div class="ultraguard-performance-metric"><div class="ultraguard-performance-value ultraguard-performance-value-%s">%s</div><div class="ultraguard-performance-label">%s</div></div>',
                esc_attr( sanitize_key( $scheme['rating'] ) ), esc_html( $m['value'] ), esc_html( $m['label'] )
            );
        }

        return sprintf(
            '<div%s class="ultraguard-performance-impact ultraguard-card %s">'
            . '<div class="ultraguard-card-header">'
            . '<h3 class="ultraguard-card-title">%s %s</h3>'
            . '<span class="ultraguard-badge ultraguard-performance-badge ultraguard-performance-badge-%s">%s</span>'
            . '</div>'
            . '<div class="ultraguard-card-body">'
            . '<div class="ultraguard-performance-metrics">%s</div>'
            . '</div>'
            . '</div>',
            $id_attr, esc_attr( $scheme['class'] ),
            $instance->render_ui_icon( 'dashicons-performance' ),
            esc_html( $scheme['title'] ),
            esc_attr( sanitize_key( $scheme['rating'] ) ), esc_html( $scheme['rating_label'] ),
            $metrics_html
        );
    }


    /**
     * Render security-dashboard component
     * Lays out multiple chart components in a responsive grid.
     */
    public static function render_security_dashboard( $scheme, $context ) {
        if ( ! self::check_capability() ) { return ''; }

        $instance = self::get_cached_instance();
        $scheme   = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, [
            'layout'  => 'grid',
            'columns' => 2,
            'gap'     => '20px',
            'charts'  => [],
            'id'      => '',
            'class'   => '',
        ] );

        $charts  = is_array( $scheme['charts'] ) ? $scheme['charts'] : [];
        $cols    = max( 1, min( 4, absint( $scheme['columns'] ) ) );
        $gap     = esc_attr( $scheme['gap'] );
        $id_attr = $scheme['id'] ? ' id="' . esc_attr( $scheme['id'] ) . '"' : '';
        $cls     = trim( 'ultraguard-security-dashboard ' . esc_attr( $scheme['class'] ) );

        $items_html = '';
        foreach ( $charts as $chart_scheme ) {
            if ( is_array( $chart_scheme ) ) {
                $items_html .= '<div class="ultraguard-security-dashboard-item">'
                    . $instance->engine->render( $chart_scheme, $context )
                    . '</div>';
            }
        }

        $output = sprintf(
            '<div%s class="%s" style="display:grid;grid-template-columns:repeat(%d,minmax(0,1fr));gap:%s;">%s</div>',
            $id_attr, $cls, $cols, $gap, $items_html
        );

        return $instance->after_render( $output, $scheme, $context );
    }

    /**
     * Render vulnerability-scanner component
     * Displays a list of vulnerability/threat items with severity badges.
     */
    public static function render_vulnerability_scanner( $scheme, $context ) {
        if ( ! self::check_capability() ) { return ''; }

        $instance = self::get_cached_instance();
        $scheme   = $instance->before_render( $scheme, $context );

        $scheme = wp_parse_args( $scheme, [
            'title'            => '',
            'scan_in_progress' => false,
            'vulnerabilities'  => [],
            'actions'          => [],
            'empty_message'    => '',
            'id'               => '',
            'class'            => '',
        ] );

        $vulns   = is_array( $scheme['vulnerabilities'] ) ? $scheme['vulnerabilities'] : [];
        $id_attr = $scheme['id'] ? ' id="' . esc_attr( $scheme['id'] ) . '"' : '';
        $cls     = trim( 'ultraguard-vulnerability-scanner ' . esc_attr( $scheme['class'] ) );

        // Header
        $header = '';
        if ( ! empty( $scheme['title'] ) ) {
            $header = '<div class="ultraguard-card-header">'
                . '<h3 class="ultraguard-card-title">'
                . $instance->render_ui_icon( 'dashicons-shield-alt' ) . ' '
                . esc_html( $scheme['title'] )
                . '</h3>'
                . '</div>';
        }

        // Scan in progress notice
        if ( $scheme['scan_in_progress'] ) {
            $body = '<div class="ultraguard-card-body"><div class="ultraguard-scanner-progress">'
                . $instance->render_ui_icon( 'dashicons-update', '', [ 'style' => 'animation:ultraguard-spin 1.5s linear infinite;display:inline-flex;' ] ) . ' '
                . esc_html__( 'Scan in progress…', 'ultraguard-security-suite' )
                . '</div></div>';
            $output = sprintf( '<div%s class="ultraguard-card %s">%s%s</div>', $id_attr, $cls, $header, $body );
            return $instance->after_render( $output, $scheme, $context );
        }

        // Vulnerability list
        $severity_classes = [
            'critical' => 'ultraguard-vulnerability-critical',
            'high'     => 'ultraguard-vulnerability-high',
            'medium'   => 'ultraguard-vulnerability-medium',
            'low'      => 'ultraguard-vulnerability-low',
        ];

        $items_html = '';
        foreach ( $vulns as $v ) {
            if ( ! is_array( $v ) ) { continue; }
            $v        = wp_parse_args( $v, [ 'severity' => 'medium', 'title' => '', 'component' => '', 'date' => '', 'fix_available' => false ] );
            $sev      = sanitize_key( $v['severity'] );
            $sev_cls  = $severity_classes[ $sev ] ?? $severity_classes['medium'];
            $fix_html = $v['fix_available']
                ? '<span class="ultraguard-badge ultraguard-badge-success" style="margin-left:8px;">' . esc_html__( 'Fix Available', 'ultraguard-security-suite' ) . '</span>'
                : '';
            $items_html .= sprintf(
                '<div class="ultraguard-vulnerability-item %s" style="padding:12px;border-left:3px solid currentColor;margin-bottom:8px;background:#fff;border-radius:0 4px 4px 0;">'
                . '<div style="font-weight:600;font-size:13px;">%s%s</div>'
                . '<div style="font-size:12px;color:#64748b;margin-top:4px;">%s</div>'
                . '</div>',
                esc_attr( $sev_cls ),
                esc_html( $v['title'] ?: $v['component'] ),
                $fix_html,
                esc_html( $v['component'] )
            );
        }

        if ( empty( $items_html ) ) {
            $empty_msg = $scheme['empty_message'] ?: __( 'No threats detected', 'ultraguard-security-suite' );
            $items_html = '<div class="ultraguard-empty-state">' . $instance->render_ui_icon( 'dashicons-yes-alt', '', [ 'style' => 'color:#10b981;font-size:28px;width:28px;height:28px;' ] ) . '<p>' . esc_html( $empty_msg ) . '</p></div>';
        }

        // Actions
        $actions_html = '';
        if ( ! empty( $scheme['actions'] ) ) {
            foreach ( $scheme['actions'] as $action ) {
                if ( is_array( $action ) ) {
                    $actions_html .= $instance->engine->render( $action, $context );
                }
            }
            $actions_html = '<div class="ultraguard-card-footer" style="padding-top:12px;">' . $actions_html . '</div>';
        }

        $body   = '<div class="ultraguard-card-body">' . $items_html . '</div>';
        $output = sprintf( '<div%s class="ultraguard-card %s">%s%s%s</div>', $id_attr, $cls, $header, $body, $actions_html );

        return $instance->after_render( $output, $scheme, $context );
    }

}
