<?php
/**
 * UltraGuard Pro - Enhanced AJAX Response Builder
 *
 * A comprehensive, production-ready response builder for handling all AJAX interactions
 * with robust error handling, flexible action system, extensive validation, and advanced
 * DOM manipulation capabilities.
 *
 * @package    UltraguardPro
 * @subpackage Core
 * @version    3.0.0
 * @author     UltraGuard Pro Team
 * @license    GPL-2.0+
 */

namespace UltraguardPro\support;

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Enhanced AJAX Response Builder Class
 *
 * Provides a fluent interface for building standardized AJAX responses
 * with support for multiple actions, error handling, various response types,
 * and advanced DOM manipulation features.
 *
 * NEW IN 3.0.0:
 * - Additional DOM manipulation methods (show, hide, toggle, slide, fade)
 * - Conditional actions based on client-side conditions
 * - Action priorities for execution order control
 * - Batch actions for better performance
 * - Enhanced animation support
 * - CSS manipulation helpers
 * - Advanced form handling
 * - Event delegation support
 *
 * @since 3.0.0
 */
class AjaxResponseBuilder {

    /**
     * Optional UI / DOM signature metadata merged into every response.
     *
     * @var array
     */
    private $dom_signature = [];

    /**
     * Response structure
     *
     * @var array
     */
    private $response = [
        'success' => false,
        'message' => '',
        'data'    => [],
        'actions' => [],
        'code'    => null,
        'debug'   => []
    ];

    /**
     * Valid action types
     *
     * @var array
     */
    private static $valid_action_types = [
        // Core actions
        'notification',
        'reload',
        'redirect',

        // Content manipulation
        'update',
        'remove',
        'append',
        'prepend',
        'replace',
        'empty',
        'clone',
        'insertBefore',
        'insertAfter',

        // Class manipulation
        'addClass',
        'removeClass',
        'toggleClass',

        // Attribute manipulation
        'updateAttribute',
        'removeAttribute',
        'updateData',

        // Visibility manipulation
        'show',
        'hide',
        'toggle',
        'fadeIn',
        'fadeOut',
        'fadeToggle',
        'slideUp',
        'slideDown',
        'slideToggle',

        // CSS manipulation
        'css',
        'animate',

        // Events
        'trigger',
        'on',
        'off',

        // Component actions
        'modal',
        'widget',
        'form',
        'datatable',

        // Advanced actions
        'script',
        'style',
        'scroll',
        'focus',
        'download',
        'showMessage',

        // Batch actions
        'batch',
        'conditional',
        'delay'
    ];

    /**
     * Valid notification/message statuses
     *
     * @var array
     */
    private static $valid_statuses = [
        'success',
        'error',
        'warning',
        'info'
    ];

    /**
     * Action priority levels
     *
     * @var array
     */
    private static $priority_levels = [
        'critical' => 0,
        'high'     => 10,
        'normal'   => 50,
        'low'      => 100
    ];

    /**
     * Debug mode flag
     *
     * @var bool
     */
    private $debug_mode = false;

    /**
     * Constructor
     */
    public function __construct() {
        $this->debug_mode = defined('WP_DEBUG') && WP_DEBUG;
        $this->reset();
    }

    /**
     * Create a new response instance
     *
     * @return self
     */
    public function create() {
        $this->reset();
        return $this;
    }

    /**
     * Reset response to default state
     *
     * @return self
     */
    public function reset() {
        $this->response = [
            'success' => false,
            'message' => '',
            'data'    => [],
            'actions' => [],
            'code'    => null,
            'debug'   => []
        ];
        return $this;
    }

    // ==================== Core Response Methods ====================

    /**
     * Set success status
     *
     * @param bool $success Success status
     * @return self
     */
    public function setSuccess($success = true) {
        $this->response['success'] = (bool) $success;
        return $this;
    }

    /**
     * Set error status (convenience method)
     *
     * @return self
     */
    public function setError() {
        $this->response['success'] = false;
        return $this;
    }

    /**
     * Set response message
     *
     * @param string $message Message to display
     * @return self
     */
    public function setMessage($message) {
        $this->response['message'] = sanitize_text_field($message);
        return $this;
    }

    /**
     * Set error message and code
     *
     * @param string $message Error message
     * @param string $code    Error code (default: 'error')
     * @return self
     */
    public function setErrorMessage($message, $code = 'error') {
        $this->response['success'] = false;
        $this->response['message'] = sanitize_text_field($message);
        $this->response['code'] = $code;
        return $this;
    }

    /**
     * Set success message
     *
     * @param string $message Success message
     * @return self
     */
    public function setSuccessMessage($message) {
        $this->response['success'] = true;
        $this->response['message'] = sanitize_text_field($message);
        return $this;
    }

    /**
     * Set response code
     *
     * @param string $code Response code
     * @return self
     */
    public function setCode($code) {
        $this->response['code'] = sanitize_key($code);
        return $this;
    }

    /**
     * Set entire data array
     *
     * @param array|object $data Data to set
     * @return self
     */
    public function setData($data) {
        $this->response['data'] = (array) $data;
        return $this;
    }

    /**
     * Add a single data item
     *
     * @param string $key   Data key
     * @param mixed  $value Data value
     * @return self
     */
    public function addData($key, $value) {
        $this->response['data'][$key] = $value;
        return $this;
    }

    /**
     * Merge data array
     *
     * @param array|mixed $data Data to merge
     * @return self
     */
    public function mergeData($data) {
        if (is_array($data)) {
            $this->response['data'] = array_merge($this->response['data'], $data);
        }
        return $this;
    }

    /**
     * Remove data by key
     *
     * @param string $key Data key to remove
     * @return self
     */
    public function removeData($key) {
        unset($this->response['data'][$key]);
        return $this;
    }

    /**
     * Attach extra DOM signature metadata to the response.
     *
     * @param array $signature Signature fields to merge.
     * @return self
     */
    public function withDomSignature(array $signature = []) {
        $this->dom_signature = array_merge(
            $this->dom_signature,
            $this->sanitizeDomSignature($signature)
        );
        return $this;
    }

    // ==================== Action Management ====================

