<?php
/**
 * Public AJAX route registry for WebRTC widget endpoints.
 *
 * Centralizes endpoint ownership and prevents duplicate callback registration
 * across SiteStaffr_Widget and SiteStaffr_Button_Widget.
 *
 * @package    SiteStaffr
 * @subpackage SiteStaffr/public
 * @since      0.14.256
 */

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

/**
 * Public AJAX router.
 *
 * Registers shared endpoints once and supports explicit button aliases.
 */
class SiteStaffr_Public_Ajax_Router {

	/**
	 * Whether shared AJAX routes have been registered.
	 *
	 * @var bool
	 */
	private static $shared_registered = false;

	/**
	 * Register shared public AJAX handlers once.
	 *
	 * @param object $owner Handler owner object (widget or button widget).
	 * @return void
	 */
	public static function register_shared_handlers( $owner ) {
		if ( self::$shared_registered ) {
			return;
		}

		self::register_route_pair( 'sitestaffr_get_token', $owner, 'ajax_get_token' );
		self::register_route_pair( 'sitestaffr_get_realtime_session', $owner, 'ajax_get_realtime_session' );
		self::register_route_pair( 'sitestaffr_webrtc_session', $owner, 'ajax_webrtc_session' );
		self::register_route_pair( 'sitestaffr_save_conversation', $owner, 'ajax_save_conversation' );
		self::register_route_pair( 'sitestaffr_finalize_usage', $owner, 'ajax_finalize_usage' );

		// Text chat streaming proxy (static handler — no widget instance needed).
		require_once SITESTAFFR_PLUGIN_DIR . 'public/modules/class-sitestaffr-chat-message-handler.php';
		self::register_static_route_pair( 'sitestaffr_chat_message', 'SiteStaffr_Chat_Message_Handler', 'ajax_chat_message' );

		// Knowledge search relay for voice RAG (browser DataChannel → WP AJAX → middleware embed → local search).
		require_once SITESTAFFR_PLUGIN_DIR . 'public/modules/class-sitestaffr-knowledge-search-handler.php';
		self::register_static_route_pair( 'sitestaffr_knowledge_search', 'SiteStaffr_Knowledge_Search_Handler', 'ajax_knowledge_search' );

		// Nonce refresh — returns fresh nonces for page-cached environments (LiteSpeed, etc.).
		add_action( 'wp_ajax_sitestaffr_refresh_nonces', array( __CLASS__, 'ajax_refresh_nonces' ) );
		add_action( 'wp_ajax_nopriv_sitestaffr_refresh_nonces', array( __CLASS__, 'ajax_refresh_nonces' ) );

		self::$shared_registered = true;
	}

	/**
	 * Register button-only alias endpoints.
	 *
	 * @param object $owner Button widget owner instance.
	 * @return void
	 */
	public static function register_button_alias_handlers( $owner ) {
		self::register_route_pair( 'sitestaffr_button_save_conversation', $owner, 'ajax_save_conversation' );
		self::register_route_pair( 'sitestaffr_button_finalize_usage', $owner, 'ajax_finalize_usage' );
	}

	/**
	 * Register a logged-in and nopriv route pair for one action.
	 *
	 * @param string $action   AJAX action slug.
	 * @param object $owner    Callback owner object.
	 * @param string $method   Callback method name.
	 * @return void
	 */
	private static function register_route_pair( $action, $owner, $method ) {
		if ( ! is_object( $owner ) || ! method_exists( $owner, $method ) ) {
			return;
		}

		add_action( 'wp_ajax_' . $action, array( $owner, $method ) );
		add_action( 'wp_ajax_nopriv_' . $action, array( $owner, $method ) );
	}

	/**
	 * Return fresh nonces for page-cached environments.
	 *
	 * Page caching (LiteSpeed, Cloudflare, etc.) serves stale nonces embedded
	 * by wp_localize_script. This endpoint lets the JS fetch fresh ones before
	 * the first interaction. No nonce verification here — generating nonces is
	 * safe (they're per-session and only valid for the current user/visitor).
	 *
	 * @since 1.6.0
	 * @return void
	 */
	public static function ajax_refresh_nonces() {
		wp_send_json_success( array(
			'token_nonce'    => wp_create_nonce( 'sitestaffr_widget_token' ),
			'save_nonce'     => wp_create_nonce( 'sitestaffr_save_conversation' ),
			'finalize_nonce' => wp_create_nonce( 'sitestaffr_finalize_usage' ),
			'webrtc_nonce'   => wp_create_nonce( 'sitestaffr_webrtc_session' ),
			'realtime_nonce' => wp_create_nonce( 'sitestaffr_realtime_session' ),
			'chat_nonce'              => wp_create_nonce( 'sitestaffr_chat_message' ),
			'knowledge_search_nonce' => wp_create_nonce( 'sitestaffr_knowledge_search' ),
		) );
	}

	/**
	 * Register a logged-in and nopriv route pair for a static class method.
	 *
	 * @param string $action     AJAX action slug.
	 * @param string $class_name Fully qualified class name.
	 * @param string $method     Static method name.
	 * @return void
	 */
	private static function register_static_route_pair( $action, $class_name, $method ) {
		if ( ! class_exists( $class_name ) || ! method_exists( $class_name, $method ) ) {
			return;
		}

		add_action( 'wp_ajax_' . $action, array( $class_name, $method ) );
		add_action( 'wp_ajax_nopriv_' . $action, array( $class_name, $method ) );
	}
}

