<?php
/**
 * Base Widget Class - Optimized Version
 *
 * This file contains the BaseWidget abstract class which provides common
 * functionality for all widgets in the UltraguardPro system. It implements
 * performance-optimized methods for configuration parsing, validation,
 * rendering, and AJAX operations.
 *
 * The class serves as the foundation for all widget implementations,
 * providing a consistent API and ensuring security through proper
 * sanitization and validation of all widget data.
 *
 * @package    UltraguardPro\view
 * @author     Ultraguard Team <support@ultraguardpro.com>
 * @copyright  2024 UltraguardPro
 * @license    GPL-2.0-or-later
 * @version    1.0.0
 * @link       https://ultraguardpro.com/docs/widgets
 */

namespace UltraguardPro\view;

defined( 'ABSPATH' ) || exit;

/**
 * Base Widget Class - Optimized Version
 *
 * Provides common functionality for all widgets including configuration
 * management, data validation, rendering pipeline, and AJAX handlers.
 * Designed with performance optimizations through caching and lazy loading.
 *
 * This abstract class implements the Template Method pattern, requiring
 * derived classes to implement specific rendering logic while inheriting
 * common functionality. It includes performance optimizations such as
 * static caching, lazy initialization, and conditionally applied filters.
 *
 * Key features:
 * - Optimized configuration and data parsing with schema validation
 * - Lazy-loaded render engine for improved performance
 * - Comprehensive user permission checking
 * - AJAX support for dynamic updates
 * - Responsive error and loading states
 * - Extensible through WordPress filters and actions
 *
 * @package    UltraguardPro\view
 * @author     Ultraguard Team
 * @version    1.0.0
 * @since      1.0.0
 * @see        \UltraguardPro\view\RenderEngine
 *
 * @example
 * // In a concrete widget class:
 * class MyWidget extends BaseWidget {
 *     public function render() {
 *         $content = $this->render_content();
 *         return $this->render_wrapper($content);
 *     }
 *
 *     public static function enqueue_assets() {
 *         wp_enqueue_script('my-widget-script');
 *     }
 *
 *     public static function get_config_schema() {
 *         return [
 *             'title' => ['type' => 'string', 'default' => 'My Widget'],
 *             'show_data' => ['type' => 'boolean', 'default' => true]
 *         ];
 *     }
 * }
 */
abstract class BaseWidget {

    /**
     * Widget ID
     *
     * Unique identifier for the widget instance. Used for DOM element IDs,
     * CSS classes, and widget identification in the system.
     *
     * @var string
     * @access protected
     */
    protected $id;

    /**
     * Widget configuration
     *
     * Array of configuration options for the widget, including display
     * settings, behavior flags, and user permissions. Validated against
     * the configuration schema.
     *
     * @var array
     * @access protected
     */
    protected $config;

    /**
     * Widget data
     *
     * Array of data to be displayed by the widget. This can include
     * items, totals, timestamps, and other data specific to the widget
     * type. Validated against the data schema.
     *
     * @var array
     * @access protected
     */
    protected $data;

    /**
     * Render engine instance
     *
     * Reference to the render engine for rendering child components.
     * Lazily initialized when needed to improve performance.
     *
     * @var \UltraguardPro\view\RenderEngine|null
     * @access protected
     */
    protected $render_engine;

    /**
     * Widget type cache
     *
     * Cached widget type derived from class name. Used for CSS classes,
     * data attributes, and widget identification.
     *
     * @var string|null
     * @access protected
     */
    protected $widget_type = null;

    /**
     * Default config cache
     *
     * Static cache for default configuration values. Shared across all
     * widget instances to improve performance.
     *
     * @var array|null
     * @access protected
     * @static
     */
    protected static $default_config_cache = null;

    /**
     * Default data cache
     *
     * Static cache for default data values. Shared across all widget
     * instances to improve performance.
     *
     * @var array|null
     * @access protected
     * @static
     */
    protected static $default_data_cache = null;

    /**
     * BaseWidget constructor
     *
     * Initializes the widget with ID, configuration, and data. Validates
     * and sanitizes all input, sets up the widget instance, and fires
     * initialization hooks.
     *
     * @param  string  $id      Widget identifier
     * @param  array   $config  Widget configuration array
     * @param  array   $data    Widget data array
     * @return void
     * @access public
     *
     * @example
     * $widget = new MyWidget(
     *     'my-widget-123',
     *     ['title' => 'My Widget', 'visible' => true],
     *     ['items' => ['item1', 'item2']]
     * );
     */
    public function __construct( $id, $config = array(), $data = array() ) {
        // Validate and sanitize ID
        $this->id = $this->sanitize_widget_id( $id );
        $this->config = $this->parse_config( $config );
        $this->data = $this->parse_data( $data );

        // Initialize render engine lazily when needed
        $this->render_engine = null;

        $this->init();

        // Only fire action if there are listeners
        if ( has_action( 'ultraguard_widget_initialized' ) ) {
            do_action( 'ultraguard_widget_initialized', $this->id, $this->config, $this->data );
        }
    }