    /**
     * Add an action to the response
     *
     * @param array|string $action   Action configuration or action type
     * @param array        $params   Optional parameters if first arg is string
     * @param string       $priority Action priority (critical, high, normal, low)
     * @return self
     * @throws \InvalidArgumentException
     */
    public function addAction($action, $params = [], $priority = 'normal') {
        // Handle string action type (shorthand)
        if (is_string($action)) {
            $action = array_merge(['type' => $action], $params);
        }

        if (!is_array($action)) {
            $this->addDebug('Invalid action format', $action);
            throw new \InvalidArgumentException(esc_html( 'Action must be an array or string' ));
        }

        if (!isset($action['type'])) {
            $this->addDebug('Action missing type', $action);
            throw new \InvalidArgumentException(esc_html( 'Action must have a type' ));
        }

        if (!in_array($action['type'], self::$valid_action_types)) {
            $this->addDebug('Invalid action type: ' . $action['type'], $action);
        }

        // Add priority if not already set
        if (!isset($action['priority'])) {
            $action['priority'] = isset(self::$priority_levels[$priority])
                ? self::$priority_levels[$priority]
                : self::$priority_levels['normal'];
        }

        $this->response['actions'][] = $action;
        return $this;
    }

    /**
     * Add multiple actions
     *
     * @param array $actions Array of action configurations
     * @return self
     */
    public function addActions($actions) {
        if (!is_array($actions)) {
            $this->addDebug('addActions expects array', gettype($actions));
            return $this;
        }

        foreach ($actions as $action) {
            if (is_array($action) || is_string($action)) {
                try {
                    $this->addAction($action);
                } catch (\Exception $e) {
                    $this->addDebug('Failed to add action: ' . $e->getMessage(), $action);
                }
            }
        }
        return $this;
    }

    /**
     * Add a batch of actions to execute together
     *
     * @param array $actions Array of actions to batch
     * @param array $options Batch options (parallel, rollback, etc.)
     * @return self
     */
    public function addBatch($actions, $options = []) {
        return $this->addAction([
            'type'    => 'batch',
            'actions' => $actions,
            'options' => $options
        ], [], 'high');
    }

    /**
     * Add a conditional action
     *
     * @param string $condition JavaScript condition to evaluate
     * @param array  $ifTrue    Actions to execute if condition is true
     * @param array  $ifFalse   Actions to execute if condition is false
     * @return self
     */
    public function addConditional($condition, $ifTrue, $ifFalse = []) {
        return $this->addAction([
            'type'      => 'conditional',
            'condition' => $condition,
            'ifTrue'    => $ifTrue,
            'ifFalse'   => $ifFalse
        ], [], 'high');
    }

    /**
     * Add a delayed action
     *
     * @param array $action Action to delay
     * @param int   $delay  Delay in milliseconds
     * @return self
     */
    public function addDelay($action, $delay) {
        return $this->addAction([
            'type'   => 'delay',
            'action' => $action,
            'delay'  => absint($delay)
        ]);
    }

    /**
     * Clear all actions
     *
     * @return self
     */
    public function clearActions() {
        $this->response['actions'] = [];
        return $this;
    }

    /**
     * Sort actions by priority
     *
     * @return self
     */
    public function sortActionsByPriority() {
        usort($this->response['actions'], function($a, $b) {
            $priorityA = isset($a['priority']) ? $a['priority'] : 50;
            $priorityB = isset($b['priority']) ? $b['priority'] : 50;
            return $priorityA - $priorityB;
        });
        return $this;
    }

    // ==================== Content Manipulation Actions ====================

    /**
     * Add notification action
     *
     * @param string $message  Notification message
     * @param string $status   Status type (success, error, warning, info)
     * @param int    $duration Duration in milliseconds (0 = no auto-hide)
     * @return self
     */
    public function addNotification($message, $status = 'info', $duration = 5000) {
        $status = in_array($status, self::$valid_statuses) ? $status : 'info';

        return $this->addAction([
            'type'     => 'notification',
            'message'  => sanitize_text_field($message),
            'status'   => $status,
            'duration' => absint($duration)
        ], [], 'high');
    }

    /**
     * Add reload action
     *
     * @param int $delay Delay in milliseconds before reload
     * @return self
     */
    public function addReload($delay = 1000) {
        return $this->addAction([
            'type'  => 'reload',
            'delay' => absint($delay)
        ], [], 'low');
    }

    /**
     * Add redirect action
     *
     * @param string $url   URL to redirect to
     * @param int    $delay Delay in milliseconds before redirect
     * @return self
     */
    public function addRedirect($url, $delay = 0) {
        return $this->addAction([
            'type'  => 'redirect',
            'url'   => $url,
            'delay' => absint($delay)
        ], [], 'low');
    }
    public function updateText($selector, $content, $method = 'text') {
        return $this->addUpdate([
            'type'     => 'update',
            'selector' => $selector,
            'content'  => $content,
            'method'   => in_array($method, ['html', 'text', 'val']) ? $method : 'html'
        ]);
    }
    /**
     * Add update element action
     *
     * Accepts two call styles:
     *   addUpdate($selector, $content, $method = 'html')   — positional (external callers)
     *   addUpdate([ 'type' => 'update', ... ])             — pre-built array (used by updateText internally)
     *
     * @param string|array $selector  Element selector, or a pre-built action array
     * @param string       $content   New content (ignored when $selector is an array)
     * @param string       $method    Method: html | text | val  (ignored when $selector is an array)
     * @return self
     */
    public function addUpdate($selector, $content = '', $method = 'html') {
        if ( is_array( $selector ) ) {
            // Called with a pre-built action array (e.g. from updateText())
            return $this->addAction( $selector );
        }
        return $this->addAction([
            'type'     => 'update',
            'selector' => $selector,
            'content'  => $content,
            'method'   => in_array($method, ['html', 'text', 'val']) ? $method : 'html'
        ]);
    }

    /**
     * Add remove element action
     *
     * @param string $selector Element selector
     * @param bool   $animate  Whether to animate removal
     * @param int    $duration Animation duration
     * @return self
     */
    public function addRemove($selector, $animate = true, $duration = 300) {
        return $this->addAction([
            'type'     => 'remove',
            'selector' => $selector,
            'animate'  => (bool) $animate,
            'duration' => absint($duration)
        ]);
    }

    /**
     * Add append content action
     *
     * @param string $selector Element selector
     * @param string $content  Content to append
     * @param bool   $animate  Whether to animate
     * @return self
     */
    public function addAppend($selector, $content, $animate = true) {
        return $this->addAction([
            'type'     => 'append',
            'selector' => $selector,
            'content'  => $content,
            'animate'  => (bool) $animate
        ]);
    }

