<?php
/**
 * FE Admin Orders controller.
 *
 * @since 1.0
 * @since 1.4 Event authorization restriction
 */

declare( strict_types=1 );
namespace FeData\FastEvents\RestAPI\Public;

defined( 'ABSPATH' ) || exit;

use Exception;
use FeData\FastEvents\Helpers\AuthHelper;
use FeData\FastEvents\Helpers\EventsHelper;
use FeData\FastEvents\Helpers\OrderHelper;
use FeData\FastEvents\Storage\PluginSettings;
use FeData\FastEvents\Utilities\JsonUtil;
use FeData\FastEvents\Utilities\WebhookUtil;
use PHPCSStandards\Composer\Plugin\Installers\PHPCodeSniffer\Plugin;
use stdClass;
use WP_Error;
use WP_REST_Controller;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;


/**
 * FE Admin Orders class.
 */
class OrdersController extends WP_REST_Controller {


	/**
	 * Admin Orders constructor.
	 *
	 * @param AuthHelper     $auth The auth helper.
	 * @param PluginSettings $settings The plugin settings.
	 *
	 * @since 1.0
	 */
	public function __construct(
		private readonly AuthHelper $auth,
		private readonly PluginSettings $settings,
	) {
		$this->namespace = 'fast-events/v1';
		$this->rest_base = 'admin/orders';
	}


