<?php

namespace Limb_Chatbot\Includes\Api\V1\Controllers;

use Limb_Chatbot\Includes\Factories\Wp_Object_Repository_Factory;
use Exception;
use Limb_Chatbot\Includes\Repositories\Wp_Object_Group_Repository;
use Limb_Chatbot\Includes\Services\Helper;
use Limb_Chatbot\Includes\Services\Post_Types_Service;
use WP_Error;
use WP_HTTP_Response;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

/**
 * REST Controller for managing post types.
 *
 * Provides endpoints to retrieve posts from custom post types with pagination and search support.
 *
 * @package Limb_Chatbot\Includes\Api\V1\Controllers
 * @since 1.0.0
 */
class Post_Types_Controller extends Rest_Controller {

	/**
	 * REST base route with CPT name parameter.
	 *
	 * @var string
	 * @since 1.0.0
	 */
	protected $rest_base = 'post_types/(?P<cpt_name>[a-zA-Z0-9_-]+)';

	/**
	 * Service instance for post types operations.
	 *
	 * @var Post_Types_Service
	 * @since 1.0.0
	 */
	protected Post_Types_Service $service;

	/**
	 * Post_Types_Controller constructor.
	 *
	 * Initializes the service instance.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
		$this->service = new Post_Types_Service();
	}

	/**
	 * Registers REST API routes for post types.
	 *
	 * Defines routes for retrieving posts from custom post types.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	public function register_routes() {
		register_rest_route( $this->namespace, '/' . $this->rest_base, array(
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_items' ),
				'permission_callback' => array( $this, 'permission_callback' ),
				'args'                => $this->get_collection_params(),
			),
			'schema' => array( $this, 'get_item_schema' ),
		) );
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/count', array(
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'get_filtered_items_count' ),
				'permission_callback' => array( $this, 'permission_callback' ),
				'args'                => $this->get_count_params(),
			),
		) );
		register_rest_route( $this->namespace, '/object_groups', array(
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_groups' ),
				'permission_callback' => array( $this, 'permission_callback' ),
			),
		) );
		register_rest_route( $this->namespace, '/object_groups/(?P<group_name>[a-zA-Z0-9_.-]+)/objects', array(
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_group_objects' ),
				'permission_callback' => array( $this, 'permission_callback' ),
			),
		) );
	}

	/**
	 * Returns query parameters accepted for the collection endpoint.
	 *
	 * Supports page, per_page, and search (s) parameters.
	 *
	 * @return array Query parameter definitions.
	 * @since 1.0.0
	 */
	public function get_collection_params() {
		return array(
			'cpt_name' => array(
				'description'       => __( 'Custom post type name.', 'limb-chatbot' ),
				'type'              => 'string',
				'required'          => true,
				'validate_callback' => function ( $value ) {
					$post_type_obj = get_post_type_object( sanitize_key( $value ) );

					return $post_type_obj !== null;
				},
			),
			'page'     => array(
				'description'       => __( 'Current page of the collection.', 'limb-chatbot' ),
				'type'              => 'integer',
				'default'           => 1,
				'sanitize_callback' => 'absint',
				'validate_callback' => 'rest_validate_request_arg',
			),
			'per_page' => array(
				'description'       => __( 'Maximum number of items to be returned in result set.', 'limb-chatbot' ),
				'type'              => 'integer',
				'default'           => 10,
				'minimum'           => 1,
				'sanitize_callback' => 'absint',
				'validate_callback' => 'rest_validate_request_arg',
			),
			'lbaic_title_search'        => array(
				'description'       => __( 'Limit results to those matching a string.', 'limb-chatbot' ),
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
				'validate_callback' => 'rest_validate_request_arg',
			),
			'orderby'  => array(
				'description'       => __( 'Sort the collection by attribute.', 'limb-chatbot' ),
				'type'              => 'string',
				'default'           => 'modified',
				'enum'              => array( 'date', 'title', 'modified', 'id', 'author' ),
				'sanitize_callback' => 'sanitize_key',
				'validate_callback' => 'rest_validate_request_arg',
			),
			'order'    => array(
				'description'       => __( 'Order sort attribute ascending or descending.', 'limb-chatbot' ),
				'type'              => 'string',
				'default'           => 'DESC',
				'enum'              => array( 'ASC', 'DESC', 'asc', 'desc' ),
				'sanitize_callback' => function ( $value ) {
					return strtoupper( $value );
				},
				'validate_callback' => 'rest_validate_request_arg',
			),
			'include'   => array(
				'description'       => __( 'Include additional data. Integrations can hook into this to provide additional properties.', 'limb-chatbot' ),
				'type'              => 'array',
				'validate_callback' => 'rest_validate_request_arg',
			),
		);
	}