    /**
     * Add prepend content action
     *
     * @param string $selector Element selector
     * @param string $content  Content to prepend
     * @param bool   $animate  Whether to animate
     * @return self
     */
    public function addPrepend($selector, $content, $animate = true) {
        return $this->addAction([
            'type'     => 'prepend',
            'selector' => $selector,
            'content'  => $content,
            'animate'  => (bool) $animate
        ]);
    }

    /**
     * Add replace element action
     *
     * @param string $selector Element selector
     * @param string $content  Replacement content
     * @param bool   $animate  Whether to animate
     * @return self
     */
    public function addReplace($selector, $content, $animate = true) {
        return $this->addAction([
            'type'     => 'replace',
            'selector' => $selector,
            'content'  => $content,
            'animate'  => (bool) $animate
        ]);
    }

    /**
     * Empty element content
     *
     * @param string $selector Element selector
     * @param bool   $animate  Whether to animate
     * @return self
     */
    public function emptyElement($selector, $animate = false) {
        return $this->addAction([
            'type'     => 'empty',
            'selector' => $selector,
            'animate'  => (bool) $animate
        ]);
    }

    /**
     * Clone element
     *
     * @param string $selector Element selector
     * @param string $target   Where to insert clone (appendTo, prependTo, insertAfter, insertBefore)
     * @param string $targetSelector Target selector for insertion
     * @return self
     */
    public function cloneElement($selector, $target, $targetSelector) {
        return $this->addAction([
            'type'           => 'clone',
            'selector'       => $selector,
            'target'         => $target,
            'targetSelector' => $targetSelector
        ]);
    }

    /**
     * Insert content before element
     *
     * @param string $selector Element selector
     * @param string $content  Content to insert
     * @return self
     */
    public function insertBefore($selector, $content) {
        return $this->addAction([
            'type'     => 'insertBefore',
            'selector' => $selector,
            'content'  => $content
        ]);
    }

    /**
     * Insert content after element
     *
     * @param string $selector Element selector
     * @param string $content  Content to insert
     * @return self
     */
    public function insertAfter($selector, $content) {
        return $this->addAction([
            'type'     => 'insertAfter',
            'selector' => $selector,
            'content'  => $content
        ]);
    }

    // ==================== Class Manipulation Actions ====================

    /**
     * Add CSS class to element
     *
     * @param string $selector  Element selector
     * @param string $className Class name to add
     * @return self
     */
    public function addClass($selector, $className) {
        return $this->addAction([
            'type'      => 'addClass',
            'selector'  => $selector,
            'className' => $className
        ]);
    }
        /**
     * Add CSS class to element
     *
     * @param string $selector  Element selector
     * @param string $className Class name to add
     * @return self
     */
    public function updateClass($selector, $className) {
        return $this->addAction([
            'type'      => 'updateClass',
            'selector'  => $selector,
            'className' => $className
        ]);
    }
    /**
     * Remove CSS class from element
     *
     * @param string $selector  Element selector
     * @param string $className Class name to remove
     * @return self
     */
    public function removeClass($selector, $className) {
        return $this->addAction([
            'type'      => 'removeClass',
            'selector'  => $selector,
            'className' => $className
        ]);
    }

    /**
     * Toggle CSS class on element
     *
     * @param string $selector  Element selector
     * @param string $className Class name to toggle
     * @return self
     */
    public function toggleClass($selector, $className) {
        return $this->addAction([
            'type'      => 'toggleClass',
            'selector'  => $selector,
            'className' => $className
        ]);
    }

    // ==================== Attribute Manipulation Actions ====================

    /**
     * Update element attribute
     *
     * @param string $selector  Element selector
     * @param string $attribute Attribute name
     * @param mixed  $value     Attribute value (null to remove)
     * @return self
     */
    public function updateAttribute($selector, $attribute, $value = null) {
        return $this->addAction([
            'type'      => 'updateAttribute',
            'selector'  => $selector,
            'attribute' => $attribute,
            'value'     => $value
        ]);
    }

    /**
     * Remove element attribute
     *
     * @param string $selector  Element selector
     * @param string $attribute Attribute name
     * @return self
     */
    public function removeAttribute($selector, $attribute) {
        return $this->addAction([
            'type'      => 'removeAttribute',
            'selector'  => $selector,
            'attribute' => $attribute
        ]);
    }

    /**
     * Update data attribute
     *
     * @param string $selector Element selector
     * @param string $key      Data key
     * @param mixed  $value    Data value
     * @return self
     */
    public function updateData($selector, $key, $value) {
        return $this->addAction([
            'type'     => 'updateData',
            'selector' => $selector,
            'key'      => $key,
            'value'    => $value
        ]);
    }

    // ==================== Visibility Manipulation Actions ====================

    /**
     * Show element
     *
     * @param string $selector Element selector
     * @param int    $duration Animation duration
     * @return self
     */
    public function showElement($selector, $duration = 0) {
        return $this->addAction([
            'type'     => 'show',
            'selector' => $selector,
            'duration' => absint($duration)
        ]);
    }

    /**
     * Hide element
     *
     * @param string $selector Element selector
     * @param int    $duration Animation duration
     * @return self
     */
    public function hideElement($selector, $duration = 0) {
        return $this->addAction([
            'type'     => 'hide',
            'selector' => $selector,
            'duration' => absint($duration)
        ]);
    }

    /**
     * Toggle element visibility
     *
     * @param string $selector Element selector
     * @param int    $duration Animation duration
     * @return self
     */
    public function toggleElement($selector, $duration = 0) {
        return $this->addAction([
            'type'     => 'toggle',
            'selector' => $selector,
            'duration' => absint($duration)
        ]);
    }

    /**
     * Fade in element
     *
     * @param string $selector Element selector
     * @param int    $duration Animation duration
     * @param string $easing   Easing function
     * @return self
     */
    public function fadeIn($selector, $duration = 400, $easing = 'swing') {
        return $this->addAction([
            'type'     => 'fadeIn',
            'selector' => $selector,
            'duration' => absint($duration),
            'easing'   => $easing
        ]);
    }

    /**
     * Fade out element
     *
     * @param string $selector Element selector
     * @param int    $duration Animation duration
     * @param string $easing   Easing function
     * @return self
     */
    public function fadeOut($selector, $duration = 400, $easing = 'swing') {
        return $this->addAction([
            'type'     => 'fadeOut',
            'selector' => $selector,
            'duration' => absint($duration),
            'easing'   => $easing
        ]);
    }