    /**
     * Initialize widget
     *
     * Hook method called after construction. Can be overridden by derived
     * classes to perform additional initialization. Fires the widget
     * initialization action.
     *
     * @return void
     * @access protected
     * @since  1.0.0
     *
     * @see    __construct()
     */
    protected function init() {
        // Only fire action if there are listeners
        if ( has_action( 'ultraguard_widget_init' ) ) {
            do_action( 'ultraguard_widget_init', $this->id );
        }
    }

    /**
     * Main render method
     *
     * Abstract method that must be implemented by derived classes to
     * render the widget's primary content. Should return the rendered
     * HTML output.
     *
     * @return string Rendered HTML content
     * @access public
     * @abstract
     *
     * @example
     * public function render() {
     *     $content = $this->generate_content();
     *     return $this->render_wrapper($content);
     * }
     */
    abstract public function render();

    /**
     * Enqueue widget-specific assets
     *
     * Abstract static method that must be implemented by derived classes
     * to enqueue CSS and JavaScript assets required by the widget.
     * Called when the widget is registered or displayed.
     *
     * @return void
     * @access public
     * @static
     * @abstract
     *
     * @example
     * public static function enqueue_assets() {
     *     wp_enqueue_style('my-widget-style', 'path/to/style.css');
     *     wp_enqueue_script('my-widget-script', 'path/to/script.js');
     * }
     */
    abstract public static function enqueue_assets();

    /**
     * Get widget configuration schema
     *
     * Abstract static method that must be implemented by derived classes
     * to define the configuration schema. The schema defines valid
     * configuration options, their types, defaults, and validation rules.
     *
     * @return array Configuration schema definition
     * @access public
     * @static
     * @abstract
     *
     * @example
     * public static function get_config_schema() {
     *     return [
     *         'title' => [
     *             'type' => 'string',
     *             'default' => '',
     *             'sanitize_callback' => 'sanitize_text_field'
     *         ],
     *         'refresh_interval' => [
     *             'type' => 'integer',
     *             'default' => 0,
     *             'min' => 0
     *         ]
     *     ];
     * }
     */
    abstract public static function get_config_schema();

    /**
     * Get data requirements
     *
     * Abstract static method that must be implemented by derived classes
     * to define the data schema. The schema defines the structure and
     * validation rules for widget data.
     *
     * @return array Data schema definition
     * @access public
     * @static
     * @abstract
     *
     * @example
     * public static function get_data_schema() {
     *     return [
     *         'items' => [
     *             'type' => 'array',
     *             'default' => [],
     *             'required' => false
     *         ],
     *         'total' => [
     *             'type' => 'integer',
     *             'default' => 0
     *         ]
     *     ];
     * }
     */
    abstract public static function get_data_schema();

    /**
     * Sanitize widget ID - OPTIMIZED VERSION
     *
     * Sanitizes and validates a widget ID string. Ensures the ID is safe
     * for use in HTML attributes and follows naming conventions. Falls
     * back to a generated ID if input is invalid.
     *
     * @param  string  $id  Raw widget ID
     * @return string       Sanitized widget ID
     * @access protected
     * @since  1.0.0
     *
     * @example
     * $clean_id = $this->sanitize_widget_id('My Widget!');
     * // Returns: 'my-widget'
     *
     * $clean_id = $this->sanitize_widget_id('');
     * // Returns: 'widget_abc123def'
     */
    protected function sanitize_widget_id( $id ) {
        // Fast return for empty
        if ( empty( $id ) || ! is_string( $id ) ) {
            return 'widget_' . wp_generate_password( 8, false );
        }

        $id = trim( $id );

        if ( empty( $id ) ) {
            return 'widget_' . wp_generate_password( 8, false );
        }

        $id = sanitize_key( $id );

        // Check if starts with letter (fast ASCII check)
        if ( ! empty( $id ) && ! ctype_alpha( $id[0] ) ) {
            $id = 'w_' . $id;
        }

        return ! empty( $id ) ? $id : 'widget_' . wp_generate_password( 8, false );
    }

