<?php

namespace Limb_Chatbot\Includes\Api;

use Limb_Chatbot\Includes\Api\V1\Controllers\Rest_Controller;
use Limb_Chatbot\Includes\Services\Chatbot_Parameter_Manager;
use WP_REST_Request;
use WP_REST_Server;


/**
 * Singleton Server class to initialize and register REST API controllers.
 *
 * Handles REST API routes registration and suppresses debug output for JSON responses.
 *
 * @since 1.0.0
 */
class Server {

	/**
	 * The single instance of the class.
	 *
	 * @var self|null
	 * @since 1.0.0
	 */
	private static $_instance = null;

	/**
	 * Array of controller instances.
	 *
	 * @var Rest_Controller[]
	 * @since 1.0.0
	 */
	protected $controllers = [];

	/**
	 * Get the singleton instance of Server.
	 *
	 * @return self Instance of Server.
	 * @since 1.0.0
	 */
	public static function get_instance() {
		if ( is_null( self::$_instance ) ) {
			self::$_instance = new self();
		}

		return self::$_instance;
	}

	/**
	 * Initialize the server: add necessary hooks.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	public function init() {
		add_action( 'rest_api_init', array( $this, 'register_rest_routes' ) );
		add_filter( 'rest_pre_dispatch', array($this, 'inject_flag_params'), 10, 3 );
		add_filter( 'rest_pre_dispatch', array($this, 'disallow_litespeed_cache'), 10, 3 );
		add_filter( 'rest_authentication_errors', array( $this, 'allow_plugin_nonce_route_cookie_auth' ), 99 );

		// Initialize the parameter manager for handling parameter-related services
		Chatbot_Parameter_Manager::instance()->boot();
	}

	/**
	 * Skip core REST cookie/nonce downgrade for GET /plugin/nonce so generate_nonce() runs as the real user.
	 *
	 * @param mixed $result Prior auth result from rest_authentication_errors.
	 *
	 * @return mixed
	 */
	public function allow_plugin_nonce_route_cookie_auth( $result ) {
		if ( ! empty( $result ) ) {
			return $result;
		}
		if ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) {
			return $result;
		}
		if ( ( $_SERVER['REQUEST_METHOD'] ?? '' ) !== 'GET' ) {
			return $result;
		}
		global $wp;
		$route = isset( $wp->query_vars['rest_route'] ) ? (string) $wp->query_vars['rest_route'] : '';
		$route = trim( $route, '/' );
		if ( $route !== 'limb/chatbot/v1/plugin/nonce' ) {
			return $result;
		}

		return true;
	}

	/**
	 * Register REST API routes from all controllers.
	 *
	 * Instantiates each controller class and calls its register_routes() method.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	public function register_rest_routes() {
		foreach ( $this->get_controllers() as $key => $controller ) {
			$this->controllers[ $key ] = new $controller;
			$this->controllers[ $key ]->register_routes();
		}
	}

	/**
	 * Inject from_admin and current_tab flags to requests, to understand from where the request came from
	 *
	 * @param  mixed  $result  Response to replace the requested version with. Can be anything
	 *                                 a normal endpoint can return, or null to not hijack the request.
	 * @param  WP_REST_Server  $server  Server instance.
	 * @param  WP_REST_Request  $request  Request used to generate the response.
	 *
	 * @return mixed
	 */
	public function inject_flag_params( $result, $server, $request ) {
		if ( ! str_contains( $request->get_route(), 'limb/chatbot/v1' ) ) {
			return $result;
		}
		$from_admin = false;
		$referer    = ! empty( $_SERVER['HTTP_REFERER'] ) ? sanitize_url( $_SERVER['HTTP_REFERER'] ) : null;

		if ( current_user_can( 'manage_options' ) && ! empty( $referer ) ) {
			$parsed_path = wp_parse_url( $referer, PHP_URL_PATH );
			// 1. Check where the request came from
			if ( strpos( $parsed_path, '/wp-admin' ) !== false ) {
				$from_admin = true;
			}
			// 2. Inject the tab info
			$parsed_query = wp_parse_url( $referer, PHP_URL_QUERY );
			wp_parse_str( $parsed_query, $query_params );
		}

		$request->set_param( '_from_admin', $from_admin );

		return $result;
	}

	/**
	 * Prevent litespeed caching of our rest routes
	 *
	 * @param  mixed  $result  Response to replace the requested version with. Can be anything
	 *                                 a normal endpoint can return, or null to not hijack the request.
	 * @param  WP_REST_Server  $server  Server instance.
	 * @param  WP_REST_Request  $request  Request used to generate the response.
	 *
	 * @return mixed
	 */
	public function disallow_litespeed_cache( $result, $server, $request ) {
		if ( ! str_contains( $request->get_route(), 'limb/chatbot/v1' ) ) {
			return $result;
		}

		if ( defined( 'LSCWP_V' ) ) {
			do_action( 'litespeed_control_set_nocache', 'Prevent caching Limb AI Chatbot Rest API' );
		}

		return $result;
	}

	/**
	 * Get list of REST API controller class names.
	 *
	 * Can be filtered or extended if needed.
	 *
	 * @return string[] Array of controller class names keyed by route slug.
	 * @since 1.0.0
	 */
	public function get_controllers() {
		// Filtering could be applied here
		return [
			'configs'                    => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Configs_Controller',
			'chats'                      => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Chats_Controller',
			'chatbot_metas'              => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Chatbot_Metas_Controller',
			'chat_messages'              => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Chat_Messages_Controller',
			'vectors'                    => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Vectors_Controller',
			'vector_indexes'             => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Vector_Indexes_Controller',
			'vector_index_metas'         => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Vector_Index_Metas_Controller',
			'settings'                   => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Settings_Controller',
			'datasets'                   => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Datasets_Controller',
			'dataset_entries'            => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Dataset_Entries_Controller',
			'dataset_metas'              => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Dataset_Metas_Controller',
			'models'                     => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\AI_Models_Controller',
			'chatbots'                   => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Chatbots_Controller',
			'chatbot_users'              => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Chatbot_Users_Controller',
			'ip_blocks'                  => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Ip_Blocks_Controller',
			'model_metas'                => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\AI_Model_Metas_Controller',
			'files'                      => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Files_Controller',
			'chat_metas'                 => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Chat_Metas_Controller',
			'plugin'                     => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Plugin_Controller',
			'post_types'                 => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Post_Types_Controller',
			'actions'                    => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Actions_Controller',
			'parameters'                 => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Parameters_Controller',
			'action_callbacks'           => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Action_Callbacks_Controller',
			'action_submissions'         => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Action_Submissions_Controller',
			'leads'                      => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Leads_Controller',
			'lead_fields'                => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Lead_Fields_Controller',
			'jobs'                       => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Jobs_Controller',
			'widgets'                    => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Widgets_Controller',
			'chatbot_analytics'          => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Chatbot_Analytics_Controller',
			'dataset_groups'             => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Dataset_Groups_Controller',
			'admin_notifications'        => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Admin_Notifications_Controller',
			'notification_logs'          => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Notification_Logs_Controller',
			'preview_state'              => 'Limb_Chatbot\\Includes\\Api\\V1\\Controllers\\Preview_State_Controller',
		];
	}
}