    /**
     * Toggle fade element
     *
     * @param string $selector Element selector
     * @param int    $duration Animation duration
     * @return self
     */
    public function fadeToggle($selector, $duration = 400) {
        return $this->addAction([
            'type'     => 'fadeToggle',
            'selector' => $selector,
            'duration' => absint($duration)
        ]);
    }

    /**
     * Slide up element
     *
     * @param string $selector Element selector
     * @param int    $duration Animation duration
     * @return self
     */
    public function slideUp($selector, $duration = 400) {
        return $this->addAction([
            'type'     => 'slideUp',
            'selector' => $selector,
            'duration' => absint($duration)
        ]);
    }

    /**
     * Slide down element
     *
     * @param string $selector Element selector
     * @param int    $duration Animation duration
     * @return self
     */
    public function slideDown($selector, $duration = 400) {
        return $this->addAction([
            'type'     => 'slideDown',
            'selector' => $selector,
            'duration' => absint($duration)
        ]);
    }

    /**
     * Toggle slide element
     *
     * @param string $selector Element selector
     * @param int    $duration Animation duration
     * @return self
     */
    public function slideToggle($selector, $duration = 400) {
        return $this->addAction([
            'type'     => 'slideToggle',
            'selector' => $selector,
            'duration' => absint($duration)
        ]);
    }

    // ==================== CSS Manipulation Actions ====================

    /**
     * Update CSS properties
     *
     * @param string $selector   Element selector
     * @param array  $properties CSS properties as key-value pairs
     * @return self
     */
    public function updateCss($selector, array $properties) {
        return $this->addAction([
            'type'       => 'css',
            'selector'   => $selector,
            'properties' => $properties
        ]);
    }

    /**
     * Animate element
     *
     * @param string $selector   Element selector
     * @param array  $properties Animation properties
     * @param int    $duration   Duration in milliseconds
     * @param string $easing     Easing function
     * @return self
     */
    public function animate($selector, array $properties, $duration = 400, $easing = 'swing') {
        return $this->addAction([
            'type'       => 'animate',
            'selector'   => $selector,
            'properties' => $properties,
            'duration'   => absint($duration),
            'easing'     => $easing
        ]);
    }

    // ==================== Event Actions ====================

    /**
     * Trigger jQuery event
     *
     * @param string $event    Event name
     * @param string $selector Element selector (optional)
     * @param mixed  $data     Event data (optional)
     * @return self
     */
    public function triggerEvent($event, $selector = null, $data = null) {
        $action = [
            'type'  => 'trigger',
            'event' => $event
        ];

        if ($selector) {
            $action['selector'] = $selector;
        }

        if ($data !== null) {
            $action['data'] = $data;
        }

        return $this->addAction($action);
    }

    /**
     * Attach event handler
     *
     * @param string $selector Element selector
     * @param string $event    Event name
     * @param string $handler  Handler function name or code
     * @return self
     */
    public function attachEvent($selector, $event, $handler) {
        return $this->addAction([
            'type'     => 'on',
            'selector' => $selector,
            'event'    => $event,
            'handler'  => $handler
        ]);
    }

    /**
     * Detach event handler
     *
     * @param string $selector Element selector
     * @param string $event    Event name
     * @return self
     */
    public function detachEvent($selector, $event = null) {
        $action = [
            'type'     => 'off',
            'selector' => $selector
        ];

        if ($event) {
            $action['event'] = $event;
        }

        return $this->addAction($action);
    }

    // ==================== Component Actions ====================

    /**
     * Add modal operation action
     *
     * @param string $operation Operation (open, close, toggle)
     * @param string $modalId   Modal ID
     * @param array  $options   Additional options
     * @return self
     */
    public function modalAction($operation, $modalId = 'file-details-modal', $options = []) {
        return $this->addAction([
            'type'      => 'modal',
            'operation' => $operation,
            'modalId'   => $modalId,
            'options'   => $options
        ]);
    }

    /**
     * Open modal
     *
     * @param string $modalId Modal ID
     * @param array  $options Additional options
     * @return self
     */
    public function openModal($modalId = 'file-details-modal', $options = []) {
        return $this->modalAction('open', $modalId, $options);
    }

    /**
     * Close modal
     *
     * @param string $modalId Modal ID
     * @return self
     */
    public function closeModal($modalId = 'file-details-modal') {
        return $this->modalAction('close', $modalId);
    }
    /**
    * Open modal with content
    *
    * This is a convenience method that sets modal content and opens it in one call.
    * It handles the common pattern of: set content → open modal
    *
    * @param string $modalId Modal ID
    * @param string $content HTML content to display
    * @param string $target  Target section (body, header, footer, title) - default: 'body'
    * @param array  $options Additional options for the modal
    * @return self
    *
    * @example
    * // Basic usage - set content in body and open modal
    * $response->openModalWithContent('file-details-modal', $html_content);
    *
    * // Set content in header
    * $response->openModalWithContent('file-details-modal', '<h2>My Title</h2>', 'header');
    *
    * // With additional options
    * $response->openModalWithContent('file-details-modal', $html, 'body', ['data' => ['fileId' => 123]]);
    */
   public function openModalWithContent($modalId, $content, $target = 'body', $options = []) {
       // First, set the content in the specified target
       $this->addAction([
           'type' => 'modal',
           'operation' => 'setContent',
           'modalId' => $modalId,
           'content' => $content,
           'target' => $target
       ]);

       // Then, open the modal with any additional options
       return $this->openModal($modalId, $options);
   }

   /**
    * Set modal content without opening (add this to AjaxResponseBuilder class)
    *
    * Use this when you want to update modal content without opening it,
    * or when you want more control over the opening timing.
    *
    * @param string $modalId Modal ID
    * @param string $content HTML content to display
    * @param string $target  Target section (body, header, footer, title) - default: 'body'
    * @return self
    *
    * @example
    * // Just update the body content
    * $response->setModalContent('file-details-modal', $html_content);
    *
    * // Update the title
    * $response->setModalContent('file-details-modal', 'New Title', 'title');
    */
   public function setModalContent($modalId, $content, $target = 'body') {
       return $this->addAction([
           'type' => 'modal',
           'operation' => 'setContent',
           'modalId' => $modalId,
           'content' => $content,
           'target' => $target
       ]);
   }

