<?php

namespace Limb_Chatbot\Includes\Api\V1\Controllers;

use Exception;
use Limb_Chatbot\Includes\Data_Objects\Chatbot;
use Limb_Chatbot\Includes\Frontend\Page_Context;
use Limb_Chatbot\Includes\Services\Chatbot_Payload;
use Limb_Chatbot\Includes\Services\Collection;
use Limb_Chatbot\Includes\Services\Data_Object_Collection;
use Limb_Chatbot\Includes\Services\Helper;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

/**
 * Controller for managing Chatbots via REST API.
 *
 * @package Limb_Chatbot\Includes\Api\V1\Controllers
 * @since 1.0.0
 */
class Chatbots_Controller extends Rest_Controller {

	/**
	 * REST route base.
	 *
	 * @var string
	 * @since 1.0.0
	 */
	protected $rest_base = 'chatbot';

	public function __construct() {
		$this->chatbot_payload = new Chatbot_Payload();
	}

	/**
	 * Registers REST routes.
	 *
	 * @since 1.0.0
	 * @return void
	 */
	public function register_routes() {
		register_rest_route( $this->namespace, '/' . $this->rest_base, array(
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_item' ),
				'permission_callback' => array( $this, 'get_items_permissions_check' ),
				'args'                => $this->get_collection_params(),
			),
		) );
	}


	/**
	 * Returns a collection of chatbot items.
	 *
	 * @param  WP_REST_Request  $request REST request object.
	 *
	 * @return WP_REST_Response|WP_Error
	 * @since 1.0.0
	 */
	public function get_item( $request ) {
		try {
			$preview = (bool) $request->get_param( 'preview' );
			if ( $preview && ! current_user_can( 'manage_options' ) ) {
				return new WP_Error( 'forbidden', __( 'Preview is allowed for administrators only.', 'limb-chatbot' ), array( 'status' => 403 ) );
			}

			$chatbot = $this->chatbot_payload->prepare( $preview );

			return rest_ensure_response( $chatbot );
		} catch ( Exception $e ) {
			Helper::log( $e, __METHOD__ );

			return Helper::get_wp_error( $e );
		}
	}

	/**
	 * Prepares a single chatbot item for REST response.
	 *
	 * @param  mixed  $item  The item to prepare. Expected to be an instance of Chatbot.
	 * @param  WP_REST_Request  $request  The full REST request object.
	 *
	 * @return Chatbot|WP_Error The prepared item or WP_Error if item is invalid.
	 *
	 * @throws Exception If the provided item is not an instance of Chatbot.
	 * @since 1.0.0
	 */
	public function prepare_item( $item, $request ) {
		if ( is_a( $item, WP_Error::class ) ) {
			return $item;
		}
		if ( ! is_a( $item, Chatbot::class ) ) {
			throw new Exception( __( 'Unknown item type.', 'limb-chatbot' ) );
		}
		$include = $request->get_param( 'include' );
		if ( ! empty( $include ) && is_array( $include ) ) {
			foreach ( $include as $relation ) {
				if ( method_exists( $item, $relation ) ) {
					$item->included[ $relation ] = $item->{$relation}();
				}
			}
		}

		// Extra manipulations can be made here
		return $item;
	}

	/**
	 * Returns the query parameters for the chatbot collection endpoint.
	 *
	 * These parameters allow filtering and sorting of chatbot results based on UUID,
	 * included relationships, status, or ordering preferences.
	 *
	 * @return array Array of query parameters accepted by the collection route.
	 * @since 1.0.0
	 */
	public function get_collection_params() {
		return array_merge(
			array(
				'include' => array(
					'description' => __( 'Include extra data with chatbot.', 'limb-chatbot' ),
					'type'        => 'array',
				),
				'preview' => array(
					'description' => __( 'Whether to use preview data', 'limb-chatbot' ),
					'type'        => 'boolean',
				),
			)
		);
	}

	/**
	 * Prepares a collection of chatbot items for REST response.
	 *
	 * @param  Collection|array  $collection  The collection of chatbot objects to prepare.
	 * @param  WP_REST_Request  $request  The full REST request object.
	 *
	 * @return Collection The prepared collection with optional enhancements.
	 * @throws Exception
	 * @since 1.0.0
	 */
	public function prepare_collection( $collection, $request ) {
		$collection = parent::prepare_collection( $collection, $request );

		// Get page context from headers if available
		$page_context = $this->get_page_context_from_request( $request );

		// Filter CPT-based chatbots based on page context
		if ( $page_context ) {
			$filtered_items = [];
			foreach ( $collection->get() as $chatbot ) {
				// todo
				if ( $this->should_show_chatbot( $chatbot, $page_context ) ) {
					$filtered_items[] = $chatbot;
				}
			}
			$collection = new Data_Object_Collection( $filtered_items );
		}

		// Handle default chatbot


		return apply_filters( 'lbaic_chatbots_collection_results', $collection, $request );
	}

	/**
	 * Extract page context from request headers.
	 *
	 * @param  WP_REST_Request  $request  The REST request object.
	 *
	 * @return array|null Page context array or null if not available.
	 * @since 1.0.0
	 */
	private function get_page_context_from_request( $request ) {
		$context_header = $request->get_header( 'X-LBAIC-Page-Context' );
		if ( empty( $context_header ) ) {
			return null;
		}

		$context = json_decode( $context_header, true );
		if ( json_last_error() !== JSON_ERROR_NONE ) {
			return null;
		}
		if ( empty( $context['identifier'] ) ) {
			return null;
		}

		return $context;
	}

	/**
	 * Check if a chatbot should be shown based on page context.
	 *
	 * @param  Chatbot  $chatbot  The chatbot object to check.
	 * @param  array  $context  The page context array.
	 *
	 * @return bool True if chatbot should be shown, false otherwise.
	 * @since 1.0.0
	 */
	private function should_show_chatbot( $chatbot, $context ) {
		$show_in = $chatbot->get_parameter('show_in') ?? ['all'];
		$hide_in = $chatbot->get_parameter('hide_in') ?? [];

		// Use Page_Context helper to determine visibility
		return Page_Context::should_show_chatbot( $show_in, $hide_in, $context );
	}

	/**
	 * Checks whether the current user has permission to list chatbot items.
	 *
	 * @param  WP_REST_Request  $request  The REST request being handled.
	 *
	 * @return bool True if the user has permission, false otherwise.
	 * @since 1.0.0
	 */
	public function get_items_permissions_check( $request ) {
		if ( $this->permission_callback( $request ) ) {
			return true;
		}

		return false;
	}

	/**
	 * Checks whether the current user has permission to view a single chatbot item.
	 *
	 * @param  WP_REST_Request  $request  The REST request being handled.
	 *
	 * @return bool True if the user has permission, false otherwise.
	 * @since 1.0.0
	 */
	public function get_item_permissions_check( $request ) {
		if ( $this->permission_callback( $request ) ) {
			return true;
		}

		return false;
	}
}