    /**
     * Parse and validate configuration - OPTIMIZED
     *
     * Processes and validates widget configuration against the schema.
     * Applies default values, sanitizes input, and validates field types.
     * Uses static caching for performance.
     *
     * @param  array  $config  Raw configuration array
     * @return array           Parsed and validated configuration
     * @access protected
     * @since  1.0.0
     *
     * @see    get_config_schema()
     * @see    validate_config_field()
     *
     * @example
     * $config = $this->parse_config([
     *     'title' => 'My Widget',
     *     'refresh_interval' => '300'
     * ]);
     */
    protected function parse_config( $config ) {
        if ( ! is_array( $config ) ) {
            $config = array();
        }

        $defaults = $this->get_default_config();

        // Fast merge for empty config
        if ( empty( $config ) ) {
            $parsed = $defaults;
        } else {
            $parsed = wp_parse_args( $config, $defaults );
        }

        $schema = static::get_config_schema();

        if ( ! empty( $schema ) && is_array( $schema ) ) {
            foreach ( $schema as $key => $field ) {
                if ( ! is_string( $key ) || empty( $key ) ) {
                    continue;
                }

                // Pre-defined field defaults for speed
                $field_type = $field['type'] ?? 'string';
                $field_default = $field['default'] ?? null;
                $field_required = $field['required'] ?? false;
                $field_sanitize = $field['sanitize_callback'] ?? null;

                // Only process if not already set or needs validation
                if ( ! array_key_exists( $key, $parsed ) ) {
                    $parsed[ $key ] = $field_default;
                } elseif ( $field_sanitize && is_callable( $field_sanitize ) ) {
                    $parsed[ $key ] = call_user_func( $field_sanitize, $parsed[ $key ] );
                } else {
                    $parsed[ $key ] = $this->validate_config_field( $parsed[ $key ], $field_type, $field_default, $field_required );
                }
            }
        }

        // Only apply filters if needed
        if ( has_filter( 'ultraguard_widget_config_parsed' ) || has_filter( "ultraguard_widget_config_parsed_{$this->id}" ) ) {
            $parsed = apply_filters( 'ultraguard_widget_config_parsed', $parsed, $this->id );
            $parsed = apply_filters( "ultraguard_widget_config_parsed_{$this->id}", $parsed );
        }

        return $parsed;
    }

    /**
     * Parse and validate data - OPTIMIZED
     *
     * Processes and validates widget data against the schema. Applies
     * default values and validates field types. Optimized for performance
     * with early returns and minimal processing.
     *
     * @param  array  $data  Raw data array
     * @return array         Parsed and validated data
     * @access protected
     * @since  1.0.0
     *
     * @see    get_data_schema()
     * @see    validate_data_field()
     *
     * @example
     * $data = $this->parse_data([
     *     'items' => ['item1', 'item2'],
     *     'total' => 2
     * ]);
     */
    protected function parse_data( $data ) {
        if ( ! is_array( $data ) ) {
            $data = array();
        }

        $defaults = $this->get_default_data();

        // Fast merge for empty data
        if ( empty( $data ) ) {
            $parsed = $defaults;
        } else {
            $parsed = wp_parse_args( $data, $defaults );
        }

        $schema = static::get_data_schema();

        if ( ! empty( $schema ) && is_array( $schema ) ) {
            foreach ( $schema as $key => $field ) {
                if ( ! is_string( $key ) || empty( $key ) ) {
                    continue;
                }

                $field_type = $field['type'] ?? 'mixed';
                $field_default = $field['default'] ?? null;
                $field_required = $field['required'] ?? false;

                if ( ! array_key_exists( $key, $parsed ) ) {
                    $parsed[ $key ] = $field_default;
                } else {
                    $parsed[ $key ] = $this->validate_data_field( $parsed[ $key ], $field_type, $field_default, $field_required );
                }
            }
        }

        // Only apply filters if needed
        if ( has_filter( 'ultraguard_widget_data_parsed' ) || has_filter( "ultraguard_widget_data_parsed_{$this->id}" ) ) {
            $parsed = apply_filters( 'ultraguard_widget_data_parsed', $parsed, $this->id );
            $parsed = apply_filters( "ultraguard_widget_data_parsed_{$this->id}", $parsed );
        }

        return $parsed;
    }

    /**
     * Get default configuration with caching
     *
     * Returns the default configuration array with static caching for
     * performance. Applies filters for extensibility only when listeners
     * are registered.
     *
     * @return array Default configuration values
     * @access protected
     * @since  1.0.0
     *
     * @example
     * $defaults = $this->get_default_config();
     * // Returns: ['title' => '', 'visible' => true, ...]
     */
    protected function get_default_config() {
        if ( self::$default_config_cache === null ) {
            $defaults = array(
                'title' => '',
                'description' => '',
                'width' => 'auto',
                'height' => 'auto',
                'refresh_interval' => 0,
                'ajax_enabled' => true,
                'css_class' => '',
                'style' => '',
                'visible' => true,
                'capability' => 'read',
                'roles' => array()
            );

            self::$default_config_cache = $defaults;
        }

        // Only apply filters if there are listeners
        if ( has_filter( 'ultraguard_widget_default_config' ) ) {
            return apply_filters( 'ultraguard_widget_default_config', self::$default_config_cache, $this->id );
        }

        return self::$default_config_cache;
    }