    public function setModalTitle($modalId, $content, $target = 'title') {
       return $this->addAction([
           'type' => 'modal',
           'operation' => 'setContent',
           'modalId' => $modalId,
           'content' => $content,
           'target' => $target
       ]);
   }
    /**
     * Add widget operation action
     *
     * @param string $operation Operation (refresh, update, remove)
     * @param string $widgetId  Widget ID
     * @param string $content   Content for update operation
     * @return self
     */
    public function widgetAction($operation, $widgetId, $content = null) {
        $action = [
            'type'      => 'widget',
            'operation' => $operation,
            'widgetId'  => $widgetId
        ];

        if ($content !== null) {
            $action['content'] = $content;
        }

        return $this->addAction($action);
    }

    /**
     * Refresh widget
     *
     * @param string $widgetId Widget ID
     * @return self
     */
    public function refreshWidget($widgetId) {
        return $this->widgetAction('refresh', $widgetId);
    }

    /**
     * Update widget content
     *
     * @param string $widgetId Widget ID
     * @param string $content  New content
     * @return self
     */
    public function updateWidget($widgetId, $content) {
        return $this->widgetAction('update', $widgetId, $content);
    }

    /**
     * Add form operation action
     *
     * @param string       $operation Operation (reset, populate, submit, validate, enable, disable)
     * @param string       $formId    Form ID
     * @param array|string $data      Data for populate operation
     * @return self
     */
    public function formAction($operation, $formId, $data = []) {
        $action = [
            'type'      => 'form',
            'operation' => $operation,
            'formId'    => $formId
        ];

        if (!empty($data) && is_array($data)) {
            $action['data'] = $data;
        }

        return $this->addAction($action);
    }

    /**
     * Reset form
     *
     * @param string $formId Form ID
     * @return self
     */
    public function resetForm($formId) {
        return $this->formAction('reset', $formId);
    }

    /**
     * Populate form with data
     *
     * @param string       $formId Form ID
     * @param array|string $data   Form data
     * @return self
     */
    public function populateForm($formId, $data) {
        if (is_array($data)) {
            return $this->formAction('populate', $formId, $data);
        }
        return $this->formAction('populate', $formId, []);
    }

    /**
     * Enable form
     *
     * @param string $formId Form ID
     * @return self
     */
    public function enableForm($formId) {
        return $this->formAction('enable', $formId);
    }

    /**
     * Disable form
     *
     * @param string $formId Form ID
     * @return self
     */
    public function disableForm($formId) {
        return $this->formAction('disable', $formId);
    }

    /**
     * Validate form
     *
     * @param string $formId Form ID
     * @return self
     */
    public function validateForm($formId) {
        return $this->formAction('validate', $formId);
    }

    /**
     * Add DataTable operation action
     *
     * @param string $operation    Operation (reload, refresh, draw, clear)
     * @param string $tableId      Table ID
     * @param bool   $resetPaging  Whether to reset paging
     * @return self
     */
    public function dataTableAction($operation, $tableId, $resetPaging = true) {
        return $this->addAction([
            'type'        => 'datatable',
            'operation'   => $operation,
            'tableId'     => $tableId,
            'resetPaging' => (bool) $resetPaging
        ]);
    }

    /**
     * Reload DataTable
     *
     * @param string $tableId     Table ID
     * @param bool   $resetPaging Whether to reset paging
     * @return self
     */
    public function reloadDataTable($tableId, $resetPaging = true) {
        return $this->dataTableAction('reload', $tableId, $resetPaging);
    }

    // ==================== Advanced Actions ====================

    /**
     * Execute JavaScript code
     *
     * @param string $code JavaScript code to execute
     * @return self
     */
    public function executeScript($code) {
        return $this->addAction([
            'type' => 'script',
            'code' => $code
        ]);
    }

    /**
     * Add dynamic CSS styles
     *
     * @param string $css CSS code
     * @param string $id  Style element ID
     * @return self
     */
    public function addStyles($css, $id = null) {
        $action = [
            'type' => 'style',
            'css'  => $css
        ];

        if ($id) {
            $action['id'] = $id;
        }

        return $this->addAction($action);
    }

    /**
     * Scroll to element or position
     *
     * @param string|int $target   Element selector or scroll position
     * @param int        $offset   Offset from target (for element)
     * @param int        $duration Scroll duration
     * @return self
     */
    public function scrollTo($target, $offset = 0, $duration = 500) {
        $action = [
            'type'     => 'scroll',
            'duration' => absint($duration)
        ];

        if (is_numeric($target)) {
            $action['position'] = absint($target);
        } else {
            $action['selector'] = $target;
            $action['offset'] = intval($offset);
        }

        return $this->addAction($action);
    }

    /**
     * Focus on element
     *
     * @param string $selector Element selector
     * @param bool   $select   Whether to select text (for inputs)
     * @param int    $delay    Delay before focusing
     * @return self
     */
    public function focusElement($selector, $select = false, $delay = 0) {
        return $this->addAction([
            'type'     => 'focus',
            'selector' => $selector,
            'select'   => (bool) $select,
            'delay'    => absint($delay)
        ]);
    }

    /**
     * Trigger file download
     *
     * @param string $url      Download URL
     * @param string $filename Filename (optional)
     * @return self
     */
    public function download($url, $filename = null) {
        $safe_url = ( strncmp( $url, 'data:', 5 ) === 0 ) ? $url : esc_url( $url );

        $action = [
            'type' => 'download',
            'url'  => $safe_url,
        ];

        if ($filename) {
            $action['filename'] = sanitize_file_name($filename);
        }

        return $this->addAction($action);
    }

    // ==================== Shorthand Methods ====================

    /**
     * Create success response with message and data
     *
     * @param string $message Success message
     * @param array  $data    Additional data
     * @return self
     */
    public function success($message = '', $data = []) {
        $this->response['success'] = true;

        if (!empty($message)) {
            $this->response['message'] = sanitize_text_field($message);
        }

        if (!empty($data) && is_array($data)) {
            $this->response['data'] = array_merge($this->response['data'], $data);
        }

        return $this;
    }

    /**
     * Create error response
     *
     * @param string       $message Error message
     * @param string       $code    Error code
     * @param array|string $data    Additional data
     * @return self
     */
    public function error($message, $code = 'error', $data = []) {
        $this->response['success'] = false;
        $this->response['message'] = sanitize_text_field($message);
        $this->response['code'] = sanitize_key($code);

        if (!empty($data)) {
            if (is_array($data)) {
                $this->response['data'] = array_merge($this->response['data'], $data);
            }
        }

        return $this;
    }

