<?php
/**
 * REST API for WAWP Settings.
 * Handles CRUD operations for the React Admin Dashboard.
 *
 * @package automation-web-platform
 */

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

/**
 * Class WAWP_Rest_Settings_API.
 *
 * @package automation-web-platform
 */
class WAWP_Rest_Settings_API {
	use WAWP_Settings_Handler;
	use WAWP_Security_Trait;

	/**
	 * REST namespace.
	 *
	 * @var string
	 */
	private $namespace = 'wawp/v1';

	/**
	 * REST base route.
	 *
	 * @var string
	 */
	private $base = 'settings';

	/**
	 * Singleton instance.
	 *
	 * @var WAWP_Rest_Settings_API|null
	 */
	private static $instance = null;

	/**
	 * Get singleton instance.
	 *
	 * @return WAWP_Rest_Settings_API
	 */
	public static function get_instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * WAWP_Rest_Settings_API constructor.
	 */
	public function __construct() {
		if ( did_action( 'rest_api_init' ) ) {
			$this->register_routes();
		} else {
			add_action( 'rest_api_init', array( $this, 'register_routes' ) );
		}
		add_action( 'wp_ajax_wawp_fetch_section_data', array( $this, 'ajax_fetch_section_data' ) );
		add_filter( 'rest_authentication_errors', array( $this, 'bypass_public_endpoints_rest_cookie_errors' ), 99 );
	}

	/**
	 * Bypass REST API cookie check invalid nonce errors for public endpoints.
	 *
	 * @param mixed $errors Current errors.
	 * @return mixed
	 */
	public function bypass_public_endpoints_rest_cookie_errors( $errors ) {
		if ( is_wp_error( $errors ) && 'rest_cookie_invalid_nonce' === $errors->get_error_code() ) {
			$request_uri = $_SERVER['REQUEST_URI'] ?? '';
			if ( strpos( $request_uri, 'wawp/v1/otp-login' ) !== false
				|| strpos( $request_uri, 'wawp/v1/signup' ) !== false
				|| strpos( $request_uri, 'wawp/v1/checkout-otp' ) !== false
				|| strpos( $request_uri, 'wawp/v1/phone-bar' ) !== false ) {
				return null;
			}
		}
		return $errors;
	}

	/**
	 * Register REST routes.
	 */
	public function register_routes() {
		// Main Settings CRUD.
		register_rest_route(
			$this->namespace,
			'/' . $this->base,
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_settings' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
				array(
					'methods'             => WP_REST_Server::EDITABLE,
					'callback'            => array( $this, 'update_settings' ),
					'permission_callback' => array( $this, 'permissions_check' ),
					'args'                => array(
						'settings' => array(
							'type'        => 'object',
							'description' => 'Key-value pairs of settings to update.',
							'required'    => true,
						),
					),
				),
			)
		);

		// Account Management.
		register_rest_route(
			$this->namespace,
			'/accounts/(?P<type>firebase|smtp|meta|whatsapp_web)',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'list_accounts' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'save_account' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/accounts/whatsapp_web/ops',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_whatsapp_ops' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/accounts/meta/(?P<op>sync|webhook)',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_meta_operations' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/accounts/(?P<type>firebase|smtp|meta|whatsapp_web)/(?P<id>\d+)',
			array(
				array(
					'methods'             => WP_REST_Server::DELETABLE,
					'callback'            => array( $this, 'delete_account' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/accounts/(?P<type>firebase|smtp)/(?P<id>\d+)/toggle',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'toggle_account' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/accounts/(?P<type>firebase|smtp)/validate',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'validate_account' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/accounts/(?P<type>firebase|smtp)/test',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'test_account' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		// Notifications & Email Templates.
		register_rest_route(
			$this->namespace,
			'/notifications/test',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'test_notification' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/email-templates',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_email_templates' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'save_email_template' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/email-templates/(?P<id>\d+)',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_email_template' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
				array(
					'methods'             => WP_REST_Server::DELETABLE,
					'callback'            => array( $this, 'delete_email_template' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/email-templates/test',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'send_test_email_template' ),
				'permission_callback' => array( $this, 'check_rest_permissions' ),
			)
		);

		register_rest_route(
			$this->namespace,
			'/email-templates/(?P<op>[a-zA-Z0-9-_]+)',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_email_template_ops' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		// Users & Campaigns.
		register_rest_route(
			$this->namespace,
			'/users/message',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'send_user_message' ),
				'permission_callback' => array( $this, 'check_rest_permissions' ),
			)
		);

		register_rest_route(
			$this->namespace,
			'/campaigns',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_campaigns' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'save_campaign' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
				array(
					'methods'             => WP_REST_Server::DELETABLE,
					'callback'            => array( $this, 'delete_campaigns' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/campaigns/(?P<id>\d+)/toggle',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'toggle_campaign' ),
				'permission_callback' => array( $this, 'check_rest_permissions' ),
			)
		);

		register_rest_route(
			$this->namespace,
			'/campaigns/(?P<id>\d+)/rerun',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'rerun_campaign' ),
				'permission_callback' => array( $this, 'check_rest_permissions' ),
			)
		);

		register_rest_route(
			$this->namespace,
			'/campaigns/(?P<id>\d+)/approve-risky',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'approve_risky_campaign' ),
				'permission_callback' => array( $this, 'check_rest_permissions' ),
			)
		);

		register_rest_route(
			$this->namespace,
			'/campaigns/(?P<op>[a-zA-Z0-9-_]+)',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_campaign_ops' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		// System & Logs.
		register_rest_route(
			$this->namespace,
			'/system-info',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_system_info' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'refresh_system_info' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/system-info/(?P<op>[a-zA-Z0-9-_]+)',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_system_info_ops' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/activity-hub/(?P<op>[a-zA-Z0-9-_]+)',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_activity_hub_ops' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/logs/(?P<op>list|timeline|delete|resend|send)',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_log_ops' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		// Auth Services (OTP, Login, Signup).
		register_rest_route(
			$this->namespace,
			'/otp-login/(?P<op>[a-zA-Z0-9-_]+)',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_otp_login_ops' ),
					'permission_callback' => array( $this, 'public_permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/signup/(?P<op>[a-zA-Z0-9-_]+)',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_signup_ops' ),
					'permission_callback' => array( $this, 'public_permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/checkout-otp/(?P<op>[a-zA-Z0-9-_]+)',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_checkout_otp_ops' ),
					'permission_callback' => array( $this, 'public_permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/otp/(?P<op>request|verify|status|-token|-log)',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'handle_otp_ops' ),
				'permission_callback' => array( $this, 'public_permissions_check' ),
			)
		);

		// Chat Widget.
		register_rest_route(
			$this->namespace,
			'/chat-widget/track',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'track_chat_widget' ),
				'permission_callback' => array( $this, 'check_rest_permissions' ),
			)
		);

		register_rest_route(
			$this->namespace,
			'/chat-widget/(?P<op>[a-zA-Z0-9-_]+)',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_chat_widget_ops' ),
					'permission_callback' => array( $this, 'public_permissions_check' ),
				),
			)
		);