    /**
     * Get default data with caching
     *
     * Returns the default data array with static caching for performance.
     * Applies filters for extensibility only when listeners are registered.
     *
     * @return array Default data values
     * @access protected
     * @since  1.0.0
     *
     * @example
     * $defaults = $this->get_default_data();
     * // Returns: ['items' => [], 'total' => 0, ...]
     */
    protected function get_default_data() {
        if ( self::$default_data_cache === null ) {
            $defaults = array(
                'items' => array(),
                'total' => 0,
                'timestamp' => time(),
                'cached' => false
            );

            self::$default_data_cache = $defaults;
        }

        // Only apply filters if there are listeners
        if ( has_filter( 'ultraguard_widget_default_data' ) ) {
            return apply_filters( 'ultraguard_widget_default_data', self::$default_data_cache, $this->id );
        }

        return self::$default_data_cache;
    }

    /**
     * Validate configuration field - OPTIMIZED
     *
     * Validates a single configuration field based on its type definition.
     * Applies type-specific validation and returns the default value if
     * validation fails.
     *
     * @param  mixed   $value     Field value to validate
     * @param  string  $type      Expected field type
     * @param  mixed   $default   Default value if validation fails
     * @param  bool    $required  Whether the field is required
     * @return mixed              Validated field value
     * @access protected
     * @since  1.0.0
     *
     * @example
     * $validated = $this->validate_config_field('300', 'integer', 0, false);
     * // Returns: 300 (as integer)
     */
    protected function validate_config_field( $value, $type, $default, $required ) {
        // Handle required fields
        if ( $required && ( $value === null || $value === '' || $value === array() ) ) {
            return $default;
        }

        switch ( $type ) {
            case 'number':
                return is_numeric( $value ) ? (float) $value : $default;

            case 'integer':
                return is_numeric( $value ) ? (int) $value : $default;

            case 'boolean':
                return (bool) $value;

            case 'array':
                return is_array( $value ) ? $value : (array) $default;

            case 'string':
            default:
                return is_string( $value ) ? sanitize_text_field( $value ) : $default;
        }
    }

    /**
     * Validate data field - OPTIMIZED
     *
     * Validates a single data field based on its type definition. Includes
     * special handling for HTML content and mixed types.
     *
     * @param  mixed   $value     Field value to validate
     * @param  string  $type      Expected field type
     * @param  mixed   $default   Default value if validation fails
     * @param  bool    $required  Whether the field is required
     * @return mixed              Validated field value
     * @access protected
     * @since  1.0.0
     *
     * @example
     * $validated = $this->validate_data_field(
     *     '<p>HTML content</p>',
     *     'html',
     *     '',
     *     false
     * );
     * // Returns: '<p>HTML content</p>' (sanitized)
     */
    protected function validate_data_field( $value, $type, $default, $required ) {
        // Handle required fields
        if ( $required && ( $value === null || $value === '' || $value === array() ) ) {
            return $default;
        }

        switch ( $type ) {
            case 'number':
                return is_numeric( $value ) ? (float) $value : $default;

            case 'integer':
                return is_numeric( $value ) ? (int) $value : $default;

            case 'boolean':
                return (bool) $value;

            case 'array':
                return is_array( $value ) ? $value : (array) $default;

            case 'string':
                return is_string( $value ) ? sanitize_text_field( $value ) : $default;

            case 'html':
                return is_string( $value ) ? wp_kses_post( $value ) : $default;

            case 'mixed':
            default:
                return $value;
        }
    }