	/**
	 * Register the routes for the objects of the controller.
	 *
	 * @since 1.0
	 * @since 2.0 Refactored for a new permission system
	 */
	public function register_routes(): void {

		// Get orders.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base,
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_items' ),
					'permission_callback' => function () {
						return $this->fast_events_admin_permissions( $this->auth::ORDER_READ );
					},
					'args'                => $this->get_collection_params(),
				),
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'create_item' ),
					'permission_callback' => function () {
						return $this->fast_events_admin_permissions( $this->auth::ORDER_ADD );
					},
					'args'                => $this->get_endpoint_args_for_item_schema(),
				),
				'schema' => array( $this, 'get_public_item_schema' ),
			)
		);

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/(?P<id>[\d]+)',
			array(
				'args'   => array(
					'id' => array(
						'description'       => __( 'The unique id of the order', 'fast-events' ),
						'type'              => 'integer',
						'required'          => true,
						'sanitize_callback' => 'absint',
					),
				),
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_item' ),
					'permission_callback' => function () {
						return $this->fast_events_admin_permissions( $this->auth::ORDER_READ );
					},
					'args'                => array(
						'context' => $this->get_context_param( array( 'default' => 'view' ) ),
					),
				),
				array(
					'methods'             => WP_REST_Server::EDITABLE,
					'callback'            => array( $this, 'update_item' ),
					'permission_callback' => function () {
						return $this->fast_events_admin_permissions( $this->auth::ORDER_UPDATE );
					},
					'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
				),
				array(
					'methods'             => WP_REST_Server::DELETABLE,
					'callback'            => array( $this, 'delete_item' ),
					'permission_callback' => function () {
						return $this->fast_events_admin_permissions( $this->auth::ORDER_DELETE );
					},
				),
				'schema' => array( $this, 'get_public_item_schema' ),
			)
		);
	}


	/**
	 * Get the authorisation for the Orders endpoints.
	 *
	 * @param int $action The action on the controller.
	 * @return WP_Error|bool
	 *
	 * @since 1.0
	 * @since 2.0 Refactored for a new permission system
	 */
	public function fast_events_admin_permissions( int $action ): WP_Error|bool {
		return $this->auth->authorize( $action );
	}


	/**
	 * Get multiple orders.
	 *
	 * @param WP_REST_Request $request Request instance.
	 * @return WP_REST_Response|WP_Error
	 *
	 * @since 1.0
	 * @since 1.4 Event authorization restriction
	 */
	public function get_items( $request ): WP_Error|WP_REST_Response {
		global $wpdb;

		// Look up the orders.
		$order_table = $wpdb->prefix . 'fe_event_orders';

		// Get selected events.
		$where = '';
		if ( ! empty( $request['event_id'] ) ) {
			$where .= 'WHERE event_id IN (' . implode( ',', $request['event_id'] ) . ')';
		} else {
			$where .= 'WHERE event_id>0';
		}

		// Only the authorized events.
		$auth_query = $this->auth->get_restricted_events( $this->auth::FAST_EVENTS_AUTH_QUERY_ORDER_LOOKUP );
		$where     .= empty( $auth_query ) ? '' : $auth_query;

		// Include specific order ids.
		if ( ! empty( $request['include'] ) ) {
			$where .= ' AND id IN (' . implode( ',', $request['include'] ) . ')';
		}

		// Exclude specific order ids.
		if ( ! empty( $request['exclude'] ) ) {
			$where .= ' AND id NOT IN (' . implode( ',', $request['exclude'] ) . ')';
		}

		// Include a possible search clause.
		if ( ! empty( $request['search'] ) ) {
			$where .= " AND email LIKE '%%" . $request['search'] . "%%'";
		}

		// Get the sort-order.
		$order = ' ORDER BY ' . $request['orderby'] . ' ' . $request['order'];

		// Set pagination.
		$limit = 'LIMIT ' . $request['per_page'] . ' OFFSET ';
		if ( ! empty( $request['offset'] ) ) {
			$limit .= $request['offset'];
			$offset = $request['offset'];
		} else {
			$limit .= ( $request['page'] - 1 ) * $request['per_page'];
			$offset = ( $request['page'] - 1 ) * $request['per_page'];
		}

		$result = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $order_table $where $order $limit" ) ); // phpcs:ignore
		if ( empty( $result ) ) {
			return new WP_Error( 'no_orders_found', __( 'No orders found', 'fast-events' ), array( 'status' => 404 ) );
		}

		$orders = array();

		foreach ( $result as $order ) {
			$data     = $this->prepare_item_for_response( $order, $request );
			$orders[] = $this->prepare_response_for_collection( $data );
		}

		$response = rest_ensure_response( $orders );

		// Generate the totals headers.
		$per_page     = (int) $request['per_page'];
		$page         = (int) ceil( ( $offset / $per_page ) + 1 );
		$total_orders = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $order_table $where" ) ); // phpcs:ignore

		$max_pages = ceil( (int) $total_orders / $per_page );
		$response->header( 'X-WP-Total', (int) $total_orders );
		$response->header( 'X-WP-TotalPages', ceil( (int) $max_pages ) );

		$base = add_query_arg( urlencode_deep( $request->get_query_params() ), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) );
		if ( $page > 1 ) {
			$prev_page = $page - 1;

			if ( $prev_page > $max_pages ) {
				$prev_page = $max_pages;
			}

			$prev_link = add_query_arg( 'page', $prev_page, $base );
			$response->link_header( 'prev', $prev_link );
		}
		if ( $max_pages > $page ) {
			$next_page = $page + 1;
			$next_link = add_query_arg( 'page', $next_page, $base );

			$response->link_header( 'next', $next_link );
		}

		return $response;
	}


	/**
	 * Retrieve a single order.
	 *
	 * @param WP_REST_Request $request Full details about the request.
	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
	 *
	 * @since 1.0
	 * @since 1.4 Event authorization restriction
	 */
	public function get_item( $request ): WP_Error|WP_REST_Response {
		global $wpdb;

		// Look up the order.
		$order = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}fe_event_orders WHERE id = %d" .
				$this->auth->get_restricted_events( $this->auth::FAST_EVENTS_AUTH_QUERY_ORDER_LOOKUP ), // phpcs:ignore
				$request['id']
			)
		);
		if ( empty( $order ) ) {
			return new WP_Error( 'not_found', __( 'Order not found', 'fast-events' ), array( 'status' => 404 ) );
		}

		return rest_ensure_response( $this->prepare_item_for_response( $order, $request ) );
	}


	/**
	 * Create a new order.
	 *
	 * @since 1.0
	 * @since 1.4.0 - Event authorization restriction
	 *              - group_type needs to be 0
	 * @since 1.9.2 Added type 'object' for patterProperties
	 * @since 2.2.0 Added coupons and different event_info structure
	 * @since 2.3.0 Use fast_events_json_encode.
	 *
	 * @param WP_REST_Request $request Full details about the request.
	 *
	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
	 * @throws Exception Ignored.
	 */
	public function create_item( $request ): WP_Error|WP_REST_Response {
		global $wpdb;
		global $fevt_container;

		// Check the event authorization.
		$resp = $this->auth->check_event_authorization( absint( $request['event_id'] ) );
		if ( is_wp_error( $resp ) ) {
			return $resp;
		}

		// Look up the event.
		$event = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT id, event_type, group_type, event_group, terms, recaptcha_needed, coupons_needed, input_fields FROM {$wpdb->prefix}fe_events WHERE id = %d",
				$request['event_id']
			)
		);
		if ( empty( $event ) ) {
			return new WP_Error( 'not_found', __( 'Event not found', 'fast-events' ), array( 'status' => 404 ) );
		}

		// Event info structure which is used for the nonce.
		$event_info   = array();
		$input_fields = JsonUtil::get_input_fields( $event->input_fields );
		$extra_input  = array();
		foreach ( $input_fields->fields as $field ) {
			if ( 0 === $field->personalise ) { // Only the non-personalised input is allowed.
				$extra_input[] = $field;
			}
		}
		$ticket_types = array();
		foreach ( $input_fields->tickets as $ticket ) {
			$tmp                 = array();
			$tmp['id']           = $ticket->id;
			$tmp['price']        = $ticket->price;
			$tmp['volume_price'] = $ticket->volume_price ?? array();
			$tmp['min']          = $ticket->min;
			$tmp['max']          = $ticket->max;
			$ticket_types[]      = $tmp;
		}
		$event_info[ $event->id ] = array(
			'extra_input'  => $extra_input,
			'ticket_types' => $ticket_types,
			'terms'        => empty( $event->terms ) ? 0 : 1,
			'coupons'      => $event->coupons_needed ? 1 : 0,
			'recaptcha'    => $event->recaptcha_needed ? 1 : 0,
			'event_type'   => (int) $event->event_type,
			'group_type'   => (int) $event->group_type,
			'event_group'  => $event->event_group,
		);

		// Set the nonce and hidden fields.
		$event_info_string = JsonUtil::fast_events_json_encode( $event_info );
		$nonce             = 'event_nonce_value' . $event_info_string;

		// Add extra fields, so we can use the common add order function.
		$request->set_param( 'event_nonce', wp_create_nonce( $nonce ) );
		$request->set_param( 'event_info', $event_info_string );

		// Add extra input values.
		foreach ( $request['fields'] as $item ) {
			foreach ( $item as $key => $value ) {
				$request->set_param( 'e' . $request['event_id'] . $key, $value );
			}
		}

		// Add ticket values.
		foreach ( $request['tickets'] as $item ) {
			foreach ( $item as $key => $value ) {
				$request->set_param( 'e' . $request['event_id'] . $key, $value );
			}
		}

		$result = $fevt_container->get( OrderHelper::class )->new_dashboard_order( $request );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		// Return the new order via the 'orders' endpoint.
		$route = '/fast-events/v1/admin/orders/' . $fevt_container->get( EventsHelper::class )->get_order_ids()[0];
		return rest_ensure_response( rest_do_request( new WP_REST_Request( 'GET', $route ) ) );
	}


	/**
	 * Update a single order.
	 *
	 * @param WP_REST_Request $request Full details about the request.
	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
	 *
	 * @since 1.0
	 * @since 1.4 Event authorization restriction
	 */
	public function update_item( $request ): WP_Error|WP_REST_Response {
		global $wpdb;

		// Look up the order.
		$order_table = $wpdb->prefix . 'fe_event_orders';
		$event_table = $wpdb->prefix . 'fe_events';
		// phpcs:disable
		$order       = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT $order_table.id, $order_table.id, $order_table.name, $order_table.email, $order_table.custom_status, $event_table.webhooks_needed  " .
				"FROM $order_table " .
				"INNER JOIN $event_table ON $event_table.id = $order_table.event_id " .
				"WHERE $order_table.id = %d" .
				$this->auth->get_restricted_events( $this->auth::FAST_EVENTS_AUTH_QUERY_ORDERS, $event_table ),
				$request['id']
			)
		);
		// phpcs:enable
		if ( empty( $order ) ) {
			return new WP_Error( 'not_found', __( 'Order not found', 'fast-events' ), array( 'status' => 404 ) );
		}

		$changed_order = array();

		// Did the name change?
		if ( isset( $request['name'] ) && $order->name !== $request['name'] ) {
			$changed_order['name'] = $request['name'];
			$order->name           = $request['name'];
		}

		// Did the emailaddress change?
		if ( isset( $request['email'] ) && $order->email !== $request['email'] ) {
			$changed_order['email'] = $request['email'];
			$order->email           = $request['email'];
		}

		// Did the custom status change?
		if ( isset( $request['custom_status'] ) && $order->custom_status !== $request['custom_status'] ) {
			$changed_order['custom_status'] = $request['custom_status'];
			$order->custom_status           = $request['custom_status'];
		}

		if ( empty( $changed_order ) ) {
			return new WP_Error( 'no_changes', __( 'No changes found', 'fast-events' ), array( 'status' => 400 ) );
		}

		// Update the data.
		$result = $wpdb->update( $order_table, $changed_order, array( 'id' => $request['id'] ) );

		// Analyse the update.
		if ( false === $result ) {
			return new WP_Error( 'failed', __( 'Order update failed: ', 'fast-events' ) . $wpdb->last_error, array( 'status' => 400 ) );
		}
		if ( 0 === $result ) {
			return new WP_Error( 'nothing_to_update', __( 'Order update: nothing to update', 'fast-events' ), array( 'status' => 400 ) );
		}

		// Fire webhook if needed.
		if ( 1 === (int) $order->webhooks_needed ) {
			WebhookUtil::create_webhook( 'order.updated', (int) $request['id'] );
		}

		$request->set_param( 'context', 'edit' );

		return rest_ensure_response( $this->prepare_item_for_response( $order, $request ) );
	}


	/**
	 * Delete a single order.
	 *
	 * @param WP_REST_Request $request Full details about the request.
	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
	 *
	 * @since 1.0
	 * @since 1.4 Event authorization restriction
	 */
	public function delete_item( $request ): WP_Error|WP_REST_Response {
		global $wpdb;
		global $fevt_container;

		// Look up the order.
		$order = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}fe_event_orders WHERE id = %d" .
				$this->auth->get_restricted_events( $this->auth::FAST_EVENTS_AUTH_QUERY_ORDER_LOOKUP ), // phpcs:ignore
				$request['id']
			)
		);
		if ( empty( $order ) ) {
			return new WP_Error( 'not_found', __( 'Order not found', 'fast-events' ), array( 'status' => 404 ) );
		}

		// Delete the data (Webhooks are scheduled in the helper).
		$result = $fevt_container->get( OrderHelper::class )->order_delete( $request['id'] );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		$request->set_param( 'context', 'edit' );

		$previous = $this->prepare_item_for_response( $order, $request );

		$response = new WP_REST_Response();
		$response->set_data(
			array(
				'deleted'  => true,
				'previous' => $previous->get_data(),
			)
		);

		return $response;
	}


	/**
	 * Prepares a single order output for response.
	 *
	 * @param mixed           $item    Order object.
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 *
	 * @since 1.0
	 * @since 2.2.0 Added 'discount' field.
	 */
	public function prepare_item_for_response( $item, $request ): WP_REST_Response {

		$data   = array();
		$fields = $this->get_fields_for_response( $request );

		if ( rest_is_field_included( 'id', $fields ) ) {
			$data['id'] = (int) $item->id;
		}

		if ( rest_is_field_included( 'event_id', $fields ) ) {
			$data['event_id'] = (int) $item->event_id;
		}

		if ( rest_is_field_included( 'event_date', $fields ) ) {
			$data['event_date'] = $item->event_date;
		}

		if ( rest_is_field_included( 'payment_id', $fields ) ) {
			$data['payment_id'] = $item->payment_id;
		}

		if ( rest_is_field_included( 'payment_status', $fields ) ) {
			$data['payment_status'] = $item->payment_status;
		}

		if ( rest_is_field_included( 'custom_status', $fields ) ) {
			$data['custom_status'] = $item->custom_status;
		}

		if ( rest_is_field_included( 'created_at', $fields ) ) {
			$data['created_at'] = $item->created_at;
		}

		if ( rest_is_field_included( 'uid', $fields ) ) {
			$data['uid'] = $item->uid;
		}

		if ( rest_is_field_included( 'name', $fields ) ) {
			$data['name'] = $item->name;
		}

		if ( rest_is_field_included( 'email', $fields ) ) {
			$data['email'] = $item->email;
		}

		if ( rest_is_field_included( 'input_fields', $fields ) ) {
			$inp_fields    = array();
			$ticket_fields = array();

			$inp = json_decode( $item->input_fields );
			if ( null !== $inp ) {

				// Add the text fields.
				if ( ! empty( $inp->fields ) ) {
					foreach ( $inp->fields as $text_field ) {
						$tmp['name']  = $text_field->name;
						$tmp['value'] = $text_field->value;
						$inp_fields[] = $tmp;
					}
				}

				// Add the ticket fields.
				unset( $tmp );
				if ( ! empty( $inp->tickets ) ) {
					foreach ( $inp->tickets as $ticket ) {
						if ( 0 !== $ticket->count ) {
							$tmp['name']       = $ticket->name;
							$tmp['price']      = (float) $ticket->price;
							$tmp['vat']        = (float) $ticket->vat;
							$tmp['is_counted'] = (bool) $ticket->cflag;
							$tmp['number']     = $ticket->count;
							$ticket_fields[]   = $tmp;
						}
					}
				}
			}

			$input['fields']      = $inp_fields;
			$input['tickets']     = $ticket_fields;
			$data['input_fields'] = $input;
		}

		if ( rest_is_field_included( 'num_tickets', $fields ) ) {
			$data['num_tickets'] = (int) $item->num_tickets;
		}

		if ( rest_is_field_included( 'total', $fields ) ) {
			$data['total'] = (float) $item->total;
		}

		if ( rest_is_field_included( 'discount', $fields ) ) {
			$data['discount'] = (float) $item->discount;
		}

		if ( rest_is_field_included( 'ip_address', $fields ) ) {
			$data['ip_address'] = $item->ip_address;
		}

		$context = ! empty( $request['context'] ) ? $request['context'] : 'embed';

		$data = $this->add_additional_fields_to_object( $data, $request );
		$data = $this->filter_response_by_context( $data, $context );

		// Wrap the data in a response object.
		$response = rest_ensure_response( $data );

		if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
			$response->add_links( $this->prepare_links( $item ) );
		}

		return $response;
	}


	/**
	 * Prepares links for the order request.
	 *
	 * @param stdClass $order Order object.
	 * @return array Links for the given order.
	 *
	 * @since 1.0
	 */
	protected function prepare_links( stdClass $order ): array {
		$links = array(
			'self'       => array(
				'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $order->id ) ),
			),
			'collection' => array(
				'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
			),
		);

		if (
			isset( $order->payment_status ) &&
			in_array(
				$order->payment_status,
				array(
					'paid',
					'dashboard',
					'dashboard - confirmed',
					'booked',
					'booked - confirmed',
				),
				true
			) ) {
			$links['tickets'] = array(
				'href'       => rest_url( 'fast-events/v1/admin/tickets/' . $order->id ),
				'embeddable' => true,
			);
		}

		return $links;
	}


	/**
	 * Retrieves the query params for order collections.
	 *
	 * @return array
	 *
	 * @since 1.0
	 */
	public function get_collection_params(): array {
		$query_params = parent::get_collection_params();

		$query_params['context']['default'] = 'view';

		$query_params['event_id'] = array(
			'description' => __( 'Specific event_ids should be included.', 'fast-events' ),
			'type'        => 'array',
			'items'       => array(
				'type' => 'integer',
			),
		);

		$query_params['exclude'] = array(
			'description' => __( 'Ensure result set excludes specific IDs.' ),
			'type'        => 'array',
			'items'       => array(
				'type' => 'integer',
			),
			'default'     => array(),
		);

		$query_params['include'] = array(
			'description' => __( 'Limit result set to specific IDs.' ),
			'type'        => 'array',
			'items'       => array(
				'type' => 'integer',
			),
			'default'     => array(),
		);

		$query_params['offset'] = array(
			'description' => __( 'Offset the result set by a specific number of items.' ),
			'type'        => 'integer',
		);

		$query_params['order'] = array(
			'default'     => 'asc',
			'description' => __( 'Order sort attribute ascending or descending.' ),
			'enum'        => array( 'asc', 'desc' ),
			'type'        => 'string',
		);

		$query_params['orderby'] = array(
			'default'     => 'id',
			'description' => __( 'Sort collection by object attribute.' ),
			'enum'        => array(
				'id',
				'event_id',
				'email',
			),
			'type'        => 'string',
		);

		return $query_params;
	}


	/**
	 * Return the orders' schema.
	 *
	 * @return array
	 * @since 2.2.0 Added 'discount' field.
	 *
	 * @since 1.0
	 */
	public function get_item_schema(): array {
		if ( $this->schema ) {
			return $this->add_additional_fields_schema( $this->schema );
		}

		$this->schema = array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'orders',
			'type'       => 'object',
			'properties' => array(
				'id'             => array(
					'description' => __( 'The unique id of the order.', 'fast-events' ),
					'context'     => array( 'view' ),
					'type'        => 'integer',
					'readonly'    => true,
				),
				'uid'            => array(
					'description' => __( 'The public unique id of the order.', 'fast-events' ),
					'context'     => array( 'view' ),
					'type'        => 'string',
					'readonly'    => true,
				),
				'event_id'       => array(
					'description' => __( 'The unique id of the event.', 'fast-events' ),
					'context'     => array( 'view' ),
					'type'        => 'integer',
					'readonly'    => true,
				),
				'event_date'     => array(
					'description' => __( 'The date of the event.', 'fast-events' ),
					'context'     => array( 'view' ),
					'type'        => 'string',
					'format'      => 'date-time',
					'readonly'    => true,
				),
				'payment_id'     => array(
					'description' => __( 'The unique id of the payment transaction.', 'fast-events' ),
					'context'     => array( 'view' ),
					'type'        => 'string',
					'readonly'    => true,
				),
				'payment_status' => array(
					'description' => __( 'The status of the payment.', 'fast-events' ),
					'context'     => array( 'view' ),
					'type'        => 'string',
					'enum'        => array(
						'open',
						'authorized',
						'paid',
						'canceled',
						'failed',
						'expired',
						'refunded',
						'chargeback',
						'pending',
						'dashboard',
						'dashboard - confirmed',
						'booked',
						'booked - confirmed',
					),
					'readonly'    => true,
				),
				'custom_status'  => array(
					'description' => __( 'The custom status of the order.', 'fast-events' ),
					'context'     => array( 'view', 'edit' ),
					'type'        => array( 'string', 'null' ),
					'maxLength'   => 32,
					'enum'        => explode( ',', ( $this->settings->misc_custom_order_status() ) . ',' ),
				),
				'created_at'     => array(
					'description' => __( 'The time the order was created.', 'fast-events' ),
					'context'     => array( 'view' ),
					'type'        => 'string',
					'format'      => 'date-time',
					'readonly'    => true,
				),
				'name'           => array(
					'description' => __( 'The name of the customer.', 'fast-events' ),
					'context'     => array( 'view', 'edit' ),
					'type'        => 'string',
					'maxLength'   => 50,
				),
				'email'          => array(
					'description' => __( 'The emailaddress of the customer.', 'fast-events' ),
					'context'     => array( 'view', 'edit' ),
					'type'        => 'string',
					'format'      => 'email',
					'maxLength'   => 100,
				),
				'input_fields'   => array(
					'description' => __( 'Entries made during ordering.', 'fast-events' ),
					'context'     => array( 'view' ),
					'type'        => 'object',
					'readonly'    => true,
					'properties'  => array(
						'fields'  => array(
							'description' => __( 'Text entries made during ordering.', 'fast-events' ),
							'context'     => array( 'view' ),
							'type'        => 'array',
							'readonly'    => true,
							'items'       => array(
								'type'       => 'object',
								'properties' => array(
									'name'  => array(
										'description' => __( 'Name of the text field.', 'fast-events' ),
										'context'     => array( 'view' ),
										'type'        => 'string',
										'readonly'    => true,
									),
									'value' => array(
										'description' => __( 'Value of the text field.', 'fast-events' ),
										'context'     => array( 'view' ),
										'type'        => 'string',
										'readonly'    => true,
									),
								),
							),
						),
						'tickets' => array(
							'description' => __( 'Ordered tickets.', 'fast-events' ),
							'context'     => array( 'view' ),
							'type'        => 'array',
							'readonly'    => true,
							'items'       => array(
								'type'       => 'object',
								'properties' => array(
									'name'       => array(
										'description' => __( 'Name of the ticket.', 'fast-events' ),
										'context'     => array( 'view' ),
										'type'        => 'string',
										'readonly'    => true,
									),
									'price'      => array(
										'description' => __( 'Price per ticket.', 'fast-events' ),
										'context'     => array( 'view' ),
										'type'        => 'number',
										'readonly'    => true,
									),
									'vat'        => array(
										'description' => __( 'VAT percentage.', 'fast-events' ),
										'context'     => array( 'view' ),
										'type'        => 'number',
										'readonly'    => true,
									),
									'is_counted' => array(
										'description' => __( 'Is the ticket counted.', 'fast-events' ),
										'context'     => array( 'view' ),
										'type'        => 'bool',
										'readonly'    => true,
									),
									'number'     => array(
										'description' => __( 'Price of the ticket.', 'fast-events' ),
										'context'     => array( 'view' ),
										'type'        => 'integer',
										'readonly'    => true,
									),
								),
							),
						),
					),
				),
				'num_tickets'    => array(
					'description' => __( 'The number of tickets ordered.', 'fast-events' ),
					'context'     => array( 'view' ),
					'type'        => 'integer',
					'readonly'    => true,
				),
				'total'          => array(
					'description' => __( 'The total amount.', 'fast-events' ),
					'context'     => array( 'view' ),
					'type'        => 'number',
					'readonly'    => true,
				),
				'discount'       => array(
					'description' => __( 'The total discount amount.', 'fast-events' ),
					'context'     => array( 'view' ),
					'type'        => 'number',
					'readonly'    => true,
				),
				'ip_address'     => array(
					'description' => __( 'The ip address used during ordering.', 'fast-events' ),
					'context'     => array( 'view' ),
					'type'        => 'string',
					'format'      => 'ip',
					'readonly'    => true,
				),
			),
		);

		return $this->add_additional_fields_schema( $this->schema );
	}
}
