<?php

namespace Limb_Chatbot\Includes\Api\V1\Controllers;

use Exception;
use Limb_Chatbot\Includes\Data_Objects\AI_Model;
use Limb_Chatbot\Includes\Data_Objects\AI_Model_Meta;
use Limb_Chatbot\Includes\Repositories\AI_Model_Meta_Repository;
use Limb_Chatbot\Includes\Services\Helper;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

/**
 * REST API Controller for managing AI Model Metas.
 *
 * Handles retrieval, batch creation, and batch updating of AI Model Meta resources.
 *
 * @package Limb_Chatbot\Includes\Api\V1\Controllers
 * @since 1.0.0
 */
class AI_Model_Metas_Controller extends Rest_Controller {

	/**
	 * REST base route including AI model ID.
	 *
	 * @since 1.0.0
	 * @var string
	 */
	protected $rest_base = 'models/(?P<ai_model_id>[\d]+)/metas';

	/**
	 * Repository instance for AI Model Meta data operations.
	 *
	 * @since 1.0.0
	 * @var AI_Model_Meta_Repository
	 */
	protected AI_Model_Meta_Repository $repository;

	/**
	 * Constructor.
	 *
	 * Initializes the AI Model Meta repository.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
		$this->repository = new AI_Model_Meta_Repository();
	}

	/**
	 * Registers REST API routes for AI Model Meta endpoints.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function register_routes(): void {
		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'                => array_merge( $this->get_model_id_arg() ),
			),
		) );
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<meta_key>[a-zA-Z0-9._-])', array(
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_item' ),
				'permission_callback' => array( $this, 'permission_callback' ),
				'args'                => array_merge( $this->get_model_id_arg(), $this->get_meta_key_arg() ),
			),
			'schema' => array( $this, 'get_item_schema' ),
		) );
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array(
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'batch_create_items' ),
				'permission_callback' => array( $this, 'permission_callback' ),
				'args'                => $this->get_model_id_arg(),
			),
			array(
				'methods'             => WP_REST_Server::EDITABLE,
				'callback'            => array( $this, 'batch_update_items' ),
				'permission_callback' => array( $this, 'permission_callback' ),
				'args'                => $this->get_model_id_arg(),
			),
		) );
	}

	/**
	 * Defines and returns the argument specification for AI model ID.
	 *
	 * Validates that the AI model exists.
	 *
	 * @since 1.0.0
	 *
	 * @return array Argument specification for 'ai_model_id'.
	 */
	private function get_model_id_arg(): array {
		return array(
			'ai_model_id' => array(
				'type'              => 'integer',
				'validate_callback' => function ( $value, $request, $param ) {
					return ! empty( AI_Model::find( $value ) );
				}
			)
		);
	}

	/**
	 * Defines and returns the argument specification for meta key.
	 *
	 * Specifies the meta key as a required string.
	 *
	 * @since 1.0.0
	 *
	 * @return array Argument specification for 'meta_key'.
	 */
	private function get_meta_key_arg(): array {
		return array(
			'meta_key' => array(
				'type'     => 'string',
				'required' => true,
			)
		);
	}

	/**
	 * Retrieves a collection of AI Model Meta items matching the request parameters.
	 *
	 * @param  WP_REST_Request  $request  The REST request object.
	 *
	 * @return WP_REST_Response|WP_Error REST response with collection or error.
	 * @since 1.0.0
	 */
	public function get_items( $request ) {
		try {
			return rest_ensure_response( AI_Model_Meta::where( $request->get_query_params() + [ 'ai_model_id' => $request->get_param( 'ai_model_id' ) ] )->get() );
		} catch ( Exception $e ) {
			Helper::log( $e, __METHOD__ );

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

	/**
	 * Handles batch creation of AI Model Meta items.
	 *
	 * Validates incoming data and creates meta items in batch.
	 *
	 * @param WP_REST_Request $request  The REST request object.
	 *
	 * @return WP_REST_Response|WP_Error REST response with created items or error.
	 *@since 1.0.0
	 *
	 */
	public function batch_create_items( $request ) {
		try {
			$items = $request->get_json_params();
			$error = $this->validate_batch_items( $items, $this->get_item_schema()['properties'] );
			if ( is_wp_error( $error ) ) {
				return $error;
			}

			return rest_ensure_response( $this->repository->batch_create( $items, $request->get_param( 'ai_model_id' ) ) );
		} catch ( Exception $e ) {
			Helper::log( $e, __METHOD__ );

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

	/**
	 * Handles batch updating of AI Model Meta items.
	 *
	 * Validates incoming data and updates meta items in batch.
	 *
	 * @param WP_REST_Request $request  The REST request object.
	 *
	 * @return WP_REST_Response|WP_Error REST response with updated items or error.
	 *@since 1.0.0
	 *
	 */
	public function batch_update_items( $request ) {
		try {
			$items = $request->get_json_params();
			$error = $this->validate_batch_items( $items, $this->get_item_schema()['properties'] );
			if ( is_wp_error( $error ) ) {
				return $error;
			}

			return rest_ensure_response( $this->repository->batch_update( $items, $request->get_param( 'ai_model_id' ) ) );
		} catch ( Exception $e ) {
			Helper::log( $e, __METHOD__ );

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

	/**
	 * Returns the JSON schema for AI Model Meta resources.
	 *
	 * Used for validating and documenting the REST API schema.
	 *
	 * @since 1.0.0
	 *
	 * @return array JSON schema for AI Model Meta.
	 */
	public function get_item_schema(): array {
		if ( $this->schema ) {
			// Since WordPress 5.3, the schema can be cached in the $schema property.
			return $this->schema;
		}
		$this->schema = array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'AI_Model Meta',
			'type'       => 'object',
			'properties' => array(
				'id'          => array(
					'description'       => __( 'Unique identifier for the resource.', 'limb-chatbot' ),
					'type'              => 'integer',
					'context'           => array( 'view', 'edit' ),
					'readonly'          => true,
					'sanitize_callback' => 'absint',
				),
				'ai_model_id' => array(
					'description' => __( 'The model id.', 'limb-chatbot' ),
					'type'        => 'integer',
					'context'     => array( 'view', 'edit' ),
					'arg_options' => array(
						'validate_callback' => function ( $param ) {
							return ! empty( AI_Model::find( $param ) );
						}
					)
				),
				'meta_key'    => array(
					'description'       => __( 'Key of the resource', 'limb-chatbot' ),
					'type'              => 'string',
					'required'          => true,
					'sanitize_callback' => 'sanitize_key',
				),
				'meta_value'  => array(
					'description' => __( 'Value of the resource', 'limb-chatbot' ),
					'type'        => array( 'string', 'integer', 'array' ),
					'required'    => true,
					'arg_options' => array(
						'validate_callback' => array( $this, 'validate_meta_value' ),
					)
				)
			),
		);

		return $this->schema;
	}

	/**
	 * Validates the meta_value parameter.
	 *
	 * Ensures the value is non-empty and of type string, int, or array.
	 *
	 * @param mixed             $value   Value to validate.
	 * @param WP_REST_Request  $request  The REST request object.
	 * @param string            $param   Parameter name.
	 *
	 * @return bool True if valid; false otherwise.
	 * @since 1.0.0
	 */
	public function validate_meta_value( $value, $request, $param ) {
		if ( empty( $value ) ) {
			return false;
		}
		if ( ! is_string( $value ) && ! is_int( $value ) && ! is_array( $value ) ) {
			return false;
		}

		return true;
	}
}