		// Entities & Tools.
		register_rest_route(
			$this->namespace,
			'/entities/search',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'search_entities' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/system/(?P<op>status|sync-users|repair|schedule-cron|migrate-signup|migrate-notifications|wizard-checks|import-email-templates|import-auto-notifications|install-updater)',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_system_ops' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/system/db/(?P<op>truncate|create|drop|repair)',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_db_ops' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/cart/sessions',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_cart_sessions' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/cart/(?P<op>clear|toggle-visibility)',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_cart_ops' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/connector/refresh',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'refresh_connector_status' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		// Temporary Admin Access Links CRUD.
		register_rest_route(
			$this->namespace,
			'/temp-access',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_temp_access_links' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'create_temp_access_link' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/temp-access/(?P<id>\d+)',
			array(
				array(
					'methods'             => WP_REST_Server::DELETABLE,
					'callback'            => array( $this, 'delete_temp_access_link' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/temp-access/(?P<id>\d+)/revoke',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'revoke_temp_access_link' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/temp-access/(?P<id>\d+)/regenerate',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'regenerate_temp_access_link' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/temp-access/(?P<id>\d+)/logs',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_temp_access_logs' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/temp-access/(?P<id>\d+)/restrictions',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'update_temp_access_restrictions' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/temp-access/(?P<id>\d+)/terminate',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'terminate_temp_access_session' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/(?P<section>[a-zA-Z0-9_-]+)',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_section_data' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/recaptcha/test',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'handle_recaptcha_test' ),
				'permission_callback' => array( $this, 'permissions_check' ),
			)
		);

		register_rest_route(
			$this->namespace,
			'/pages/create',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'handle_create_page' ),
				'permission_callback' => array( $this, 'permissions_check' ),
			)
		);

		register_rest_route(
			$this->namespace,
			'/flows/(?P<op>search|test)',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'handle_flow_ops' ),
				'permission_callback' => array( $this, 'permissions_check' ),
			)
		);

		register_rest_route(
			$this->namespace,
			'/phone-bar/(?P<op>send|verify|status|-token|-log|update-phone|dismiss)',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'handle_phone_bar_ops' ),
					'permission_callback' => 'is_user_logged_in',
				),
			)
		);

		register_rest_route(
			$this->namespace,
			'/' . $this->base . '/abandoned-cart/create-coupon',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'create_abandoned_cart_coupon' ),
					'permission_callback' => array( $this, 'permissions_check' ),
				),
			)
		);
	}

	/**
	 * Public permissions check.
	 *
	 * @return bool
	 */
	public function public_permissions_check() {
		return true;
	}

	/**
	 * Get section data for the React dashboard.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function get_section_data( $request ) {
		$section = $request->get_param( 'section' );
		$data    = WAWP_Enqueue_Scripts::prepare_dashboard_data( $section, false );

		if ( ! empty( $data['error'] ) ) {
			return new WP_Error( 'dashboard_data_error', $data['message'] ?? 'Error fetching section data', array( 'status' => 500 ) );
		}

		// Always include a fresh nonce to keep the session alive and unified.
		$data['nonce'] = wp_create_nonce( 'wawp_nonce' );

		return rest_ensure_response( $data );
	}

	/**
	 * AJAX handler for fetching section data.
	 */
	public function ajax_fetch_section_data() {
		$this->check_permissions( 'wawp_nonce', 'security' );
		$section_raw = filter_input( INPUT_POST, 'section', FILTER_SANITIZE_SPECIAL_CHARS );
		$section     = $section_raw ? sanitize_key( $section_raw ) : '';
		$data        = WAWP_Enqueue_Scripts::prepare_dashboard_data( $section, false );
		$this->send_success( '', $data );
	}

	/**
	 * Get the appropriate sender instance based on type.
	 *
	 * @param string $type Sender type.
	 * @return mixed Sender instance or null.
	 */
	private function get_sender( $type ) {
		if ( 'firebase' === $type && class_exists( 'WAWP_Firebase_Sender' ) ) {
			return WAWP_Firebase_Sender::get_instance();
		} elseif ( 'smtp' === $type && class_exists( 'WAWP_Email_Sender' ) ) {
			return WAWP_Email_Sender::get_instance();
		} elseif ( 'whatsapp_web' === $type && class_exists( 'WAWP_Senders' ) ) {
			return WAWP()->senders;
		} elseif ( 'meta' === $type && class_exists( 'WAWP_Meta_Sender' ) ) {
			return WAWP_Meta_Sender::get_instance();
		}

		return null;
	}

	/**
	 * List accounts for a specific sender.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function list_accounts( $request ) {
		$type   = $request->get_param( 'type' );
		$sender = $this->get_sender( $type );
		if ( ! $sender ) {
			return new WP_Error( 'invalid_type', 'Invalid account type', array( 'status' => 400 ) );
		}

		if ( 'whatsapp_web' === $type ) {
			wp_cache_delete( 'wawp_all_instances', 'wawp_instances' );
			delete_transient( 'wawp_online_instances' );
			$accounts = WAWP()->instance_manager->get_all_instances();
		} else {
			wp_cache_delete( 'wawp_smtp_accounts_list', 'wawp_database' );
			wp_cache_delete( 'wawp_smtp_active', 'wawp_database' );
			$accounts = method_exists( $sender, 'list_accounts' ) ? $sender->list_accounts() : array();
		}

		return rest_ensure_response(
			array(
				'success' => true,
				'data'    => $accounts,
			)
		);
	}

	/**
	 * Save/Update an account.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function save_account( $request ) {
		$type   = $request->get_param( 'type' );
		$sender = $this->get_sender( $type );
		if ( ! $sender ) {
			return new WP_Error( 'invalid_type', 'Invalid account type', array( 'status' => 400 ) );
		}

		if ( 'firebase' === $type ) {
			$name   = $request->get_param( 'account_name' );
			$config = $request->get_param( 'config' );
			$id     = $request->get_param( 'id' );
			$res_id = WAWP_Firebase_Sender::get_instance()->save_account( $name, $config, 1, $id );
			$res    = array(
				'success' => true,
				'id'      => $res_id,
				'message' => esc_html__( 'Account saved successfully.', 'automation-web-platform' ),
			);
		} elseif ( 'whatsapp_web' === $type ) {
			$id     = $request->get_param( 'id' );
			$config = $request->get_param( 'config' ) ? $request->get_param( 'config' ) : array();
			$data   = array(
				'name'         => $request->get_param( 'account_name' ),
				'instance_id'  => $config['instance_id'] ?? '',
				'access_token' => $config['access_token'] ?? '',
			);
			if ( ! empty( $id ) ) {
				$res = $sender->wawp_edit_instance( $id, $data );
			} else {
				$res = $sender->wawp_add_instance( $data );
			}
		} elseif ( 'meta' === $type ) {
			$res = $sender->handle_save_settings( $request->get_param( 'config' ) ? $request->get_param( 'config' ) : array() );
		} elseif ( 'smtp' === $type ) {
			$data = array(
				'id'           => $request->get_param( 'id' ),
				'account_name' => $request->get_param( 'account_name' ),
				'provider'     => $request->get_param( 'provider' ) ? $request->get_param( 'provider' ) : 'smtp',
				'config'       => $request->get_param( 'config' ) ? $request->get_param( 'config' ) : array(),
			);
			$res  = $sender->handle_save_account( $data );
		}

		return rest_ensure_response( $res );
	}

	/**
	 * Delete an account.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function delete_account( $request ) {
		$type   = $request->get_param( 'type' );
		$id     = $request->get_param( 'id' );
		$sender = $this->get_sender( $type );
		if ( ! $sender ) {
			return new WP_Error( 'invalid_type', 'Invalid account type', array( 'status' => 400 ) );
		}

		if ( 'whatsapp_web' === $type ) {
			$res = $sender->wawp_delete_instance( $id );
		} else {
			$res = $sender->handle_delete_account( $id );
		}

		return rest_ensure_response( $res );
	}

	/**
	 * Toggle account status.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function toggle_account( $request ) {
		$type   = $request->get_param( 'type' );
		$id     = $request->get_param( 'id' );
		$sender = $this->get_sender( $type );
		if ( ! $sender ) {
			return new WP_Error( 'invalid_type', 'Invalid account type', array( 'status' => 400 ) );
		}

		if ( 'firebase' === $type ) {
			$res = $sender->handle_toggle_account( $id );
		} else {
			$res = $sender->handle_toggle_active( $id, $request->get_param( 'active' ) );
		}

		return rest_ensure_response( $res );
	}

	/**
	 * Validate account credentials.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function validate_account( $request ) {
		$type   = $request->get_param( 'type' );
		$sender = $this->get_sender( $type );
		if ( ! $sender ) {
			return new WP_Error( 'invalid_type', 'Invalid account type', array( 'status' => 400 ) );
		}

		if ( 'firebase' === $type ) {
			$res = $sender->handle_validate_account( $request->get_param( 'id' ) );
		} elseif ( 'smtp' === $type ) {
			$config = $request->get_param( 'config' ) ? $request->get_param( 'config' ) : array();
			if ( ! empty( $config ) ) {
				$res = $sender->handle_test_connection( $config );
			} else {
				$res = $sender->handle_validate_account( $request->get_param( 'id' ), $request->get_param( 'validated' ) );
			}
		} else {
			$res = $sender->handle_validate_account( $request->get_param( 'id' ), $request->get_param( 'validated' ) );
		}

		return rest_ensure_response( $res );
	}

	/**
	 * Send test message.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function test_account( $request ) {
		$type   = $request->get_param( 'type' );
		$sender = $this->get_sender( $type );
		if ( ! $sender ) {
			return new WP_Error( 'invalid_type', 'Invalid account type', array( 'status' => 400 ) );
		}

		if ( 'firebase' === $type ) {
			$phone = $request->get_param( 'phone' ) ? $request->get_param( 'phone' ) : $request->get_param( 'to' );
			$res   = $sender->handle_send_test( $phone );
		} elseif ( 'smtp' === $type ) {
			$email = $request->get_param( 'email' ) ? $request->get_param( 'email' ) : ( $request->get_param( 'to' ) ? $request->get_param( 'to' ) : $request->get_param( 'test_email' ) );
			$res   = $sender->handle_send_test_email( $email );
		} else {
			$res = array(
				'success' => false,
				'message' => 'Operation not supported for this type',
			);
		}

		return rest_ensure_response( $res );
	}

	/**
	 * Handle test notification.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function test_notification( $request ) {
		if ( ! class_exists( 'WAWP_Flow_Builder' ) ) {
			return new WP_Error( 'not_found', 'Flow Builder class not found.', array( 'status' => 404 ) );
		}

		$params = $request->get_params();
		$res    = WAWP_Flow_Builder::get_instance()->send_test_notification( $params );

		return rest_ensure_response( $res );
	}

	/**
	 * Get notification statistics for AI assistant.
	 *
	 * @return WP_REST_Response Response object.
	 */
	public function get_notification_stats() {
		if ( ! class_exists( 'WAWP_Flow_Builder' ) ) {
			return rest_ensure_response(
				array(
					'success' => true,
					'data'    => array(
						'total'    => 0,
						'active'   => 0,
						'triggers' => array(),
					),
				)
			);
		}

		$settings = WAWP_Flow_Builder::get_instance()->get_settings();
		$total    = 0;
		$active   = 0;
		$triggers = array();

		if ( ! empty( $settings['configured_languages'] ) ) {
			foreach ( $settings['configured_languages'] as $lang_data ) {
				if ( empty( $lang_data['notifications'] ) ) {
					continue;
				}
				foreach ( $lang_data['notifications'] as $rule ) {
					++$total;
					if ( ! empty( $rule['enabled'] ) ) {
						++$active;
					}
					$tk = isset( $rule['trigger_key'] ) ? $rule['trigger_key'] : '';
					if ( $tk && ! in_array( $tk, $triggers, true ) ) {
						$triggers[] = $tk;
					}
				}
			}
		}

		return rest_ensure_response(
			array(
				'success' => true,
				'data'    => array(
					'total'    => $total,
					'active'   => $active,
					'inactive' => $total - $active,
					'triggers' => $triggers,
				),
			)
		);
	}

	/**
	 * Create a notification rule from the AI assistant.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function ai_create_notification( $request ) {
		if ( ! class_exists( 'WAWP_Flow_Builder' ) ) {
			return new WP_Error( 'not_found', 'Flow Builder class not found.', array( 'status' => 404 ) );
		}

		$params = $request->get_json_params();
		$rule   = $params['rule'] ?? array();

		if ( empty( $rule['trigger_key'] ) ) {
			return new WP_Error( 'missing_trigger', 'trigger_key is required.', array( 'status' => 400 ) );
		}

		// Get current settings.
		$fb       = WAWP_Flow_Builder::get_instance();
		$settings = $fb->get_settings();
		$main     = $settings['main_language_code'] ?? 'en_US';

		// Build the notification rule with defaults.
		$new_rule = array(
			'id'                          => 'rule_' . time() . '_' . wp_generate_password( 4, false ),
			'enabled'                     => true,
			'trigger_key'                 => sanitize_text_field( $rule['trigger_key'] ),
			'name'                        => sanitize_text_field( $rule['name'] ?? '' ),
			'sender_type'                 => sanitize_text_field( $rule['sender_type'] ?? 'user_whatsapp' ),
			'whatsapp_enabled'            => (int) ( $rule['whatsapp_enabled'] ?? 1 ),
			'whatsapp_message'            => wp_kses_post( $rule['whatsapp_message'] ?? '' ),
			'whatsapp_media_url'          => esc_url_raw( $rule['whatsapp_media_url'] ?? '' ),
			'email_enabled'               => (int) ( $rule['email_enabled'] ?? 0 ),
			'email_subject'               => sanitize_text_field( $rule['email_subject'] ?? '' ),
			'email_body'                  => wp_kses_post( $rule['email_body'] ?? '' ),
			'admin_user_ids'              => sanitize_text_field( $rule['admin_user_ids'] ?? '' ),
			'admin_whatsapp_enabled'      => (int) ( $rule['admin_whatsapp_enabled'] ?? 0 ),
			'admin_whatsapp_message'      => wp_kses_post( $rule['admin_whatsapp_message'] ?? '' ),
			'admin_whatsapp_media_url'    => '',
			'admin_email_enabled'         => (int) ( $rule['admin_email_enabled'] ?? 0 ),
			'admin_email_subject'         => sanitize_text_field( $rule['admin_email_subject'] ?? '' ),
			'admin_email_body'            => wp_kses_post( $rule['admin_email_body'] ?? '' ),
			'image_source_type'           => sanitize_text_field( $rule['image_source_type'] ?? 'none' ),
			'custom_image_url'            => esc_url_raw( $rule['custom_image_url'] ?? '' ),
			'send_product_image'          => (int) ( $rule['send_product_image'] ?? 0 ),
			'send_timing'                 => sanitize_text_field( $rule['send_timing'] ?? 'instant' ),
			'delay_value'                 => (int) ( $rule['delay_value'] ?? 0 ),
			'delay_unit'                  => sanitize_text_field( $rule['delay_unit'] ?? 'minutes' ),
			'country_filter_enabled'      => (int) ( $rule['country_filter_enabled'] ?? 0 ),
			'product_filter_enabled'      => (int) ( $rule['product_filter_enabled'] ?? 0 ),
			'category_filter_enabled'     => (int) ( $rule['category_filter_enabled'] ?? 0 ),
			'payment_filter_enabled'      => (int) ( $rule['payment_filter_enabled'] ?? 0 ),
			'billing_countries_whitelist' => sanitize_text_field( $rule['billing_countries_whitelist'] ?? '' ),
			'billing_countries_blocklist' => sanitize_text_field( $rule['billing_countries_blocklist'] ?? '' ),
			'payment_gateways'            => sanitize_text_field( $rule['payment_gateways'] ?? '' ),
			'product_ids_whitelist'       => sanitize_text_field( $rule['product_ids_whitelist'] ?? '' ),
			'product_ids_blocklist'       => sanitize_text_field( $rule['product_ids_blocklist'] ?? '' ),
			'category_ids_whitelist'      => sanitize_text_field( $rule['category_ids_whitelist'] ?? '' ),
			'category_ids_blocklist'      => sanitize_text_field( $rule['category_ids_blocklist'] ?? '' ),
			'meta_message_type'           => sanitize_text_field( $rule['meta_message_type'] ?? 'text' ),
			'meta_template_name'          => sanitize_text_field( $rule['meta_template_name'] ?? '' ),
			'meta_template_lang'          => sanitize_text_field( $rule['meta_template_lang'] ?? '' ),
			'email_template_id'           => sanitize_text_field( $rule['email_template_id'] ?? '' ),
			'admin_email_template_id'     => sanitize_text_field( $rule['admin_email_template_id'] ?? '' ),
		);

		// Append the new rule to the main language.
		if ( ! isset( $settings['configured_languages'][ $main ] ) ) {
			$settings['configured_languages'][ $main ] = array(
				'name'          => 'English',
				'notifications' => array(),
			);
		}
		$settings['configured_languages'][ $main ]['notifications'][] = $new_rule;

		// Save using the flow builder.
		$result = $fb->update_settings_from_react( $settings );

		return rest_ensure_response(
			array(
				'success' => true,
				'message' => 'Notification created successfully',
				'rule_id' => $new_rule['id'],
				'name'    => $new_rule['name'] ? $new_rule['name'] : $new_rule['trigger_key'],
			)
		);
	}

	/**
	 * Check if a given request has access to manage settings.
	 *
	 * @param WP_REST_Request|null $request Request object.
	 * @return bool|WP_Error True if permitted.
	 */
	public function permissions_check( $request = null ) {
		if ( ! defined( 'DONOTCACHEPAGE' ) ) {
			define( 'DONOTCACHEPAGE', true );
		}
		// Base capability check.
		if ( ! current_user_can( WAWP_CAPABILITY ) && ! current_user_can( 'manage_options' ) ) {
			return new WP_Error( 'rest_forbidden', esc_html__( 'You do not have permission to access Wawp settings.', 'automation-web-platform' ), array( 'status' => 403 ) );
		}

		if ( $request ) {
			$section = $request->get_param( 'section' );
			if ( ! empty( $section ) ) {
				// Future: Add granular section checks here (e.g., if a user has only campaign access).
				return apply_filters( 'wawp_rest_section_permissions', true, $section, get_current_user_id() );
			}
		}

		return true;
	}

	/**
	 * Retrieve all safe settings for the React dashboard.
	 *
	 * @return WP_REST_Response Response object.
	 */
	public function get_settings() {
		$keys = WAWP_Settings_Registry::get_all_keys();
		$data = array();
		foreach ( $keys as $key ) {
			// Get the value using the unified handler.
			$data[ $key ] = $this->get_wawp_setting( $key );
		}

		return rest_ensure_response(
			array(
				'success' => true,
				'data'    => $data,
			)
		);
	}

	/**
	 * Update settings from the React dashboard.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function update_settings( $request ) {
		$settings = $request->get_param( 'settings' );
		if ( ! is_array( $settings ) ) {
			return new WP_Error( 'rest_invalid_param', esc_html__( 'Settings must be an object.', 'automation-web-platform' ), array( 'status' => 400 ) );
		}

		$valid_keys       = WAWP_Settings_Registry::get_all_keys();
		$updated          = array();
		$premium_keys_map = array(
			WAWP_Settings_Registry::EMAIL_TRACKING_ENABLED => 'activity_log',
			WAWP_Settings_Registry::UNIFIED_LOG_ENABLED    => 'activity_log',
			WAWP_Settings_Registry::EMAIL_TEMPLATES_ENABLED => 'email_templates',
			WAWP_Settings_Registry::CAMPAIGNS_ENABLED      => 'segmented_notifications',
			WAWP_Settings_Registry::ABANDONED_CARTS_ENABLED => 'abandoned_cart_recovery',
			WAWP_Settings_Registry::SUB_NOTIFS_ENABLED     => 'subscription_alerts',
			WAWP_Settings_Registry::MULTILANG_ENABLED      => 'multilingual_support',
			WAWP_Settings_Registry::CHECKOUT_OTP_ENABLED   => 'checkout_verification',
			WAWP_Settings_Registry::CHECKOUT_SETTINGS      => 'checkout_verification',
		);

		foreach ( $settings as $key => $value ) {
			if ( isset( $premium_keys_map[ $key ] ) && ! wawp_is_feature_allowed( $premium_keys_map[ $key ] ) ) {
				continue;
			}

			if ( WAWP_Settings_Registry::CHECKOUT_SETTINGS === $key && class_exists( 'WAWP_Checkout_Otp' ) ) {
				// Checkout settings are handled by their own class to split into individual options.
				WAWP_Checkout_Otp::get_instance()->update_settings( $value );
				$updated[] = $key;
			} elseif ( 'wawp_signup_settings' === $key ) {
				// Map frontend key to backend registration form settings.
				$this->update_wawp_setting( WAWP_Settings_Registry::REGISTRATION_FORM_SETTINGS, $value );
				$updated[] = $key;
			} elseif ( WAWP_Settings_Registry::NOTIFICATIONS_RULES === $key && class_exists( 'WAWP_Flow_Builder' ) ) {
				// Special case for notification rules which are stored in custom tables.
				WAWP_Flow_Builder::get_instance()->update_settings_from_react( $value );
				$updated[] = $key;
			} elseif ( WAWP_Settings_Registry::SENDERS_ENABLED === $key ) {
				// Merge array values for senders to prevent overwriting other flags.
				$current = $this->get_wawp_setting( $key, array() );
				if ( ! is_array( $current ) ) {
					$current = array(
						'wa'    => (int) $current,
						'block' => (int) $current,
					);
				}
				$val = (array) $value;
				if ( isset( $val['meta'] ) && ! wawp_is_feature_allowed( 'meta_api_sender' ) ) {
					unset( $val['meta'] );
				}
				if ( isset( $val['firebase'] ) && ! wawp_is_feature_allowed( 'firebase_sms' ) ) {
					unset( $val['firebase'] );
				}
				$merged = array_merge( $current, $val );
				$this->update_wawp_setting( $key, $merged );
				$updated[] = $key;
			} elseif ( in_array( $key, $valid_keys, true ) ) {
				// Enforce mutual exclusivity: Lock Site and Show Globally cannot be both active.
				if ( WAWP_Settings_Registry::PHONE_BAR_LOCK_SITE === $key && 1 === (int) $value ) {
					$this->update_wawp_setting( WAWP_Settings_Registry::PHONE_BAR_GLOBALLY, 0 );
				} elseif ( WAWP_Settings_Registry::PHONE_BAR_GLOBALLY === $key && 1 === (int) $value ) {
					$this->update_wawp_setting( WAWP_Settings_Registry::PHONE_BAR_LOCK_SITE, 0 );
				}

				// The update_wawp_setting handles prepare_for_db automatically (arrays to json, etc.).
				$this->update_wawp_setting( $key, $value );
				$updated[] = $key;
			} elseif ( strpos( $key, 'woocommerce_' ) === 0 ) {
				// Allow core WooCommerce settings used in our dashboard.
				update_option( $key, sanitize_text_field( $value ) );
				$updated[] = $key;
			}
		}

		if ( ! empty( $updated ) ) {
			// Clear relevant caches to ensure changes are reflected immediately.
			if ( class_exists( 'WAWP_Menu' ) ) {
				WAWP_Menu::clear_all_dashboard_transients();
			} else {
				wp_cache_delete( 'wawp_otp_settings_raw', 'wawp_otp' );
				wp_cache_delete( 'wawp_dashboard_data_full_' . get_current_user_id(), 'wawp_database' );
				delete_transient( 'wawp_dashboard_data_full_' . get_current_user_id() );
			}
			// Purge all page cache plugins (LiteSpeed, WP Rocket, etc.) so new settings are live immediately.
			if ( class_exists( 'WAWP_Cache_Compat' ) ) {
				WAWP_Cache_Compat::purge_on_settings_save();
			}
		}

		return rest_ensure_response(
			array(
				'success' => true,
				'message' => esc_html__( 'Settings updated successfully.', 'automation-web-platform' ),
				'updated' => $updated,
			)
		);
	}

	/**
	 * Handle Meta-specific operations (Sync, Webhook).
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_meta_operations( $request ) {
		$op   = $request->get_param( 'op' );
		$meta = new WAWP_Meta_Sender( null );
		$res  = array();
		if ( 'sync' === $op ) {
			$res = $meta->handle_fetch_templates();
		} elseif ( 'webhook' === $op ) {
			$res = $meta->handle_subscribe_webhooks();
		}

		return rest_ensure_response( $res );
	}

	/**
	 * Handle WhatsApp Web-specific operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_whatsapp_ops( $request ) {
		$op  = $request->get_param( 'op' );
		$wa  = WAWP()->senders;
		$res = array();
		switch ( $op ) {
			case 'status':
				$res = $wa->wawp_update_status( $request->get_param( 'instance_id' ), $request->get_param( 'access_token' ) );
				break;
			case 'test':
				$res = $wa->wawp_send_test_message( $request->get_param( 'instance_id' ), $request->get_param( 'access_token' ), $request->get_param( 'phone_number' ), $request->get_param( 'message' ) );
				break;
			case 'me':
				$res = $wa->wawp_get_session_me( $request->get_param( 'instance_id' ), $request->get_param( 'access_token' ) );
				break;
			case 'sync_all':
				$res = $wa->wawp_auto_check_all_instance_status();
				break;
		}

		return rest_ensure_response( $res );
	}

	/**
	 * Handle database operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_db_ops( $request ) {
		$op    = $request->get_param( 'op' );
		$table = $request->get_param( 'table' );
		if ( empty( WAWP()->system_info ) && class_exists( 'WAWP_System_Info' ) ) {
			WAWP()->system_info = new WAWP_System_Info();
		}
		$si = WAWP()->system_info;

		if ( ! $si ) {
			return new WP_Error( 'not_found', 'System Info class not found.', array( 'status' => 404 ) );
		}

		switch ( $op ) {
			case 'truncate':
				$res = $si->handle_truncate_table( $table );
				break;
			case 'drop':
				$res = $si->handle_drop_table( $table );
				break;
			case 'create':
				$res = $si->handle_create_table( $table );
				break;
			case 'repair':
				$res = $si->handle_repair_database();
				break;
			default:
				return new WP_Error( 'invalid_op', 'Invalid database operation', array( 'status' => 400 ) );
		}

		return rest_ensure_response( $res );
	}

	/**
	 * Get cart sessions.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function get_cart_sessions( $request ) {
		if ( ! class_exists( 'WAWP_Abandoned_Carts' ) ) {
			return new WP_Error( 'not_found', 'Abandoned Carts class not found.', array( 'status' => 404 ) );
		}

		$ac     = new WAWP_Abandoned_Carts();
		$params = array(
			'status'      => $request->get_param( 'status' ),
			'search'      => $request->get_param( 'search' ),
			'paged'       => $request->get_param( 'paged' ),
			'has_contact' => $request->get_param( 'has_contact' ),
		);

		$result = $ac->get_sessions( $params );
		return rest_ensure_response(
			array(
				'success' => true,
				'data'    => $result,
			)
		);
	}

	/**
	 * Search entities (products, categories, users) for React UI.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function search_entities( $request ) {
		if ( ! class_exists( 'WAWP_Flow_Builder' ) ) {
			return new WP_Error( 'not_found', 'Flow Builder class not found.', array( 'status' => 404 ) );
		}

		$flow_builder = WAWP_Flow_Builder::get_instance();
		$params       = $request->get_params();
		$res          = $flow_builder->search_entities( $params );

		return rest_ensure_response( $res );
	}


	/**
	 * Handle cart operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_cart_ops( $request ) {
		$op = $request->get_param( 'op' );
		if ( ! class_exists( 'WAWP_Abandoned_Carts' ) ) {
			return new WP_Error( 'not_found', 'Abandoned Carts class not found.', array( 'status' => 404 ) );
		}

		$ac = new WAWP_Abandoned_Carts();
		if ( 'clear' === $op ) {
			$params = array(
				'clear_type' => $request->get_param( 'clear_type' ),
				'ids'        => $request->get_param( 'ids' ),
			);
			$res    = $ac->clear_abandoned_carts( $params );
		} elseif ( 'toggle-visibility' === $op ) {
			$res = $ac->toggle_hide_incomplete();
		} else {
			return new WP_Error( 'invalid_op', 'Invalid cart operation', array( 'status' => 400 ) );
		}

		return rest_ensure_response( $res );
	}

	/**
	 * Refresh connector status.
	 *
	 * @return WP_REST_Response Response object.
	 */
	public function refresh_connector_status() {
		$connector = WAWP()->connector;
		if ( ! $connector ) {
			return new WP_Error( 'not_found', 'Connector instance not found.', array( 'status' => 404 ) );
		}

		return rest_ensure_response( $connector->auto_check_status() );
	}

	/**
	 * Handle log operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_log_ops( $request ) {
		$op = $request->get_param( 'op' );
		$ul = WAWP()->unified_log;
		if ( ! $ul ) {
			return new WP_Error( 'not_found', 'Unified Log instance not found.', array( 'status' => 404 ) );
		}

		$params = $request->get_params();
		switch ( $op ) {
			case 'list':
				$res = $ul->get_logs( $params );
				break;
			case 'timeline':
				$res = $ul->get_user_timeline( $params );
				break;
			case 'delete':
				$res = $ul->delete_logs( $params );
				break;
			case 'clear':
				$res = $ul->delete_logs( array( 'clear_all' => true ) );
				break;
			case 'resend':
				$log_id = isset( $params['log_id'] ) ? intval( $params['log_id'] ) : 0;
				if ( ! $log_id ) {
					return new WP_Error( 'missing_param', 'Missing log_id parameter', array( 'status' => 400 ) );
				}
				$log = WAWP()->db->get_row_by_id( 'unified_activity_logs', $log_id );
				if ( ! $log ) {
					return new WP_Error( 'not_found', 'Log entry not found', array( 'status' => 404 ) );
				}

				$gateway   = $log->gateway;
				$recipient = '';
				$send_args = array(
					'channel'     => $gateway,
					'message'     => $log->message,
					'user_id'     => $log->user_id,
					'related_id'  => $log->order_id,
					'context'     => 'Resend Activity Hub Log',
					'send_timing' => 'instant',
				);

				if ( 'email' === $gateway ) {
					$recipient            = $log->email;
					$details              = json_decode( $log->details, true );
					$details              = is_array( $details ) ? $details : array();
					$send_args['subject'] = $details['message_type'] ?? $details['subject'] ?? 'Notification';
				} else {
					$recipient = $log->phone;
					if ( 'meta' === $gateway ) {
						$details = json_decode( $log->details, true );
						$details = is_array( $details ) ? $details : array();
						if ( ! empty( $details['meta_template_name'] ) || ! empty( $details['template_name'] ) ) {
							$send_args['meta_message_type'] = 'template';
							$send_args['template_name']     = $details['meta_template_name'] ?? $details['template_name'] ?? '';
							$send_args['template_lang']     = $details['meta_template_lang'] ?? $details['template_lang'] ?? 'en';
							$send_args['components']        = $details['components'] ?? array();
						} else {
							$send_args['meta_message_type'] = 'text';
						}
					}
				}

				if ( empty( $recipient ) ) {
					return new WP_Error( 'missing_recipient', 'No recipient phone or email found in log record', array( 'status' => 400 ) );
				}

				// Bypass the 10-second deduplication lock.
				$lock_key = 'wawp_msg_lock_' . md5( $recipient . wp_json_encode( $send_args ) );
				delete_transient( $lock_key );

				$success = wawp_messenger()->send( $recipient, $send_args );

				$res = array(
					'success' => (bool) $success,
					'message' => $success ? 'Message resent successfully.' : 'Failed to resend message via gateway.',
				);
				break;
			case 'send':
				$send_user_id = isset( $params['user_id'] ) ? intval( $params['user_id'] ) : 0;
				$gateway      = isset( $params['gateway'] ) ? sanitize_text_field( $params['gateway'] ) : '';
				$message      = isset( $params['message'] ) ? $params['message'] : '';
				$subject      = isset( $params['subject'] ) ? sanitize_text_field( $params['subject'] ) : 'Manual Message';

				if ( ! $send_user_id ) {
					return new WP_Error( 'missing_user', 'Missing user_id parameter', array( 'status' => 400 ) );
				}
				if ( ! in_array( $gateway, array( 'email', 'whatsapp', 'meta' ), true ) ) {
					return new WP_Error( 'invalid_gateway', 'Invalid gateway. Supported: email, whatsapp, meta', array( 'status' => 400 ) );
				}
				if ( empty( $message ) ) {
					return new WP_Error( 'empty_message', 'Message body cannot be empty', array( 'status' => 400 ) );
				}

				$user = get_userdata( $send_user_id );
				if ( ! $user ) {
					return new WP_Error( 'user_not_found', 'User not found', array( 'status' => 404 ) );
				}

				$email = $user->user_email;
				$phone = WAWP()->user_manager->get_user_phone( $user->ID );

				$recipient = '';
				$send_args = array(
					'channel'     => $gateway,
					'message'     => $message,
					'user_id'     => $user->ID,
					'context'     => 'Manual Message Send',
					'send_timing' => 'instant',
				);

				if ( 'email' === $gateway ) {
					if ( empty( $email ) || ! is_email( $email ) ) {
						return new WP_Error( 'no_email', 'User has no valid email address', array( 'status' => 400 ) );
					}
					$recipient            = $email;
					$send_args['subject'] = $subject;
				} else {
					if ( empty( $phone ) ) {
						return new WP_Error( 'no_phone', 'User has no phone number for WhatsApp', array( 'status' => 400 ) );
					}
					$recipient = $phone;
					if ( 'meta' === $gateway ) {
						$send_args['meta_message_type'] = 'text';
					}
				}

				// Bypass the 10-second deduplication lock.
				$lock_key = 'wawp_msg_lock_' . md5( $recipient . wp_json_encode( $send_args ) );
				delete_transient( $lock_key );

				$success = wawp_messenger()->send( $recipient, $send_args );

				$res = array(
					'success' => (bool) $success,
					'message' => $success ? 'Message sent successfully.' : 'Failed to send message via gateway.',
				);
				break;
			default:
				return new WP_Error( 'invalid_op', 'Invalid log operation', array( 'status' => 400 ) );
		}

		return rest_ensure_response( $res );
	}

	/**
	 * Get email templates.
	 *
	 * @return WP_REST_Response Response object.
	 */
	public function get_email_templates() {
		$templates = array();
		if ( ! empty( WAWP()->email_templates ) ) {
			$templates = WAWP()->email_templates->handle_get_templates();
		}

		return rest_ensure_response(
			array(
				'success'   => true,
				'templates' => $templates,
			)
		);
	}

	/**
	 * Get single email template.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function get_email_template( $request ) {
		if ( empty( WAWP()->email_templates ) ) {
			return new WP_Error( 'not_found', 'Email templates component not found', array( 'status' => 404 ) );
		}
		$id     = $request->get_param( 'id' );
		$result = WAWP()->email_templates->handle_get_template( $id );

		return rest_ensure_response( $result );
	}

	/**
	 * Save email template.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function save_email_template( $request ) {
		$result = WAWP()->email_templates->handle_save_template( $request->get_params() );

		return rest_ensure_response( $result );
	}

	/**
	 * Delete email template.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function delete_email_template( $request ) {
		if ( empty( WAWP()->email_templates ) ) {
			return new WP_Error( 'not_found', 'Email templates component not found', array( 'status' => 404 ) );
		}
		$id     = $request->get_param( 'id' );
		$result = WAWP()->email_templates->handle_delete_template( $id );

		return rest_ensure_response( $result );
	}

	/**
	 * Send test email template.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function send_test_email_template( $request ) {
		$result = WAWP()->email_templates->handle_send_test_email( $request->get_params() );

		return rest_ensure_response( $result );
	}

	/**
	 * Send custom message to user.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function send_user_message( $request ) {
		if ( empty( WAWP()->others ) ) {
			return new WP_Error( 'not_found', 'Others component not found', array( 'status' => 404 ) );
		}
		$result = WAWP()->others->handle_send_user_custom_message( $request->get_params() );

		return rest_ensure_response( $result );
	}

	/**
	 * Get Campaigns instance, instantiating if necessary.
	 *
	 * @return WAWP_Campaigns_Advanced|null
	 */
	private function get_campaigns_instance() {
		if ( empty( WAWP()->campaigns ) && class_exists( 'WAWP_Campaigns_Advanced' ) ) {
			WAWP()->campaigns = new WAWP_Campaigns_Advanced();
		}
		return WAWP()->campaigns;
	}

	/**
	 * Get all campaigns.
	 *
	 * @return WP_REST_Response Response object.
	 */
	public function get_campaigns() {
		$campaigns = $this->get_campaigns_instance();
		$result    = $campaigns ? $campaigns->handle_get_campaigns_data() : array();

		return rest_ensure_response(
			array(
				'success' => true,
				'data'    => $result,
			)
		);
	}

	/**
	 * Toggle campaign status.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function toggle_campaign( $request ) {
		$id        = $request->get_param( 'id' );
		$pause_val = $request->get_param( 'pause_val' );
		$campaigns = $this->get_campaigns_instance();
		$result    = $campaigns ? $campaigns->handle_toggle_campaign( $id, $pause_val ) : array();

		return rest_ensure_response( $result );
	}

	/**
	 * Rerun campaign.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function rerun_campaign( $request ) {
		$id        = $request->get_param( 'id' );
		$campaigns = $this->get_campaigns_instance();
		$result    = $campaigns ? $campaigns->handle_rerun_campaign( $id ) : array();

		return rest_ensure_response( $result );
	}

	/**
	 * Approve risky campaign.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function approve_risky_campaign( $request ) {
		$id        = $request->get_param( 'id' );
		$campaigns = $this->get_campaigns_instance();
		$result    = $campaigns ? $campaigns->handle_run_risky( $id ) : array();

		return rest_ensure_response( $result );
	}

	/**
	 * Save campaign.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function save_campaign( $request ) {
		$campaigns = $this->get_campaigns_instance();
		$result    = $campaigns ? $campaigns->handle_save_campaign( $request->get_params() ) : array();

		return rest_ensure_response( $result );
	}

	/**
	 * Delete campaigns.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function delete_campaigns( $request ) {
		$ids       = $request->get_param( 'ids' );
		$campaigns = $this->get_campaigns_instance();
		$result    = $campaigns ? $campaigns->handle_bulk_delete_campaigns( $ids ) : array();

		return rest_ensure_response( $result );
	}

	/**
	 * Get system info.
	 *
	 * @return WP_REST_Response Response object.
	 */
	public function get_system_info() {
		if ( empty( WAWP()->system_info ) && class_exists( 'WAWP_System_Info' ) ) {
			WAWP()->system_info = new WAWP_System_Info();
		}
		$result = WAWP()->system_info ? WAWP()->system_info->handle_refresh_status() : array();

		return rest_ensure_response( $result );
	}

	/**
	 * Refresh system info.
	 *
	 * @return WP_REST_Response Response object.
	 */
	public function refresh_system_info() {
		if ( empty( WAWP()->system_info ) && class_exists( 'WAWP_System_Info' ) ) {
			WAWP()->system_info = new WAWP_System_Info();
		}
		$result = WAWP()->system_info ? WAWP()->system_info->handle_refresh_status() : array();

		return rest_ensure_response( $result );
	}

	/**
	 * Track chat widget interactions.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function track_chat_widget( $request ) {
		$op     = $request->get_param( 'op' );
		$params = $request->get_params();
		if ( empty( WAWP()->chat_widget ) && class_exists( 'WAWP_Chat_Widget' ) ) {
			WAWP()->chat_widget = new WAWP_Chat_Widget();
		}
		$chat = WAWP()->chat_widget;
		if ( ! $chat ) {
			return new WP_Error( 'not_found', 'Chat Widget not active.', array( 'status' => 404 ) );
		}
		switch ( $op ) {
			case 'contact_click':
				$res = $chat->handle_contact_click( $params );
				break;
			case 'whatsapp_click':
				$res = $chat->handle_open_whatsapp_click( $params );
				break;
			case 'impression':
				$res = $chat->handle_track_chat_impression( $params );
				break;
			default:
				return new WP_Error( 'invalid_op', 'Invalid chat widget operation', array( 'status' => 400 ) );
		}

		return rest_ensure_response( $res );
	}

	/**
	 * Handle Connection Test.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_recaptcha_test( $request ) {
		$params     = $request->get_params();
		$site_key   = $params['site_key'] ?? '';
		$secret_key = $params['secret_key'] ?? '';
		$token      = $params['token'] ?? '';
		if ( ! $site_key || ! $secret_key || ! $token ) {
			return new WP_Error( 'missing_params', 'Missing keys or token.', array( 'status' => 400 ) );
		}

		// reCAPTCHA verification logic would go here.
		return rest_ensure_response(
			array(
				'success' => true,
				'message' => 'Connection verified successfully.',
			)
		);
	}

	/**
	 * Handle Custom Page Creation.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_create_page( $request ) {
		$type = $request->get_param( 'type' );
		if ( ! class_exists( 'WAWP_Custom_Pages_Settings' ) ) {
			return new WP_Error( 'not_found', 'Custom Pages class not found.', array( 'status' => 404 ) );
		}

		$pages_settings = new WAWP_Custom_Pages_Settings();
		$result         = $pages_settings->handle_create_page( $type );

		return rest_ensure_response( $result );
	}

	/**
	 * Handle OTP operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_otp_ops( $request ) {
		$op     = $request->get_param( 'op' );
		$params = $request->get_params();

		if ( in_array( $op, array( 'request', 'verify', 'status' ), true ) ) {
			if ( ! class_exists( 'WAWP_Otp_Login' ) ) {
				return new WP_Error( 'not_found', 'OTP Login class not found.', array( 'status' => 404 ) );
			}

			$otp_login = new WAWP_Otp_Login( WAWP()->db, WAWP()->instances );
			switch ( $op ) {
				case 'request':
					$res = $otp_login->ajax_request_otp_return( $params );
					if ( is_wp_error( $res ) ) {
						return $res;
					}
					return rest_ensure_response(
						array(
							'success' => true,
							'data'    => $res,
						)
					);
				case 'verify':
					$res = $otp_login->handle_verify_otp_return( $params );
					if ( is_wp_error( $res ) ) {
						return $res;
					}
					return rest_ensure_response(
						array(
							'success' => true,
							'data'    => $res,
						)
					);
				case 'status':
					$res = $otp_login->ajax_check_auth_status_return( $params );
					if ( is_wp_error( $res ) ) {
						return $res;
					}
					return rest_ensure_response(
						array(
							'success' => true,
							'data'    => $res,
						)
					);
			}
		}

		if ( in_array( $op, array( '-token', '-log' ), true ) ) {
			if ( ! class_exists( 'WAWP_Otp_Login' ) ) {
				return new WP_Error( 'not_found', 'OTP Login class not found.', array( 'status' => 404 ) );
			}

			$otp_login = new WAWP_Otp_Login( WAWP()->db, WAWP()->instances );
			if ( '-token' === $op ) {
				return rest_ensure_response( $otp_login->handle_verify_firebase_token_return( $params ) );
			} else {
				return rest_ensure_response( $otp_login->ajax_log_firebase_otp_return( $params ) );
			}
		}

		return new WP_Error( 'invalid_op', 'Invalid OTP operation', array( 'status' => 400 ) );
	}

	/**
	 * Check REST permissions (Alias for permissions_check for consistency).
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return bool|WP_Error True if permitted.
	 */
	public function check_rest_permissions( $request ) {
		return $this->permissions_check( $request );
	}

	/**
	 * Handle System Info operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_system_info_ops( $request ) {
		$op     = $request->get_param( 'op' );
		$params = $request->get_params();
		$sys    = new WAWP_System_Info();

		switch ( $op ) {
			case 'refresh':
				return rest_ensure_response( $sys->refresh_system_status_return() );
			case 'sync-users':
				return rest_ensure_response( $sys->handle_sync_users() );
			case 'repair-all':
				return rest_ensure_response( $sys->repair_all_issues_return() );
			case 'migrate-notifications':
				return rest_ensure_response( $sys->handle_migrate_notifications_return( $params ) );
			case 'repair-db':
				return rest_ensure_response( $sys->repair_database_return() );
			case 'schedule-cron':
				return rest_ensure_response( $sys->schedule_cron_return( $params ) );
			case 'truncate-table':
				return rest_ensure_response( $sys->truncate_table_return( $params ) );
			case 'create-table':
				return rest_ensure_response( $sys->create_table_return( $params ) );
			case 'drop-table':
				return rest_ensure_response( $sys->drop_table_return( $params ) );
			case 'migrate-signup':
				return rest_ensure_response( $sys->handle_migrate_signup_return( $params ) );
			default:
				return new WP_Error( 'invalid_op', 'Invalid system info operation', array( 'status' => 400 ) );
		}
	}

	/**
	 * Handle Activity Hub operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_activity_hub_ops( $request ) {
		$op     = $request->get_param( 'op' );
		$params = $request->get_params();
		$log    = WAWP()->unified_log;

		if ( ! $log ) {
			return new WP_Error( 'not_found', 'Unified Log features require Wawp Pro.', array( 'status' => 404 ) );
		}

		switch ( $op ) {
			case 'get-logs':
				return rest_ensure_response( $log->get_logs( $params ) );
			case 'get-timeline':
				return rest_ensure_response( $log->get_user_timeline( $params ) );
			case 'delete-logs':
				return rest_ensure_response( $log->delete_logs( $params ) );
			case 'clear-all':
				return rest_ensure_response( $log->delete_logs( array( 'clear_all' => true ) ) );
			default:
				return new WP_Error( 'invalid_op', 'Invalid activity hub operation', array( 'status' => 400 ) );
		}
	}

	/**
	 * Handle OTP Login operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_otp_login_ops( $request ) {
		$op     = $request->get_param( 'op' );
		$params = $request->get_params();
		$otp    = WAWP_Otp_Login::get_instance( WAWP()->db, WAWP()->senders );

		switch ( $op ) {
			case 'request':
				$res = $otp->ajax_request_otp_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case 'resend':
				$res = $otp->ajax_resend_otp_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case 'verify':
				$res = $otp->handle_verify_otp_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case 'status':
				$res = $otp->ajax_check_auth_status_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case 'fetch':
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $otp->get_react_settings_data(),
					)
				);
			case 'verify_firebase':
				$res = $otp->handle_verify_firebase_token_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case 'log_firebase':
				$res = $otp->ajax_log_firebase_otp_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case 'log_auth_failure':
				$res = $otp->ajax_log_auth_failure( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case 'login_password':
				$res = $otp->handle_email_password_login_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			default:
				return new WP_Error( 'invalid_op', 'Invalid OTP login operation', array( 'status' => 400 ) );
		}
	}

	/**
	 * Handle Email Template operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_email_template_ops( $request ) {
		$op        = $request->get_param( 'op' );
		$params    = $request->get_params();
		$templates = new WAWP_Email_Templates();

		switch ( $op ) {
			case 'fetch':
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $templates->handle_get_templates(),
					)
				);
			case 'get':
				return rest_ensure_response( $templates->handle_get_template( $params['id'] ?? 0 ) );
			case 'save':
				return rest_ensure_response( $templates->handle_save_template( $params ) );
			case 'delete':
				return rest_ensure_response( $templates->handle_delete_template( $params['id'] ?? 0 ) );
			case 'test':
				return rest_ensure_response( $templates->handle_send_test_email( $params ) );
			default:
				return new WP_Error( 'invalid_op', 'Invalid email template operation', array( 'status' => 400 ) );
		}
	}

	/**
	 * Handle Chat Widget operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_chat_widget_ops( $request ) {
		$op     = $request->get_param( 'op' );
		$params = $request->get_params();
		$chat   = new WAWP_Chat_Widget();

		switch ( $op ) {
			case 'contact-click':
				return rest_ensure_response( $chat->handle_contact_click_return( $params ) );
			case 'open-whatsapp':
				return rest_ensure_response( $chat->handle_open_whatsapp_click_return( $params ) );
			case 'impression':
				return rest_ensure_response( $chat->handle_track_chat_impression_return( $params ) );
			case 'increment-clicks':
				return rest_ensure_response( $chat->handle_increment_chat_clicks_return( $params ) );
			case 'social-click':
				return rest_ensure_response( $chat->handle_track_social_click_return( $params ) );
			case 'clear-stats':
				if ( ! $this->permissions_check() ) {
					return new WP_Error( 'rest_forbidden', 'Forbidden', array( 'status' => 403 ) );
				}

				return rest_ensure_response( $chat->handle_clear_stats_return() );
			default:
				return new WP_Error( 'invalid_op', 'Invalid chat widget operation', array( 'status' => 400 ) );
		}
	}

	/**
	 * Handle Campaigns operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_campaign_ops( $request ) {
		$op        = $request->get_param( 'op' );
		$params    = $request->get_params();
		$campaigns = new WAWP_Campaigns_Advanced();

		switch ( $op ) {
			case 'fetch':
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $campaigns->handle_get_campaigns_data(),
					)
				);
			case 'toggle':
				return rest_ensure_response( $campaigns->handle_toggle_campaign( $params['id'] ?? 0, $params['pause_val'] ?? 0 ) );
			case 'rerun':
				return rest_ensure_response( $campaigns->handle_rerun_campaign( $params['id'] ?? 0 ) );
			case 'delete':
				return rest_ensure_response( $campaigns->handle_bulk_delete_campaigns( $params['ids'] ?? array() ) );
			case 'save':
				return rest_ensure_response( $campaigns->handle_save_campaign( $params ) );
			case 'risky':
				return rest_ensure_response( $campaigns->handle_run_risky( $params['cid'] ?? 0 ) );
			case 'calc':
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $campaigns->handle_wizard_calc_recipients( $params ),
					)
				);
			case 'preview':
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $campaigns->handle_preview( $params['message'] ?? '', $params['user_id'] ?? get_current_user_id() ),
					)
				);
			case 'search-users':
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $campaigns->handle_search_users( $params ),
					)
				);
			case 'search-products':
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $campaigns->handle_search_products( $params ),
					)
				);
			case 'search-posts':
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $campaigns->handle_search_posts( $params ),
					)
				);
			default:
				return new WP_Error( 'invalid_op', 'Invalid campaign operation', array( 'status' => 400 ) );
		}
	}

	/**
	 * Handle Signup operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_signup_ops( $request ) {
		$op     = $request->get_param( 'op' );
		$params = $request->get_params();
		$signup = WAWP_Signup::get_instance();

		switch ( $op ) {
			case 'signup':
				$res = $signup->ajax_signup_form_submit_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case 'check_availability':
				$res = $signup->ajax_check_availability_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case 'verify':
				$res = $signup->ajax_verify_otp_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case 'resend':
				$res = $signup->ajax_resend_otp_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case 'status':
				$res = $signup->ajax_check_auth_status_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case '-token':
				$res = $signup->ajax_verify_firebase_token_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			default:
				return new WP_Error( 'invalid_op', 'Invalid signup operation', array( 'status' => 400 ) );
		}
	}

	/**
	 * Handle Checkout OTP operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_checkout_otp_ops( $request ) {
		$op       = $request->get_param( 'op' );
		$params   = $request->get_params();
		$checkout = new WAWP_Checkout_OTP();

		switch ( $op ) {
			case 'send':
				$res = $checkout->send_otp_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case 'resend':
				$res = $checkout->ajax_resend_otp_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case 'verify':
				$res = $checkout->verify_otp_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			case 'status':
				$res = $checkout->check_auth_status_return( $params );
				if ( is_wp_error( $res ) ) {
					return $res;
				}
				return rest_ensure_response(
					array(
						'success' => true,
						'data'    => $res,
					)
				);
			default:
				return new WP_Error( 'invalid_op', 'Invalid checkout OTP operation', array( 'status' => 400 ) );
		}
	}

	/**
	 * Handle Flow Builder operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_flow_ops( $request ) {
		$op     = $request->get_param( 'op' );
		$params = $request->get_params();
		if ( ! class_exists( 'WAWP_Flow_Builder' ) ) {
			return new WP_Error( 'not_found', 'Flow Builder class not found.', array( 'status' => 404 ) );
		}

		$flow_builder = WAWP_Flow_Builder::get_instance();
		switch ( $op ) {
			case 'search':
				return rest_ensure_response( $flow_builder->ajax_search_entities_return( $params ) );
			case 'test':
				return rest_ensure_response( $flow_builder->send_test_notification( $params ) );
		}

		return new WP_Error( 'invalid_op', 'Invalid flow operation', array( 'status' => 400 ) );
	}

	/**
	 * Handle System operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_system_ops( $request ) {
		$op     = $request->get_param( 'op' );
		$params = $request->get_params();
		if ( ! class_exists( 'WAWP_System_Info' ) ) {
			return new WP_Error( 'not_found', 'System Info class not found.', array( 'status' => 404 ) );
		}

		$system_info = new WAWP_System_Info();
		switch ( $op ) {
			case 'status':
			case 'refresh':
				return rest_ensure_response( $system_info->handle_refresh_status() );
			case 'sync-users':
				return rest_ensure_response( $system_info->handle_sync_users() );
			case 'repair':
				return rest_ensure_response( $system_info->handle_repair_all() );
			case 'schedule-cron':
				return rest_ensure_response( $system_info->schedule_cron_return( $params ) );
			case 'migrate-signup':
				return rest_ensure_response( $system_info->handle_migrate_signup_return() );
			case 'migrate-notifications':
				return rest_ensure_response( $system_info->handle_migrate_notifications_return() );
			case 'import-email-templates':
				return rest_ensure_response( $system_info->handle_import_email_templates() );
			case 'import-auto-notifications':
				return rest_ensure_response( $system_info->handle_import_auto_notifications() );
			case 'wizard-checks':
				return rest_ensure_response( $system_info->handle_wizard_checks() );
			case 'install-updater':
				return rest_ensure_response( $this->install_wawp_updater() );
		}

		return new WP_Error( 'invalid_op', 'Invalid system operation', array( 'status' => 400 ) );
	}

	/**
	 * Install and activate the Wawp Updater plugin automatically.
	 *
	 * @return WP_REST_Response|WP_Error Response or Error.
	 */
	public function install_wawp_updater() {
		require_once ABSPATH . 'wp-admin/includes/file.php';
		require_once ABSPATH . 'wp-admin/includes/plugin.php';
		require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
		require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';

		$plugin_dir_name = 'wawp-updater';
		$plugin_slug     = 'wawp-updater/wawp-updater.php';
		$plugin_dir      = WP_PLUGIN_DIR . '/' . $plugin_dir_name;
		$plugin_file     = $plugin_dir . '/wawp-updater.php';

		// If the updater plugin is already installed, just activate it.
		if ( file_exists( $plugin_file ) ) {
			$activate = activate_plugin( $plugin_slug );
			if ( is_wp_error( $activate ) ) {
				return new WP_Error( 'activation_failed', $activate->get_error_message(), array( 'status' => 500 ) );
			}
			// Reset localized script transients so React reflects the new active state immediately.
			$user_id = get_current_user_id();
			$locale  = get_user_locale();
			delete_transient( 'wawp_dashboard_data_full_' . $user_id . '_' . $locale );
			wp_cache_delete( 'wawp_dashboard_data_full_' . $user_id . '_' . $locale, 'wawp_database' );

			return new WP_REST_Response(
				array(
					'success' => true,
					'message' => 'Wawp Updater activated successfully.',
				),
				200
			);
		}

		$file_url = 'https://wawp.net/releases/wawp-updater.zip';

		// Download the ZIP file.
		$tmp_file = download_url( $file_url, 60 );
		if ( is_wp_error( $tmp_file ) ) {
			return new WP_Error( 'download_failed', $tmp_file->get_error_message(), array( 'status' => 500 ) );
		}

		$plugin_dir_name = 'wawp-updater';
		$plugin_slug     = 'wawp-updater/wawp-updater.php';
		$plugin_dir      = WP_PLUGIN_DIR . '/' . $plugin_dir_name;

		WP_Filesystem();
		global $wp_filesystem;

		// Create a temp extraction dir.
		$extract_dir = get_temp_dir() . 'wawp-updater-install-' . time() . '/';
		$unzip       = unzip_file( $tmp_file, $extract_dir );
		if ( file_exists( $tmp_file ) ) {
			wp_delete_file( $tmp_file );
		}

		if ( is_wp_error( $unzip ) ) {
			return new WP_Error( 'unzip_failed', $unzip->get_error_message(), array( 'status' => 500 ) );
		}

		// Find the extracted plugin directory.
		$extracted_items = glob( $extract_dir . '*', GLOB_ONLYDIR );
		if ( empty( $extracted_items ) ) {
			$wp_filesystem->delete( $extract_dir, true );
			return new WP_Error( 'empty_extraction', 'Could not find extracted plugin folder.', array( 'status' => 500 ) );
		}
		$source_dir = trailingslashit( $extracted_items[0] );

		// Remove the old plugin directory and copy the new one.
		if ( file_exists( $plugin_dir ) ) {
			$wp_filesystem->delete( $plugin_dir, true );
		}

		$copy = copy_dir( $source_dir, $plugin_dir );
		$wp_filesystem->delete( $extract_dir, true );

		if ( is_wp_error( $copy ) ) {
			return new WP_Error( 'copy_failed', $copy->get_error_message(), array( 'status' => 500 ) );
		}

		// Reactivate/Activate the plugin.
		$activate = activate_plugin( $plugin_slug );
		if ( is_wp_error( $activate ) ) {
			return new WP_Error( 'activation_failed', $activate->get_error_message(), array( 'status' => 500 ) );
		}

		// Reset localized script transients so React reflects the new active state immediately.
		$user_id = get_current_user_id();
		$locale  = get_user_locale();
		delete_transient( 'wawp_dashboard_data_full_' . $user_id . '_' . $locale );
		wp_cache_delete( 'wawp_dashboard_data_full_' . $user_id . '_' . $locale, 'wawp_database' );

		return new WP_REST_Response(
			array(
				'success' => true,
				'message' => 'Wawp Updater installed and activated successfully.',
			),
			200
		);
	}

	/**
	 * Handle Phone Verification Bar operations.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function handle_phone_bar_ops( $request ) {
		$op     = $request->get_param( 'op' );
		$params = $request->get_params();
		$bar    = new WAWP_Phone_Verification_Bar();

		switch ( $op ) {
			case 'update-phone':
				return rest_ensure_response( $bar->update_phone_number_return( $params ) );
			case 'send':
				return rest_ensure_response( $bar->send_phone_otp_return( $params ) );
			case 'verify':
				return rest_ensure_response( $bar->verify_phone_otp_return( $params ) );
			case 'status':
				return rest_ensure_response( $bar->check_phone_auth_status_return( $params ) );
			case '-token':
				return rest_ensure_response( $bar->verify_firebase_token_return( $params ) );
			case '-log':
				return rest_ensure_response( $bar->log_firebase_otp_return( $params ) );
			case 'dismiss':
				return rest_ensure_response( $bar->dismiss_phone_bar_return( $params ) );
			default:
				return new WP_Error( 'invalid_op', 'Invalid phone bar operation', array( 'status' => 400 ) );
		}
	}

	/**
	 * Create an abandoned cart coupon manually.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function create_abandoned_cart_coupon( $request ) {
		if ( ! class_exists( 'WC_Coupon' ) ) {
			return new WP_Error( 'woocommerce_missing', esc_html__( 'WooCommerce is not active.', 'automation-web-platform' ), array( 'status' => 400 ) );
		}

		if ( ! class_exists( 'WAWP_Abandoned_Cart_Notifications' ) ) {
			$file_path = WAWP_PLUGIN_DIR . 'includes/abandoned-cart/class-wawp-abandoned-cart-notifications.php';
			if ( file_exists( $file_path ) ) {
				require_once $file_path;
			}
		}

		if ( ! class_exists( 'WAWP_Abandoned_Cart_Notifications' ) ) {
			return new WP_Error( 'notifications_missing', esc_html__( 'Abandoned Cart Notifications class not found.', 'automation-web-platform' ), array( 'status' => 500 ) );
		}

		$params          = $request->get_json_params();
		$coupon_settings = isset( $params['coupon_settings'] ) ? $params['coupon_settings'] : array();

		if ( empty( $coupon_settings ) ) {
			$notif_settings  = $this->get_wawp_setting( WAWP_Settings_Registry::ABANDONED_CART_NOTIFICATIONS_SETTINGS );
			$coupon_settings = isset( $notif_settings['coupon_settings'] ) ? $notif_settings['coupon_settings'] : array();
		}

		$notifications = WAWP_Abandoned_Cart_Notifications::get_instance();
		$coupon_code   = $notifications->generate_coupon_code( 0, $coupon_settings );

		if ( empty( $coupon_code ) ) {
			return new WP_Error( 'generation_failed', esc_html__( 'Failed to generate coupon.', 'automation-web-platform' ), array( 'status' => 500 ) );
		}

		return rest_ensure_response(
			array(
				'success' => true,
				/* translators: %s: Coupon code. */
				'message' => sprintf( esc_html__( 'Coupon generated successfully: %s', 'automation-web-platform' ), $coupon_code ),
				'code'    => $coupon_code,
			)
		);
	}

	/**
	 * Get temporary access links list.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function get_temp_access_links( $request ) {
		unset( $request );
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		global $wpdb;
		$table   = WAWP()->db->tables['temp_access_links'];
		$results = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i ORDER BY created_at DESC', $table ), ARRAY_A );

		$formatted = array();
		foreach ( $results as $row ) {
			// Get Target details.
			$target_display = '';
			if ( 'user' === $row['auth_mode'] ) {
				$user           = get_userdata( intval( $row['target_id'] ) );
				$target_display = $user ? $user->user_login . ' (' . $user->display_name . ')' : '#' . $row['target_id'];
			} else {
				$target_display = ucfirst( $row['target_id'] ) . ' (Temp User)';
			}

			// Check if dynamic user exists.
			$temp_user_exists = false;
			if ( ! empty( $row['temp_user_id'] ) ) {
				$user             = get_userdata( intval( $row['temp_user_id'] ) );
				$temp_user_exists = ! empty( $user );
			}

			// Check if session is currently active.
			$is_session_active = false;
			$check_user_id     = 0;
			if ( 'user' === $row['auth_mode'] ) {
				$check_user_id = intval( $row['target_id'] );
			} else {
				$check_user_id = intval( $row['temp_user_id'] );
			}

			if ( $check_user_id > 0 ) {
				$manager      = WP_Session_Tokens::get_instance( $check_user_id );
				$all_sessions = $manager->get_all();
				if ( is_array( $all_sessions ) ) {
					foreach ( $all_sessions as $sess_data ) {
						if ( isset( $sess_data['wawp_temp_link_id'] ) && intval( $sess_data['wawp_temp_link_id'] ) === intval( $row['id'] ) ) {
							$is_session_active = true;
							break;
						}
					}
				}
			}

			// Update status in real time if expired.
			$status = $row['status'];
			if ( 'active' === $status && strtotime( $row['expires_at'] ) < time() ) {
				$status = 'expired';
				$wpdb->update( $table, array( 'status' => 'expired' ), array( 'id' => $row['id'] ) );
			}

			$formatted[] = array(
				'id'                => intval( $row['id'] ),
				'auth_mode'         => $row['auth_mode'],
				'target_id'         => $row['target_id'],
				'target_display'    => $target_display,
				'label'             => $row['label'],
				'allowed_ip'        => $row['allowed_ip'],
				'allowed_ua'        => $row['allowed_ua'],
				'max_clicks'        => intval( $row['max_clicks'] ),
				'click_count'       => intval( $row['click_count'] ),
				'expires_at'        => $row['expires_at'],
				'temp_user_id'      => intval( $row['temp_user_id'] ),
				'temp_user_exists'  => $temp_user_exists,
				'is_session_active' => $is_session_active,
				'status'            => $status,
				'restrictions'      => ! empty( $row['restrictions'] ) ? json_decode( $row['restrictions'], true ) : array(),
				'fingerprint'       => $row['fingerprint'],
				'created_at'        => $row['created_at'],
			);
		}
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

		return rest_ensure_response(
			array(
				'success' => true,
				'data'    => $formatted,
			)
		);
	}

	/**
	 * Create a temporary access link.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function create_temp_access_link( $request ) {
		global $wpdb;
		$params       = $request->get_json_params();
		$auth_mode    = isset( $params['auth_mode'] ) ? sanitize_text_field( $params['auth_mode'] ) : 'role';
		$target_id    = isset( $params['target_id'] ) ? sanitize_text_field( $params['target_id'] ) : 'administrator';
		$label        = isset( $params['label'] ) ? sanitize_text_field( $params['label'] ) : 'Support Link';
		$duration     = isset( $params['duration'] ) ? intval( $params['duration'] ) : 24; // In hours.
		$max_clicks   = isset( $params['max_clicks'] ) ? intval( $params['max_clicks'] ) : 1;
		$allowed_ip   = isset( $params['allowed_ip'] ) ? sanitize_text_field( $params['allowed_ip'] ) : '';
		$restrictions = isset( $params['restrictions'] ) && is_array( $params['restrictions'] ) ? wp_json_encode( $params['restrictions'] ) : wp_json_encode( array() );

		// Verify role if auth_mode is role.
		if ( 'role' === $auth_mode ) {
			if ( ! function_exists( 'get_editable_roles' ) ) {
				require_once ABSPATH . 'wp-admin/includes/user.php';
			}
			$editable_roles = get_editable_roles();
			if ( ! isset( $editable_roles[ $target_id ] ) ) {
				return new WP_Error( 'invalid_role', esc_html__( 'Selected user role is invalid.', 'automation-web-platform' ), array( 'status' => 400 ) );
			}
		} else {
			// Verify user exists if auth_mode is user.
			$user = get_userdata( intval( $target_id ) );
			if ( ! $user ) {
				return new WP_Error( 'invalid_user', esc_html__( 'Selected user does not exist.', 'automation-web-platform' ), array( 'status' => 400 ) );
			}
		}

		// Generate secure token.
		$token      = wp_generate_password( 32, false );
		$token_hash = hash( 'sha256', $token );
		$expires_at = gmdate( 'Y-m-d H:i:s', time() + $duration * HOUR_IN_SECONDS );
		$table      = WAWP()->db->tables['temp_access_links'];

		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
		$inserted = $wpdb->insert(
			$table,
			array(
				'auth_mode'    => $auth_mode,
				'target_id'    => $target_id,
				'token_hash'   => $token_hash,
				'label'        => $label,
				'allowed_ip'   => ! empty( $allowed_ip ) ? $allowed_ip : null,
				'max_clicks'   => $max_clicks,
				'click_count'  => 0,
				'expires_at'   => $expires_at,
				'temp_user_id' => 0,
				'status'       => 'active',
				'restrictions' => $restrictions,
			),
			array( '%s', '%s', '%s', '%s', '%s', '%d', '%d', '%s', '%d', '%s', '%s' )
		);
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery

		if ( ! $inserted ) {
			return new WP_Error( 'creation_failed', esc_html__( 'Failed to generate database record.', 'automation-web-platform' ), array( 'status' => 500 ) );
		}

		// Return the unhashed token URL. It can only be shown this once!
		$login_url = home_url( '?wawp_temp_login=' . $token );

		return rest_ensure_response(
			array(
				'success'   => true,
				'message'   => esc_html__( 'Temporary access link generated successfully.', 'automation-web-platform' ),
				'login_url' => $login_url,
			)
		);
	}

	/**
	 * Delete a temporary access link.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function delete_temp_access_link( $request ) {
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		global $wpdb;
		$id    = intval( $request->get_param( 'id' ) );
		$table = WAWP()->db->tables['temp_access_links'];

		// Retrieve first to see if there is an active temp user.
		$row = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM %i WHERE id = %d', $table, $id ), ARRAY_A );
		if ( ! $row ) {
			return new WP_Error( 'not_found', esc_html__( 'Link not found.', 'automation-web-platform' ), array( 'status' => 404 ) );
		}

		// If dynamic user was created, force delete it.
		if ( ! empty( $row['temp_user_id'] ) ) {
			require_once ABSPATH . 'wp-admin/includes/user.php';
			require_once ABSPATH . 'wp-admin/includes/post.php';
			require_once ABSPATH . 'wp-admin/includes/comment.php';
			$manager = WP_Session_Tokens::get_instance( intval( $row['temp_user_id'] ) );
			$manager->destroy_all();
			wp_delete_user( intval( $row['temp_user_id'] ) );
		}

		$wpdb->delete( $table, array( 'id' => $id ), array( '%d' ) );
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

		return rest_ensure_response(
			array(
				'success' => true,
				'message' => esc_html__( 'Access link and associated sessions deleted.', 'automation-web-platform' ),
			)
		);
	}

	/**
	 * Revoke a temporary access link.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function revoke_temp_access_link( $request ) {
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		global $wpdb;
		$id    = intval( $request->get_param( 'id' ) );
		$table = WAWP()->db->tables['temp_access_links'];

		$row = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM %i WHERE id = %d', $table, $id ), ARRAY_A );
		if ( ! $row ) {
			return new WP_Error( 'not_found', esc_html__( 'Link not found.', 'automation-web-platform' ), array( 'status' => 404 ) );
		}

		// Force destroy sessions of dynamic user if any.
		if ( ! empty( $row['temp_user_id'] ) ) {
			$manager = WP_Session_Tokens::get_instance( intval( $row['temp_user_id'] ) );
			$manager->destroy_all();
		}

		$wpdb->update( $table, array( 'status' => 'revoked' ), array( 'id' => $id ), array( '%s' ), array( '%d' ) );
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

		return rest_ensure_response(
			array(
				'success' => true,
				'message' => esc_html__( 'Access link has been revoked.', 'automation-web-platform' ),
			)
		);
	}

	/**
	 * Regenerate a temporary access link.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function regenerate_temp_access_link( $request ) {
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		global $wpdb;
		$id    = intval( $request->get_param( 'id' ) );
		$table = WAWP()->db->tables['temp_access_links'];

		$row = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM %i WHERE id = %d', $table, $id ), ARRAY_A );
		if ( ! $row ) {
			return new WP_Error( 'not_found', esc_html__( 'Link not found.', 'automation-web-platform' ), array( 'status' => 404 ) );
		}

		// Cleanup existing dynamic user session/account if any.
		if ( ! empty( $row['temp_user_id'] ) ) {
			require_once ABSPATH . 'wp-admin/includes/user.php';
			require_once ABSPATH . 'wp-admin/includes/post.php';
			require_once ABSPATH . 'wp-admin/includes/comment.php';
			$manager = WP_Session_Tokens::get_instance( intval( $row['temp_user_id'] ) );
			$manager->destroy_all();
			wp_delete_user( intval( $row['temp_user_id'] ) );
		}

		// Calculate original duration.
		$duration_seconds = strtotime( $row['expires_at'] ) - strtotime( $row['created_at'] );
		if ( $duration_seconds <= 0 ) {
			$duration_seconds = 24 * HOUR_IN_SECONDS;
		}

		// Generate new token.
		$token      = wp_generate_password( 32, false );
		$token_hash = hash( 'sha256', $token );
		$expires_at = gmdate( 'Y-m-d H:i:s', time() + $duration_seconds );

		$wpdb->update(
			$table,
			array(
				'token_hash'   => $token_hash,
				'click_count'  => 0,
				'status'       => 'active',
				'expires_at'   => $expires_at,
				'created_at'   => current_time( 'mysql', true ),
				'temp_user_id' => 0,
			),
			array( 'id' => $id ),
			array( '%s', '%d', '%s', '%s', '%s', '%d' ),
			array( '%d' )
		);
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

		$login_url = home_url( '?wawp_temp_login=' . $token );

		return rest_ensure_response(
			array(
				'success'   => true,
				'message'   => esc_html__( 'Temporary access link regenerated successfully.', 'automation-web-platform' ),
				'login_url' => $login_url,
			)
		);
	}

	/**
	 * Get temporary access link logs.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function get_temp_access_logs( $request ) {
		$id   = intval( $request['id'] );
		$logs = get_option( 'wawp_temp_access_logs_' . $id, array() );
		if ( ! is_array( $logs ) ) {
			$logs = array();
		}
		// Reverse logs to show newest first.
		$logs = array_reverse( $logs );
		return rest_ensure_response(
			array(
				'success' => true,
				'data'    => $logs,
			)
		);
	}

	/**
	 * Update temporary access link restrictions.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function update_temp_access_restrictions( $request ) {
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		global $wpdb;
		$id    = intval( $request->get_param( 'id' ) );
		$table = WAWP()->db->tables['temp_access_links'];

		$row = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM %i WHERE id = %d', $table, $id ), ARRAY_A );
		if ( ! $row ) {
			return new WP_Error( 'not_found', esc_html__( 'Link not found.', 'automation-web-platform' ), array( 'status' => 404 ) );
		}

		$params       = $request->get_json_params();
		$restrictions = isset( $params['restrictions'] ) && is_array( $params['restrictions'] ) ? wp_json_encode( $params['restrictions'] ) : wp_json_encode( array() );

		$wpdb->update(
			$table,
			array( 'restrictions' => $restrictions ),
			array( 'id' => $id ),
			array( '%s' ),
			array( '%d' )
		);
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

		return rest_ensure_response(
			array(
				'success' => true,
				'message' => esc_html__( 'Restrictions updated successfully.', 'automation-web-platform' ),
			)
		);
	}

	/**
	 * Terminate an active support session for a temporary access link.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 */
	public function terminate_temp_access_session( $request ) {
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		global $wpdb;
		$id    = intval( $request->get_param( 'id' ) );
		$table = WAWP()->db->tables['temp_access_links'];

		$row = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM %i WHERE id = %d', $table, $id ), ARRAY_A );
		if ( ! $row ) {
			return new WP_Error( 'not_found', esc_html__( 'Link not found.', 'automation-web-platform' ), array( 'status' => 404 ) );
		}

		// Force destroy sessions of dynamic user or targeted user.
		$check_user_id = 0;
		if ( 'user' === $row['auth_mode'] ) {
			$check_user_id = intval( $row['target_id'] );
		} else {
			$check_user_id = intval( $row['temp_user_id'] );
		}

		if ( $check_user_id > 0 ) {
			$manager = WP_Session_Tokens::get_instance( $check_user_id );
			$manager->destroy_all();
		}
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

		return rest_ensure_response(
			array(
				'success' => true,
				'message' => esc_html__( 'Support session has been terminated.', 'automation-web-platform' ),
			)
		);
	}
}