    /**
     * Render widget wrapper - OPTIMIZED
     *
     * Wraps widget content in a container with appropriate attributes,
     * classes, and data properties. Handles visibility checks, permission
     * validation, and lazy initialization of the render engine.
     *
     * @param  string  $content  Widget content to wrap
     * @return string            Wrapped widget HTML
     * @access protected
     * @since  1.0.0
     *
     * @see    user_can_view()
     * @see    render_insufficient_permissions()
     *
     * @example
     * $wrapped = $this->render_wrapper('<p>Widget content</p>');
     * // Returns: <div id="ultraguard-widget-myid" class="ultraguard-widget ...">...</div>
     */
    protected function render_wrapper( $content ) {
        if ( ! $this->config['visible'] ) {
            return '';
        }

        // Check user capabilities
        if ( ! $this->user_can_view() ) {
            return $this->render_insufficient_permissions();
        }

        // Initialize render engine lazily
        if ( $this->render_engine === null ) {
            $this->render_engine = RenderEngine::get_instance();
        }

        $classes = array( 'ultraguard-widget', 'ultraguard-widget-' . $this->get_type() );

        if ( ! empty( $this->config['css_class'] ) ) {
            $classes[] = sanitize_html_class( $this->config['css_class'] );
        }

        if ( $this->config['ajax_enabled'] ) {
            $classes[] = 'ultraguard-widget-ajax';
        }

        if ( $this->config['refresh_interval'] > 0 ) {
            $classes[] = 'ultraguard-widget-refreshable';
        }

        // Check for filters before applying
        if ( has_filter( 'ultraguard_widget_classes' ) || has_filter( "ultraguard_widget_classes_{$this->id}" ) ) {
            $classes = apply_filters( 'ultraguard_widget_classes', $classes, $this->id, $this->config );
            $classes = apply_filters( "ultraguard_widget_classes_{$this->id}", $classes, $this->config );
        }

        $attributes = array(
            'id' => 'ultraguard-widget-' . esc_attr( $this->id ),
            'class' => implode( ' ', $classes ),
            'data-widget-id' => esc_attr( $this->id ),
            'data-widget-type' => esc_attr( $this->get_type() ),
            'data-refresh-interval' => absint( $this->config['refresh_interval'] )
        );

        if ( ! empty( $this->config['style'] ) ) {
            $attributes['style'] = esc_attr( $this->config['style'] );
        }

        // Add data attributes
        $data_attributes = $this->get_data_attributes();
        if ( ! empty( $data_attributes ) ) {
            $attributes = array_merge( $attributes, $data_attributes );
        }

        // Check for filters before applying
        if ( has_filter( 'ultraguard_widget_attributes' ) || has_filter( "ultraguard_widget_attributes_{$this->id}" ) ) {
            $attributes = apply_filters( 'ultraguard_widget_attributes', $attributes, $this->id, $this->config );
            $attributes = apply_filters( "ultraguard_widget_attributes_{$this->id}", $attributes, $this->config );
        }

        $attributes_string = '';
        foreach ( $attributes as $key => $value ) {
            if ( is_bool( $value ) ) {
                if ( $value ) {
                    $attributes_string .= ' ' . esc_attr( $key );
                }
            } else {
                $attributes_string .= ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
            }
        }

        $header = $this->render_header();
        $footer = $this->render_footer();

        $output = '<div' . $attributes_string . '>' . $header . $content . $footer . '</div>';

        // Check for filters before applying
        if ( has_filter( 'ultraguard_widget_output' ) || has_filter( "ultraguard_widget_output_{$this->id}" ) ) {
            $output = apply_filters( 'ultraguard_widget_output', $output, $this->id, $this->config, $this->data );
            $output = apply_filters( "ultraguard_widget_output_{$this->id}", $output, $this->config, $this->data );
        }

        return $output;
    }

    /**
     * Get data attributes for wrapper - OPTIMIZED
     *
     * Generates data attributes for the widget wrapper, including
     * configuration JSON and metadata. Optimized to only apply filters
     * when listeners are registered.
     *
     * @return array Data attributes for HTML output
     * @access protected
     * @since  1.0.0
     *
     * @see    get_public_config()
     *
     * @example
     * $attrs = $this->get_data_attributes();
     * // Returns: ['data-config' => '{"id":"myid","title":"My Widget"}', ...]
     */
    protected function get_data_attributes() {
        $public_config = $this->get_public_config();

        // Use wp_json_encode with minimal flags for speed
        $json_config = wp_json_encode( $public_config, JSON_UNESCAPED_SLASHES );

        if ( false === $json_config ) {
            $json_config = '{}';
        }

        $data_attrs = array(
            'data-config' => $json_config,
            'data-timestamp' => time(),
            'data-version' => '1.0.0'
        );

        // Only apply filters if needed
        if ( has_filter( 'ultraguard_widget_data_attributes' ) ) {
            return apply_filters( 'ultraguard_widget_data_attributes', $data_attrs, $this->id );
        }

        return $data_attrs;
    }

    /**
     * Get public configuration (safe for frontend)
     *
     * Returns a sanitized subset of configuration that is safe to expose
     * to the frontend. Excludes sensitive data like user permissions and
     * internal settings.
     *
     * @return array Public-safe configuration
     * @access protected
     * @since  1.0.0
     *
     * @example
     * $public = $this->get_public_config();
     * // Returns: ['id' => 'myid', 'title' => 'My Widget', ...]
     */
    protected function get_public_config() {
        $public_config = array(
            'id' => $this->id,
            'type' => $this->get_type(),
            'title' => $this->config['title'],
            'refresh_interval' => $this->config['refresh_interval'],
            'ajax_enabled' => $this->config['ajax_enabled']
        );

        // Only apply filters if needed
        if ( has_filter( 'ultraguard_widget_public_config' ) ) {
            return apply_filters( 'ultraguard_widget_public_config', $public_config, $this->id, $this->config );
        }

        return $public_config;
    }