    // ==================== Common Error Responses ====================

    /**
     * Validation error response
     *
     * @param string|array $errors Validation errors
     * @return self
     */
    public function validationError($errors) {
        $message = is_array($errors)
            ? __('Validation failed. Please check your input.', 'ultraguard-security-suite')
            : $errors;

        $this->response['success'] = false;
        $this->response['message'] = sanitize_text_field($message);
        $this->response['code'] = 'validation_error';

        if (is_array($errors)) {
            $this->response['data']['errors'] = $errors;
        }

        return $this;
    }

    /**
     * Permission error response
     *
     * @param string $message Optional custom message
     * @return self
     */
    public function permissionError($message = '') {
        if (empty($message)) {
            $message = __('You do not have permission to perform this action.', 'ultraguard-security-suite');
        }

        return $this->error($message, 'permission_denied');
    }

    /**
     * Nonce error response
     *
     * @param string $message Optional custom message
     * @return self
     */
    public function nonceError($message = '') {
        if (empty($message)) {
            $message = __('Security verification failed. Please refresh and try again.', 'ultraguard-security-suite');
        }

        return $this->error($message, 'nonce_invalid');
    }

    /**
     * Not found error response
     *
     * @param string $message Optional custom message
     * @return self
     */
    public function notFoundError($message = '') {
        if (empty($message)) {
            $message = __('The requested resource was not found.', 'ultraguard-security-suite');
        }

        return $this->error($message, 'not_found');
    }

    /**
     * Database error response
     *
     * @param string $message Optional custom message
     * @return self
     */
    public function databaseError($message = '') {
        if (empty($message)) {
            $message = __('A database error occurred. Please try again.', 'ultraguard-security-suite');
        }

        return $this->error($message, 'database_error');
    }

    /**
     * Rate limit error
     *
     * @param int $retryAfter Seconds until retry allowed
     * @return self
     */
    public function rateLimitError($retryAfter = 60) {
        $this->response['data']['retry_after'] = absint($retryAfter);

        return $this->error(
            sprintf(
                /* translators: Placeholder values are inserted into this string. */
                __('Too many requests. Please try again in %d seconds.', 'ultraguard-security-suite'),
                $retryAfter
            ),
            'rate_limit_exceeded'
        );
    }

    // ==================== Debug Methods ====================

    /**
     * Add debug information
     *
     * @param string $message Debug message
     * @param mixed  $data    Debug data
     * @return self
     */
    public function addDebug($message, $data = null) {
        if ($this->debug_mode) {
            $debug_entry = [
                'message'   => $message,
                'timestamp' => current_time('mysql')
            ];

            if ($data !== null) {
                $debug_entry['data'] = $data;
            }

            $this->response['debug'][] = $debug_entry;
        }

        return $this;
    }

    /**
     * Add backtrace to debug
     *
     * @return self
     */
    public function addBacktrace() {
        if ($this->debug_mode) {
            $this->response['debug']['backtrace'] = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace -- intentional debug-only trace in builder debug mode.
        }

        return $this;
    }

    // ==================== Output Methods ====================

    /**
     * Get response as array
     *
     * @param bool $include_debug Whether to include debug data
     * @return array
     */
    public function toArray($include_debug = null) {
        $response = $this->response;
        $response = $this->injectDomSignature($response);

        // Sort actions by priority if any have priorities set
        $has_priorities = false;
        foreach ($response['actions'] as $action) {
            if (isset($action['priority'])) {
                $has_priorities = true;
                break;
            }
        }

        if ($has_priorities) {
            usort($response['actions'], function($a, $b) {
                $priorityA = isset($a['priority']) ? $a['priority'] : 50;
                $priorityB = isset($b['priority']) ? $b['priority'] : 50;
                return $priorityA - $priorityB;
            });

            // Remove priority from output (internal use only)
            foreach ($response['actions'] as &$action) {
                unset($action['priority']);
            }
        }

        // Remove debug in production unless explicitly requested
        if ($include_debug === false || (!$this->debug_mode && $include_debug !== true)) {
            unset($response['debug']);
        }

        // Clean empty arrays
        if (empty($response['actions'])) {
            unset($response['actions']);
        }

        if (empty($response['data'])) {
            unset($response['data']);
        }

        if (empty($response['debug'])) {
            unset($response['debug']);
        }

        // Remove null code
        if ($response['code'] === null) {
            unset($response['code']);
        }

        return $response;
    }

    /**
     * Send JSON response and exit
     *
     * @param int  $status_code HTTP status code
     * @param bool $include_debug Whether to include debug data
     * @return void
     */
    public function send($status_code = null, $include_debug = null) {
        // Set appropriate HTTP status code
        if ($status_code === null) {
            $status_code = $this->response['success'] ? 200 : 400;
        }

        status_header($status_code);

        // Use WordPress JSON response function
        wp_send_json($this->toArray($include_debug), $status_code);
    }

    /**
     * Send success response and exit
     *
     * @return void
     */
    public function sendSuccess() {
        $this->response['success'] = true;
        $this->send(200);
    }

    /**
     * Send error response and exit
     *
     * @param int $status_code HTTP status code
     * @return void
     */
    public function sendError($status_code = 400) {
        $this->response['success'] = false;
        $this->send($status_code);
    }

    /**
     * Get JSON string
     *
     * @param bool $include_debug Whether to include debug data
     * @return string
     */
    public function toJson($include_debug = null) {
        return wp_json_encode($this->toArray($include_debug));
    }

    // ==================== Validation Methods ====================

    /**
     * Validate nonce
     *
     * @param string $nonce  Nonce value
     * @param string $action Nonce action
     * @return bool
     */
    public function validateNonce($nonce, $action = -1) {
        if (!wp_verify_nonce($nonce, $action)) {
            $this->nonceError();
            return false;
        }
        return true;
    }

    /**
     * Validate capability
     *
     * @param string $capability Required capability
     * @return bool
     */
    public function validateCapability($capability) {
        $has_capability = 'manage_options' === $capability
            ? \UltraguardPro\ultraguard_current_user_can_manage()
            : current_user_can($capability);

        if (!$has_capability) {
            $this->permissionError();
            return false;
        }
        return true;
    }