	/**
	 * Returns parameters accepted for filtered count endpoint.
	 *
	 * @return array
	 * @since 1.0.0
	 */
	public function get_count_params() {
		return array(
			'cpt_name' => array(
				'description'       => __( 'Custom post type name.', 'limb-chatbot' ),
				'type'              => 'string',
				'required'          => true,
				'validate_callback' => function ( $value ) {
					$post_type_obj = get_post_type_object( sanitize_key( $value ) );

					return $post_type_obj !== null;
				},
			),
			'filters'  => array(
				'description'       => __( 'Filter payload for taxonomy, meta fields, and authors.', 'limb-chatbot' ),
				'type'              => 'object',
				'required'          => false,
				'validate_callback' => 'rest_validate_request_arg',
			),
		);
	}

	/**
	 * Returns JSON schema for a post item.
	 *
	 * Defines structure and validation rules for post resource.
	 *
	 * @return array JSON schema array.
	 * @since 1.0.0
	 */
	public function get_item_schema() {
		if ( $this->schema ) {
			return $this->schema;
		}

		$this->schema = array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'Post',
			'type'       => 'object',
			'properties' => array(
				'id'           => array(
					'description' => __( 'Unique identifier for the post.', 'limb-chatbot' ),
					'type'        => 'integer',
					'context'     => array( 'view' ),
					'readonly'    => true,
				),
				'title'        => array(
					'description' => __( 'Post title.', 'limb-chatbot' ),
					'type'        => 'string',
					'context'     => array( 'view' ),
				),
				'link'         => array(
					'description' => __( 'Post permalink.', 'limb-chatbot' ),
					'type'        => 'string',
					'format'      => 'uri',
					'context'     => array( 'view' ),
				),
				'modified_gmt' => array(
					'description' => __( 'Post modified date in GMT.', 'limb-chatbot' ),
					'type'        => 'string',
					'format'      => 'date-time',
					'context'     => array( 'view' ),
				),
			)
		);

		return $this->schema;
	}

	/**
	 * Retrieves a collection of posts from a custom post type.
	 *
	 * @param  WP_REST_Request  $request  Incoming REST request.
	 *
	 * @return WP_REST_Response|WP_Error REST response or error.
	 * @since 1.0.0
	 */
	public function get_items( $request ) {
		try {
			$cpt_name = $request->get_param( 'cpt_name' );
			$params   = $request->get_query_params();
			$posts    = $this->service->get_posts( $cpt_name, $params );
			$response = $this->set_pagination_params( $posts, $request );

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

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

	/**
	 * Returns count of posts matching structured filters for a given post type.
	 *
	 * @param  WP_REST_Request  $request  Incoming REST request.
	 *
	 * @return WP_REST_Response|WP_Error
	 * @since 1.0.0
	 */
	public function get_filtered_items_count( WP_REST_Request $request ) {
		try {
			$cpt_name = sanitize_key( (string) $request->get_param( 'cpt_name' ) );
			$payload  = (array) $request->get_json_params();
			$filters  = isset( $payload['filters'] ) && is_array( $payload['filters'] ) ? $payload['filters'] : [];
			$count    = $this->service->get_filtered_posts_count( $cpt_name, $filters );

			return rest_ensure_response( [ 'count' => $count ] );
		} catch ( Exception $e ) {
			Helper::log( $e, __METHOD__ );

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

	/**
	 * Retrieves all available page context options.
	 *
	 * This endpoint returns all possible values that can be used in show_in/hide_in
	 * settings for chatbots. The options are grouped by type (Global, Special Pages,
	 * Post Types, Taxonomies) with optgroup labels.
	 *
	 * Includes both generic options (e.g., "All Posts") and specific items
	 * (e.g., "Post: Hello World (ID: 123)").
	 *
	 * @param  WP_REST_Request  $request  Incoming REST request.
	 *
	 * @return WP_REST_Response|WP_Error REST response or error.
	 * @since 1.0.0
	 */
	public function get_groups( WP_REST_Request $request ) {
		try {
			$params = $request->get_params();
			$groups = ( new Wp_Object_Group_Repository() )->get_items($params);

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

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

	/**
	 * Retrieve list of items
	 *
	 * @param $request
	 *
	 * @return WP_Error|WP_HTTP_Response|WP_REST_Response
	 */
	public function get_group_objects( $request ) {
		try {
			$params            = $request->get_params();
			$group_name        = ! empty( $params['group_name'] ) ? sanitize_text_field( $params['group_name'] ) : '';
			$search            = ! empty( $params['s'] ) ? sanitize_text_field( $params['s'] ) : '';
			$per_page          = ! empty( $params['per_page'] ) ? (int) $params['per_page'] : 10;
			$page              = ! empty( $params['page'] ) ? (int) $params['page'] : 1;
			$object_repository = ( new Wp_Object_Repository_Factory() )->make( $group_name );

			if ( ! $object_repository ) {
				throw new Exception( __( 'Invalid group name', 'limb-chatbot' ) );
			}

			// Fetch and return the object groups based on the provided parameters
			// Returns Data_Object_Collection with items, total, page, per_page, total_pages
			$objects_collection = $object_repository->get_items( $group_name, $search, $per_page, $page );

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

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