    /**
     * Render widget header - OPTIMIZED
     *
     * Generates the widget header HTML including title, description,
     * and action buttons. Returns empty string if no header content
     * is needed.
     *
     * @return string Header HTML or empty string
     * @access protected
     * @since  1.0.0
     *
     * @see    render_header_actions()
     *
     * @example
     * $header = $this->render_header();
     * // Returns: <div class="ultraguard-widget-header">...</div>
     */
    protected function render_header() {
        $title = $this->config['title'] ?? '';
        $description = $this->config['description'] ?? '';

        if ( empty( $title ) && empty( $description ) ) {
            return '';
        }

        $title_html = $title ? '<h3 class="ultraguard-widget-title">' . esc_html( $title ) . '</h3>' : '';
        $description_html = $description ? '<p class="ultraguard-widget-description">' . esc_html( $description ) . '</p>' : '';
        $actions = $this->render_header_actions();

        return '<div class="ultraguard-widget-header">' . $title_html . $description_html . $actions . '</div>';
    }

    /**
     * Render widget footer
     *
     * Generates the widget footer HTML with action buttons. Returns
     * empty string if no footer content is needed.
     *
     * @return string Footer HTML or empty string
     * @access protected
     * @since  1.0.0
     *
     * @see    render_footer_actions()
     *
     * @example
     * $footer = $this->render_footer();
     * // Returns: <div class="ultraguard-widget-footer">...</div>
     */
    protected function render_footer() {
        $actions = $this->render_footer_actions();

        if ( empty( $actions ) ) {
            return '';
        }

        return '<div class="ultraguard-widget-footer">' . $actions . '</div>';
    }

    /**
     * Render header actions
     *
     * Generates action buttons for the widget header, including refresh
     * and configure buttons based on widget configuration.
     *
     * @return string Header actions HTML
     * @access protected
     * @since  1.0.0
     *
     * @example
     * $actions = $this->render_header_actions();
     * // Returns: '<div class="ultraguard-widget-actions">...</div>'
     */
    protected function render_header_actions() {
        $actions = array();

        // Refresh action
        if ( $this->config['refresh_interval'] > 0 ) {
            $actions[] = '<button type="button" class="ultraguard-widget-refresh" title="' .
                        esc_attr__( 'Refresh', 'ultraguard-security-suite' ) .
                        '"><span class="dashicons dashicons-update"></span></button>';
        }

        // Configure action
        $actions[] = '<button type="button" class="ultraguard-widget-configure" title="' .
                    esc_attr__( 'Configure', 'ultraguard-security-suite' ) .
                    '"><span class="dashicons dashicons-admin-generic"></span></button>';

        if ( empty( $actions ) ) {
            return '';
        }

        return '<div class="ultraguard-widget-actions">' . implode( '', $actions ) . '</div>';
    }

    /**
     * Render footer actions
     *
     * Generates action buttons for the widget footer. By default returns
     * empty string; can be populated via WordPress filters.
     *
     * @return string Footer actions HTML
     * @access protected
     * @since  1.0.0
     *
     * @example
     * // Add footer actions via filter:
     * add_filter('ultraguard_widget_footer_actions', function($actions, $widget_id) {
     *     $actions[] = '<button>Custom Action</button>';
     *     return $actions;
     * }, 10, 2);
     */
    protected function render_footer_actions() {
        // Only apply filters if there are listeners
        if ( ! has_filter( 'ultraguard_widget_footer_actions' ) && ! has_filter( "ultraguard_widget_footer_actions_{$this->id}" ) ) {
            return '';
        }

        $actions = apply_filters( 'ultraguard_widget_footer_actions', array(), $this->id, $this->config );
        $actions = apply_filters( "ultraguard_widget_footer_actions_{$this->id}", $actions, $this->config );

        return implode( '', $actions );
    }

    /**
     * Render loading state
     *
     * Generates HTML for the widget loading state with optional custom
     * message. Includes a CSS spinner for visual feedback.
     *
     * @param  string  $message  Optional loading message
     * @return string            Loading state HTML
     * @access protected
     * @since  1.0.0
     *
     * @example
     * $loading = $this->render_loading('Loading data...');
     * // Returns: <div class="ultraguard-widget-loading">...</div>
     */
    protected function render_loading( $message = '' ) {
        if ( ! is_string( $message ) || empty( $message ) ) {
            $message = esc_html__( 'Loading...', 'ultraguard-security-suite' );
        }

        return '<div class="ultraguard-widget-loading">' .
               '<div class="ultraguard-loading-spinner"></div>' .
               '<p>' . esc_html( $message ) . '</p>' .
               '</div>';
    }

    /**
     * Render error state
     *
     * Generates HTML for the widget error state with error message and
     * optional error code. Includes warning icon for visual identification.
     *
     * @param  string  $message  Error message
     * @param  string  $code     Optional error code
     * @return string            Error state HTML
     * @access protected
     * @since  1.0.0
     *
     * @example
     * $error = $this->render_error('Failed to load data', 'DATA_LOAD_ERROR');
     * // Returns: <div class="ultraguard-widget-error">...</div>
     */
    protected function render_error( $message, $code = '' ) {
        if ( ! is_string( $message ) || empty( $message ) ) {
            $message = esc_html__( 'An unknown error occurred', 'ultraguard-security-suite' );
        }

        $code_html = $code ? ' <small>(' . esc_html( $code ) . ')</small>' : '';

        return '<div class="ultraguard-widget-error">' .
               '<span class="dashicons dashicons-warning"></span>' .
               '<p>' . esc_html( $message ) . $code_html . '</p>' .
               '</div>';
    }