    /**
     * Validate and sanitize data
     *
     * @param array|mixed $data  Data to validate
     * @param array       $rules Validation rules
     * @return bool
     */
    public function validate($data, $rules) {
        if (!is_array($data)) {
            $this->validationError('Invalid data format');
            return false;
        }

        if (!is_array($rules)) {
            return true;
        }

        $errors = [];

        foreach ($rules as $field => $field_rules) {
            $value = isset($data[$field]) ? $data[$field] : null;

            if (is_string($field_rules)) {
                $field_rules = explode('|', $field_rules);
            }

            foreach ($field_rules as $rule) {
                $rule_parts = explode(':', $rule);
                $rule_name = $rule_parts[0];
                $rule_param = isset($rule_parts[1]) ? $rule_parts[1] : null;

                switch ($rule_name) {
                    case 'required':
                        if (empty($value)) {
                            /* translators: %1$s: field name */
                            $errors[$field][] = 
                            /* translators: %1$s: text */
                            sprintf( __( '%1$s is required.', 'ultraguard-security-suite' ), $field );
                        }
                        break;

                    case 'email':
                        if (!empty($value) && !is_email($value)) {
                            /* translators: %1$s: field name */
                            $errors[$field][] = 
                            /* translators: %1$s: text */
                            sprintf( __( '%1$s must be a valid email.', 'ultraguard-security-suite' ), $field );
                        }
                        break;

                    case 'url':
                        if (!empty($value) && !filter_var($value, FILTER_VALIDATE_URL)) {
                            /* translators: %1$s: field name */
                            $errors[$field][] = 
                            /* translators: %1$s: text */
                            sprintf( __( '%1$s must be a valid URL.', 'ultraguard-security-suite' ), $field );
                        }
                        break;

                    case 'numeric':
                        if (!empty($value) && !is_numeric($value)) {
                            /* translators: %1$s: field name */
                            $errors[$field][] = 
                            /* translators: %1$s: text */
                            sprintf( __( '%1$s must be numeric.', 'ultraguard-security-suite' ), $field );
                        }
                        break;

                    case 'min':
                        if (!empty($value) && is_numeric($value) && $value < $rule_param) {
                            /* translators: %1$s: field name, %2$s: minimum value */
                            $errors[$field][] = 
                            /* translators: %1$s: text, %2$s: text */
                            sprintf( __( '%1$s must be at least %2$s.', 'ultraguard-security-suite' ), $field, $rule_param );
                        }
                        break;

                    case 'max':
                        if (!empty($value) && is_numeric($value) && $value > $rule_param) {
                            /* translators: %1$s: field name, %2$s: maximum value */
                            $errors[$field][] = 
                            /* translators: %1$s: text, %2$s: text */
                            sprintf( __( '%1$s must be at most %2$s.', 'ultraguard-security-suite' ), $field, $rule_param );
                        }
                        break;
                }
            }
        }

        if (!empty($errors)) {
            $this->validationError($errors);
            return false;
        }

        return true;
    }

    // ==================== Static Factory Methods ====================

    /**
     * Create a new instance
     *
     * @return self
     */
    public static function make() {
        return new AjaxResponseManager();
    }

    /**
     * Inject the normalized DOM signature into the response payload.
     *
     * @param  array $response
     * @return array
     */
    private function injectDomSignature(array $response) {
        $signature = $this->buildDomSignature();

        if (empty($signature)) {
            return $response;
        }

        if (empty($response['data']) || !is_array($response['data'])) {
            $response['data'] = [];
        }

        $response['data']['ui_signature'] = $signature;

        return $response;
    }