    /**
     * Render empty state
     *
     * Generates HTML for the widget empty state with optional custom
     * message. Includes info icon for visual identification.
     *
     * @param  string  $message  Optional empty state message
     * @return string            Empty state HTML
     * @access protected
     * @since  1.0.0
     *
     * @example
     * $empty = $this->render_empty('No records found');
     * // Returns: <div class="ultraguard-widget-empty">...</div>
     */
    protected function render_empty( $message = '' ) {
        if ( ! is_string( $message ) || empty( $message ) ) {
            $message = esc_html__( 'No data available', 'ultraguard-security-suite' );
        }

        return '<div class="ultraguard-widget-empty">' .
               '<span class="dashicons dashicons-info"></span>' .
               '<p>' . esc_html( $message ) . '</p>' .
               '</div>';
    }

    /**
     * Render insufficient permissions state
     *
     * Generates HTML for the widget permission error state. Displayed
     * when the current user lacks permission to view the widget.
     *
     * @return string Permission error HTML
     * @access protected
     * @since  1.0.0
     *
     * @see    user_can_view()
     *
     * @example
     * $permission_error = $this->render_insufficient_permissions();
     * // Returns: <div class="ultraguard-widget-permission-error">...</div>
     */
    protected function render_insufficient_permissions() {
        return '<div class="ultraguard-widget-permission-error">' .
               '<span class="dashicons dashicons-lock"></span>' .
               '<p>' . esc_html__( 'Insufficient permissions to view this widget', 'ultraguard-security-suite' ) . '</p>' .
               '</div>';
    }

    /**
     * Get widget type with caching
     *
     * Determines the widget type from the class name with caching for
     * performance. Converts camelCase class names to kebab-case.
     *
     * @return string Widget type identifier
     * @access protected
     * @since  1.0.0
     *
     * @example
     * $type = $this->get_type(); // Returns: 'my-widget' from MyWidget class
     */
    protected function get_type() {
        if ( $this->widget_type !== null ) {
            return $this->widget_type;
        }

        $class_name = get_class( $this );
        $parts = explode( '\\', $class_name );
        $class = end( $parts );

        if ( empty( $class ) ) {
            $this->widget_type = 'unknown-widget';
            return $this->widget_type;
        }

        // Cache the result
        $this->widget_type = strtolower( preg_replace( '/([a-zA-Z])(?=[A-Z])/', '$1-', $class ) );
        return $this->widget_type;
    }

    /**
     * Check if current user can view widget - OPTIMIZED
     *
     * Validates user permissions based on widget configuration. Checks
     * WordPress capabilities and specific user roles.
     *
     * @return bool True if user has permission, false otherwise
     * @access protected
     * @since  1.0.0
     *
     * @see    current_user_can()
     * @see    wp_get_current_user()
     *
     * @example
     * if ($this->user_can_view()) {
     *     // Render widget content
     * } else {
     *     // Show permission error
     * }
     */
    protected function user_can_view() {
        // Check capability
        if ( ! empty( $this->config['capability'] ) && ! current_user_can( $this->config['capability'] ) ) {
            return false;
        }

        // Check specific roles
        $roles = $this->config['roles'] ?? array();
        if ( ! empty( $roles ) && is_array( $roles ) ) {
            $user = wp_get_current_user();

            // Fast intersection check
            if ( empty( array_intersect( (array) $user->roles, $roles ) ) ) {
                return false;
            }
        }

        // Only apply filters if there are listeners
        if ( has_filter( 'ultraguard_widget_user_can_view' ) ) {
            return (bool) apply_filters( 'ultraguard_widget_user_can_view', true, $this->id, $this->config );
        }

        return true;
    }