    /**
     * Build a best-effort DOM signature from the request and response.
     *
     * @return array
     */
    private function buildDomSignature() {
        $signature = $this->sanitizeDomSignature($this->dom_signature);
        $action    = sanitize_key( wp_unslash( (string) ( $_REQUEST['action'] ?? '' ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only request metadata for DOM signature generation.

        if (!empty($action) && empty($signature['action'])) {
            $signature['action'] = $action;
        }

        if (!empty($action) && empty($signature['module'])) {
            $signature['module'] = $this->inferModuleFromAction($action);
        }

        if (!isset($signature['status'])) {
            $signature['status'] = !empty($this->response['success']) ? 'success' : 'error';
        }

        if (!isset($signature['code']) && !empty($this->response['code'])) {
            $signature['code'] = sanitize_key((string) $this->response['code']);
        }

        if (!isset($signature['message']) && !empty($this->response['message'])) {
            $signature['message'] = sanitize_text_field((string) $this->response['message']);
        }

        $ids = $this->extractRequestIds();
        if (!empty($ids)) {
            $signature['ids'] = $ids;
        }

        $modalId = sanitize_key( wp_unslash( (string) ( $_REQUEST['modal_id'] ?? '' ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only request metadata for DOM signature generation.
        if (!empty($modalId)) {
            $signature['modal_id'] = $modalId;
        }

        if (empty($signature['timestamp'])) {
            $signature['timestamp'] = time();
        }

        return array_filter(
            $signature,
            static function ($value) {
                return !($value === null || $value === '' || $value === []);
            }
        );
    }

    /**
     * Sanitize arbitrary DOM signature data.
     *
     * @param  array $signature
     * @return array
     */
    private function sanitizeDomSignature(array $signature) {
        $clean = [];

        foreach ($signature as $key => $value) {
            $safeKey = sanitize_key((string) $key);
            if ($safeKey === '') {
                continue;
            }

            if (is_array($value)) {
                $nested = [];
                foreach ($value as $nestedKey => $nestedValue) {
                    if (is_scalar($nestedValue) || $nestedValue === null) {
                        $nested[sanitize_key((string) $nestedKey)] = is_numeric($nestedValue)
                            ? $nestedValue + 0
                            : sanitize_text_field((string) $nestedValue);
                    }
                }
                $clean[$safeKey] = $nested;
                continue;
            }

            if (is_bool($value) || is_numeric($value)) {
                $clean[$safeKey] = $value;
                continue;
            }

            if (is_scalar($value) && $value !== '') {
                $clean[$safeKey] = sanitize_text_field((string) $value);
            }
        }

        return $clean;
    }

    /**
     * Infer module slug from a standard UltraGuard AJAX action name.
     *
     * @param  string $action
     * @return string
     */
    private function inferModuleFromAction($action) {
        $action = sanitize_key((string) $action);

        if ($action === '') {
            return '';
        }

        if (strpos($action, 'ultraguard_') === 0) {
            $action = substr($action, 11);
        }

        $prefixMap = [
            'deactivation_'       => 'onboarding',
            'get_setting'         => 'settings',
            'update_setting'      => 'settings',
            'save_settings'       => 'settings',
            'save_module_settings'=> 'settings',
            'save_consolidated_settings' => 'settings',
            'export_all_settings' => 'settings',
            'reset_all_settings'  => 'settings',
            'import_settings'     => 'settings',
            'bulk_update_settings'=> 'settings',
            'validate_settings'   => 'settings',
            'rt_filechecker_'     => 'filechecker',
            'upgrade_manager_'    => 'upgrade_manager',
            'server_intelligence_' => 'server_intelligence',
            'security_headers_'   => 'security_headers',
            'traffic_monitor_'    => 'traffic_monitor',
            'reputation_monitor_' => 'reputation_monitor',
            'database_scanner_'   => 'database_scanner',
            'login_protect_'      => 'login_protect',
            'ip_intelligence_'    => 'ip_intelligence',
            'filechecker_'        => 'filechecker',
            'notifications_'      => 'notifications',
            'notification_'       => 'notifications',
            'compliance_'         => 'compliance_reports',
            'upgrade_'            => 'upgrade_manager',
            'traffic_'            => 'traffic_monitor',
            'reputation_'         => 'reputation_monitor',
            'db_scanner_'         => 'database_scanner',
            'db_scan_'            => 'database_scanner',
            'db_'                 => 'database_scanner',
            'api_'                => 'api_security',
            'audit_'              => 'audit_log',
            'notif_'              => 'notifications',
            'headers_'            => 'security_headers',
            'ip_intel_'           => 'ip_intelligence',
            'fc_'                 => 'filechecker',
            'll_'                 => 'loginlimiter',
            'si_'                 => 'server_intelligence',
            '2fa_'                => 'authenticator',
            'two_factor_'         => 'authenticator',
            'passkeys_'           => 'authenticator',
            'rt_antivirus_'       => 'antivirus',
            'rt_file_scanner_'    => 'antivirus',
            'rt_firewall_'        => 'firewall',
            'rt_htaccess_'        => 'htaccess',
            'rt_login_'           => 'loginlimiter',
            'rt_db_scan_'         => 'database_scanner',
            'rt_vuln_scan_'       => 'vulnerability',
            'antivirus_'          => 'antivirus',
            'firewall_'           => 'firewall',
            'hardening_'          => 'hardening',
            'htaccess_'           => 'htaccess',
            'dashboard_'          => 'dashboard',
            'loginlimiter_'       => 'loginlimiter',
            'login_'              => 'login_protect',
            'onboarding_'         => 'onboarding',
            'auto_updater_'       => 'auto_updater',
            'uptime_'             => 'uptime_monitor',
            'vulnerability_'      => 'vulnerability',
            'vuln_'               => 'vulnerability',
            'woo_'                => 'woo_security',
            'module_'             => 'dashboard',
        ];

        foreach ($prefixMap as $prefix => $module) {
            if (strpos($action, $prefix) === 0) {
                return $module;
            }
        }

        if (preg_match('/^save_([a-z0-9_]+)_settings$/', $action, $matches)) {
            $settingsModule = $matches[1];
            $settingsMap = [
                'antivirus'         => 'antivirus',
                'api_security'      => 'api_security',
                'auto_updater'      => 'auto_updater',
                'compliance_reports'=> 'compliance_reports',
                'db_scanner'        => 'database_scanner',
                'firewall'          => 'firewall',
                'hardening'         => 'hardening',
                'htaccess'          => 'htaccess',
                'ip_intelligence'   => 'ip_intelligence',
                'login_protect'     => 'login_protect',
                'loginlimiter'      => 'loginlimiter',
                'notifications'     => 'notifications',
                'reputation_monitor'=> 'reputation_monitor',
                'security_headers'  => 'security_headers',
                'traffic_monitor'   => 'traffic_monitor',
                'two_factor'        => 'authenticator',
                'upgrade_manager'   => 'upgrade_manager',
                'uptime_monitor'    => 'uptime_monitor',
                'vulnerability'     => 'vulnerability',
                'woo_security'      => 'woo_security',
            ];

            if (isset($settingsMap[$settingsModule])) {
                return $settingsMap[$settingsModule];
            }
        }

        $parts = array_values(array_filter(explode('_', $action)));
        if (empty($parts)) {
            return '';
        }

        $map = [
            'fc'         => 'filechecker',
            'll'         => 'loginlimiter',
            'api'        => 'api_security',
            'audit'      => 'audit_log',
            'headers'    => 'security_headers',
            'notif'      => 'notifications',
            'upgrade'    => 'upgrade_manager',
            'uptime'     => 'uptime_monitor',
            'traffic'    => 'traffic_monitor',
            'reputation' => 'reputation_monitor',
            'ip'         => 'ip_intelligence',
            'db'         => 'database_scanner',
            'vuln'       => 'vulnerability',
        ];

        $module = $parts[0];

        return $map[$module] ?? $module;
    }

    /**
     * Extract common *_id values from the current request.
     *
     * @return array
     */
    private function extractRequestIds() {
        $ids = [];

        foreach ($_REQUEST as $key => $value) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only request metadata scan for DOM signature IDs.
            if (!is_scalar($value)) {
                continue;
            }

            $safeKey = sanitize_key((string) $key);
            if ($safeKey === '' || $safeKey === 'action' || $safeKey === 'nonce' || $safeKey === 'modal_id') {
                continue;
            }

            if ($safeKey === 'id' || substr($safeKey, -3) === '_id') {
                $ids[$safeKey] = is_numeric($value)
                    ? (int) $value
                    : sanitize_text_field((string) $value);
            }
        }

        return $ids;
    }

    /**
     * Create success response
     *
     * @param string       $message Success message
     * @param array|string $data    Additional data
     * @return self
     */
    public static function createSuccess($message = '', $data = []) {
        return self::make()->success($message, $data);
    }

    /**
     * Create error response
     *
     * @param string       $message Error message
     * @param string       $code    Error code
     * @param array|string $data    Additional data
     * @return self
     */
    public static function createError($message, $code = 'error', $data = []) {
        return self::make()->error($message, $code, $data);
    }
}

/**
 * Backward-compatible semantic alias for the shared AJAX response manager.
 *
 * Existing modules still call AjaxResponseBuilder::make(), but that factory now
 * returns this manager class so the whole plugin routes through one response
 * pipeline with uniform DOM signatures.
 */
class AjaxResponseManager extends AjaxResponseBuilder {}