    /**
     * Handle AJAX refresh - OPTIMIZED
     *
     * Processes AJAX refresh requests for the widget. Validates permissions,
     * re-renders content, and returns structured JSON response. Includes
     * error handling and logging.
     *
     * @return array Structured response data
     * @access public
     * @since  1.0.0
     *
     * @throws \Exception If rendering fails
     *
     * @example
     * // AJAX endpoint handler:
     * $response = $widget->ajax_refresh();
     * wp_send_json($response);
     */
    public function ajax_refresh() {
        // Check user permissions
        if ( ! $this->user_can_view() ) {
            return array(
                'success' => false,
                'error' => esc_html__( 'Insufficient permissions', 'ultraguard-security-suite' ),
                'content' => $this->render_insufficient_permissions(),
                'widget_id' => $this->id
            );
        }

        try {
            // Clear any output buffers
            if ( ob_get_length() > 0 ) {
                ob_clean();
            }

            $content = $this->render();

            // Validate that we got string content
            if ( ! is_string( $content ) ) {
                throw new \Exception( esc_html__( 'Invalid render output', 'ultraguard-security-suite' ) );
            }

            $response = array(
                'success' => true,
                'content' => $content,
                'timestamp' => time(),
                'widget_id' => $this->id
            );

            // Only fire action if there are listeners
            if ( has_action( 'ultraguard_widget_ajax_refresh' ) ) {
                do_action( 'ultraguard_widget_ajax_refresh', $this->id, $response );
            }

            return $response;

        } catch ( \Exception $e ) {
            // Log the error
            if ( function_exists( 'error_log' ) ) {
                \UltraguardPro\core\Logger::error(
                    sprintf(
                    'Widget AJAX refresh error [%s]: %s',
                    $this->id,
                    $e->getMessage()
                )
                );
            }

            $error_response = array(
                'success' => false,
                'error' => $e->getMessage(),
                'content' => $this->render_error( $e->getMessage(), 'render_error' ),
                'widget_id' => $this->id
            );

            // Only fire action if there are listeners
            if ( has_action( 'ultraguard_widget_ajax_refresh_error' ) ) {
                do_action( 'ultraguard_widget_ajax_refresh_error', $this->id, $e->getMessage(), $error_response );
            }

            return $error_response;
        }
    }

    /**
     * Handle AJAX configuration
     *
     * Processes AJAX configuration update requests. Validates admin
     * permissions, parses new configuration, and returns updated widget
     * state.
     *
     * @param  array  $new_config  New configuration values
     * @return array               Structured response data
     * @access public
     * @since  1.0.0
     *
     * @example
     * // AJAX configuration handler:
     * $response = $widget->ajax_configure($_POST['config']);
     * wp_send_json($response);
     */
    public function ajax_configure( $new_config ) {
        if ( ! function_exists( '\\UltraguardPro\\ultraguard_current_user_can_manage' ) || ! \UltraguardPro\ultraguard_current_user_can_manage() ) {
            return array(
                'success' => false,
                'error' => esc_html__( 'Insufficient permissions', 'ultraguard-security-suite' )
            );
        }

        if ( ! is_array( $new_config ) ) {
            $new_config = array();
        }

        $this->config = $this->parse_config( $new_config );

        $response = array(
            'success' => true,
            'config' => $this->get_public_config(),
            'content' => $this->render(),
            'widget_id' => $this->id
        );

        // Only fire action if there are listeners
        if ( has_action( 'ultraguard_widget_ajax_configure' ) ) {
            do_action( 'ultraguard_widget_ajax_configure', $this->id, $new_config, $response );
        }

        return $response;
    }

    /**
     * Handle AJAX export
     *
     * Processes AJAX export requests for widget data and configuration.
     * Validates admin permissions and returns complete widget state.
     *
     * @return array Export data response
     * @access public
     * @since  1.0.0
     *
     * @example
     * // AJAX export handler:
     * $response = $widget->ajax_export();
     * wp_send_json($response);
     */
    public function ajax_export() {
        if ( ! function_exists( '\\UltraguardPro\\ultraguard_current_user_can_manage' ) || ! \UltraguardPro\ultraguard_current_user_can_manage() ) {
            return array(
                'success' => false,
                'error' => esc_html__( 'Insufficient permissions', 'ultraguard-security-suite' )
            );
        }

        $export_data = array(
            'id' => $this->id,
            'type' => $this->get_type(),
            'config' => $this->config,
            'data' => $this->data,
            'timestamp' => time(),
            'version' => '1.0.0'
        );

        $response = array(
            'success' => true,
            'data' => $export_data
        );

        // Only fire action if there are listeners
        if ( has_action( 'ultraguard_widget_ajax_export' ) ) {
            do_action( 'ultraguard_widget_ajax_export', $this->id, $export_data, $response );
        }

        return $response;
    }

    /**
     * Get widget ID
     *
     * Returns the widget's unique identifier.
     *
     * @return string Widget ID
     * @access public
     * @since  1.0.0
     *
     * @example
     * $widget_id = $widget->get_id();
     * // Returns: 'my-widget-123'
     */
    public function get_id() {
        return $this->id;
    }

    /**
     * Get widget configuration
     *
     * Returns the widget's current configuration array.
     *
     * @return array Widget configuration
     * @access public
     * @since  1.0.0
     *
     * @example
     * $config = $widget->get_config();
     * // Returns: ['title' => 'My Widget', 'visible' => true, ...]
     */
    public function get_config() {
        return $this->config;
    }

    /**
     * Get widget data
     *
     * Returns the widget's current data array.
     *
     * @return array Widget data
     * @access public
     * @since  1.0.0
     *
     * @example
     * $data = $widget->get_data();
     * // Returns: ['items' => [...], 'total' => 10, ...]
     */
    public function get_data() {
        return $this->data;
    }
}
