<?php
/**
 * FE Admin Webhooks controller.
 *
 * @since 2.0
 */

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

defined( 'ABSPATH' ) || exit;

use FeData\FastEvents\Helpers\AuthHelper;
use WP_Error;
use WP_REST_Controller;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

/**
 * FE Admin Webhooks class.
 */
class WebhooksController extends WP_REST_Controller {

	private const DATE_ZERO = '0000-00-00 00:00:00';

	/**
	 * Admin Webhooks constructor.
	 *
	 * @param AuthHelper $auth The authentication helper.
	 *
	 * @since 2.0
	 */
	public function __construct( private readonly AuthHelper $auth ) {
		$this->namespace = 'fast-events/v1';
		$this->rest_base = 'admin/webhooks';
	}


	/**
	 * Register the routes for the objects of the controller.
	 *
	 * @since 2.0
	 * @since 2.2.0 Corrected translation
	 */
	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' => function () {
						return $this->fast_events_admin_permissions( $this->auth::WEBHOOK_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::WEBHOOK_CHANGE );
					},
					'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 webhook', '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::WEBHOOK_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::WEBHOOK_CHANGE );
					},
					'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::WEBHOOK_CHANGE );
					},
				),
				'schema' => array( $this, 'get_public_item_schema' ),
			)
		);

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/(?P<id>[\d]+)/reset-counters',
			array(
				'args'   => array(
					'id' => array(
						'description'       => __( 'The unique id of the webhook', 'fast-events' ),
						'type'              => 'integer',
						'required'          => true,
						'sanitize_callback' => 'absint',
					),
				),
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'reset_counters' ),
					'permission_callback' => function () {
						return $this->fast_events_admin_permissions( $this->auth::WEBHOOK_CHANGE );
					},
					'args'                => array(
						'context' => $this->get_context_param( array( 'default' => 'view' ) ),
					),
				),
				'schema' => array( $this, 'get_public_item_schema' ),
			)
		);
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/(?P<id>[\d]+)/ping',
			array(
				'args'   => array(
					'id' => array(
						'description'       => __( 'The unique id of the webhook', 'fast-events' ),
						'type'              => 'integer',
						'required'          => true,
						'sanitize_callback' => 'absint',
					),
				),
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'ping' ),
					'permission_callback' => function () {
						return $this->fast_events_admin_permissions( $this->auth::WEBHOOK_CHANGE );
					},
					'args'                => array(
						'context' => $this->get_context_param( array( 'default' => 'view' ) ),
					),
				),
				'schema' => array( $this, 'get_public_item_schema' ),
			)
		);
	}


	/**
	 * Get the authorization for the Webhooks endpoints.
	 *
	 * @param int $action The action on the controller.
	 * @return WP_Error|bool
	 *
	 * @since 2.0
	 */
	public function fast_events_admin_permissions( int $action ): WP_Error|bool {
		return $this->auth->authorize( $action );
	}


	/**
	 * Get all webhooks.
	 *
	 * @param WP_REST_Request $request Request instance.
	 * @return WP_REST_Response|WP_Error|array
	 *
	 * @since 2.0
	 */
	public function get_items( $request ): WP_Error|WP_REST_Response|array {
		global $wpdb;

		$result = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}fe_event_webhooks ORDER BY id", ARRAY_A );

		$webhook_fields = array();

		foreach ( $result as $item ) {
			$webhook_fields[] = $this->prepare_response_for_collection(
				$this->prepare_item_for_response( $item, $request )
			);
		}

		$response = rest_ensure_response( $webhook_fields );

		// Generate the totals headers.
		$response->header( 'X-WP-Total', count( $webhook_fields ) );
		$response->header( 'X-WP-TotalPages', 1 );

		return $response;
	}


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

		$webhook = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}fe_event_webhooks WHERE id = %d", $request['id'] ), ARRAY_A );
		if ( empty( $webhook ) ) {
			return new WP_Error( 'not_found', __( 'Webhook not found', 'fast-events' ), array( 'status' => 404 ) );
		}

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


	/**
	 * Create a new webhook.
	 *
	 * @param WP_REST_Request $request Full details about the request.
	 * @return WP_REST_Response|WP_Error|bool|array Response object on success, or WP_Error object on failure.
	 *
	 * @since 1.0
	 */
	public function create_item( $request ): WP_Error|WP_REST_Response|bool|array {
		global $wpdb;

		$webhook = $this->prepare_item_for_database( $request );
		if ( is_wp_error( $webhook ) ) {
			return $webhook;
		}

		// Insert into database.
		$result = $wpdb->insert( $wpdb->prefix . 'fe_event_webhooks', $webhook );
		if ( false === $result ) {
			return new WP_Error( 'failed', __( 'Insert webhook failed', 'fast-events' ) . ': ' . $wpdb->last_error, array( 'status' => 400 ) );
		}

		$webhook = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}fe_event_webhooks WHERE id = %d", $wpdb->insert_id ), ARRAY_A );
		if ( empty( $webhook ) ) {
			return new WP_Error( 'not_found', __( 'Webhook not found', 'fast-events' ), array( 'status' => 404 ) );
		}

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

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


	/**
	 * Update a single webhook.
	 *
	 * @param WP_REST_Request $request Full details about the request.
	 * @return WP_REST_Response|WP_Error|bool|array Response object on success, or WP_Error object on failure.
	 *
	 * @since 2.0
	 */
	public function update_item( $request ): WP_Error|WP_REST_Response|bool|array {
		global $wpdb;

		$webhook = $this->prepare_item_for_database( $request );
		if ( is_wp_error( $webhook ) ) {
			return $webhook;
		}

		// Update event.
		$result = $wpdb->update( $wpdb->prefix . 'fe_event_webhooks', $webhook, array( 'id' => $request['id'] ) );
		if ( false === $result ) {
			return new WP_Error( 'failed', __( 'Update webhook failed', 'fast-events' ) . ': ' . $wpdb->last_error, array( 'status' => 400 ) );
		}
		$webhook = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}fe_event_webhooks WHERE id = %d", $request['id'] ), ARRAY_A );
		if ( empty( $webhook ) ) {
			return new WP_Error( 'not_found', __( 'Webhook not found', 'fast-events' ), array( 'status' => 404 ) );
		}

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

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


	/**
	 * Reset counters of a single webhook.
	 *
	 * @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 2.0
	 */
	public function reset_counters( WP_REST_Request $request ): WP_Error|WP_REST_Response {
		global $wpdb;

		$result = $wpdb->update(
			$wpdb->prefix . 'fe_event_webhooks',
			array(
				'pending'      => 0,
				'retries'      => 0,
				'failed'       => 0,
				'delivered'    => 0,
				'last_success' => '0000-00-00 00:00:00',
				'last_retry'   => '0000-00-00 00:00:00',
				'last_failure' => '0000-00-00 00:00:00',
			),
			array(
				'id' => $request['id'],
			)
		);
		if ( false === $result ) {
			return new WP_Error( 'counter_reset_failed', esc_html__( 'Update webhook counters failed', 'fast-events' ) . ': ' . $wpdb->last_error, array( 'status' => 400 ) );
		}
		$webhook = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}fe_event_webhooks WHERE id = %d", $request['id'] ), ARRAY_A );
		if ( empty( $webhook ) ) {
			return new WP_Error( 'not_found', __( 'Webhook not found', 'fast-events' ), array( 'status' => 404 ) );
		}

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

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


	/**
	 * Test a webhook.
	 * Return the full request and response in JSON format for analysis.
	 *
	 * @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 2.0
	 */
	public function ping( WP_REST_Request $request ): WP_Error|WP_REST_Response {
		global $wpdb;

		// Lookup the webhook.
		$webhook = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT id, url, topic, secret FROM {$wpdb->prefix}fe_event_webhooks WHERE id = %d",
				$request['id']
			),
			ARRAY_A
		);
		if ( empty( $webhook ) ) {
			return new WP_Error( 'not_found', __( 'Webhook not found', 'fast-events' ), array( 'status' => 404 ) );
		}

		$start_time = microtime( true );

		// Setup request args.
		$event       = explode( '.', $webhook['topic'] );
		$delivery_id = wp_hash( strtotime( 'now' ) );
		$http_args   = array(
			'method'     => 'POST',
			'timeout'    => MINUTE_IN_SECONDS,
			'blocking'   => true,
			'user-agent' => 'Fast-Events/' . fast_events_func()::FAST_EVENTS_VERSION . ' (WordPress/' . $GLOBALS['wp_version'] . ')',
			'body'       => '',
			'headers'    => array(
				'Content-Type'             => 'application/json',
				'X-FE-Webhook-Source'      => home_url( '/' ),
				'X-FE-Webhook-Topic'       => $webhook['topic'],
				'X-FE-Webhook-Resource'    => $event[0],
				'X-FE-Webhook-Event'       => $event[1],
				'X-FE-Webhook-ID'          => $webhook['id'],
				'X-FE-Webhook-Delivery-ID' => $delivery_id,
				// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
				'X-FE-Webhook-Signature'   => base64_encode( hash_hmac( 'sha256', '', $webhook['secret'], true ) ),
			),
			'cookies'    => array(),
		);

		// Call webhook.
		$response = wp_safe_remote_request( $webhook['url'], $http_args );

		// Get duration.
		$duration = round( ( microtime( true ) - $start_time ), 5 );

		$message = array(
			'Webhook Delivery' => array(
				'Delivery ID' => $delivery_id,
				'Date'        => gmdate( 'Y-m-d H:i:s' ) . ' GMT',
				'URL'         => $webhook['url'],
				'Duration'    => $duration . ' seconds',
				'Request'     => array(
					'Method'  => $http_args['method'],
					'Headers' => array_merge(
						array(
							'User-Agent' => $http_args['user-agent'],
						),
						$http_args['headers']
					),
					'Body'    => wp_slash( $http_args['body'] ),
				),
			),
		);

		// Parse response.
		if ( is_wp_error( $response ) ) {
			$response_code    = $response->get_error_code();
			$response_message = $response->get_error_message();
			$response_headers = array();
			$response_body    = '';
		} else {
			$response_code    = wp_remote_retrieve_response_code( $response );
			$response_message = wp_remote_retrieve_response_message( $response );
			$response_headers = wp_remote_retrieve_headers( $response )->getAll();
			$response_body    = json_decode( wp_remote_retrieve_body( $response ) );
			if ( JSON_ERROR_NONE !== json_last_error() ) {
				$response_body = wp_remote_retrieve_body( $response );
			}
		}

		$message['Webhook Delivery']['Response'] = array(
			'Code'    => $response_code,
			'Message' => $response_message,
			'Headers' => $response_headers,
			'Body'    => $response_body,
		);

		// Return a log entry structure.
		return rest_ensure_response( $message );
	}


	/**
	 * Delete a single webhook.
	 *
	 * @param WP_REST_Request $request Full details about the request.
	 * @return WP_REST_Response|WP_Error|bool|array Response object on success, or WP_Error object on failure.
	 *
	 * @since 2.0
	 */
	public function delete_item( $request ): WP_Error|WP_REST_Response|bool|array {
		global $wpdb;

		$old_webhook = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}fe_event_webhooks WHERE id = %d", $request['id'] ), ARRAY_A );
		if ( empty( $old_webhook ) ) {
			return new WP_Error( 'not_found', __( 'Webhook not found', 'fast-events' ), array( 'status' => 404 ) );
		}

		$webhook = $wpdb->delete( $wpdb->prefix . 'fe_event_webhooks', array( 'id' => $request['id'] ) );

		if ( false === $webhook || 0 === $webhook ) {
			return new WP_Error( 'not_found', __( 'Webhook not found', 'fast-events' ), array( 'status' => 404 ) );
		}

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

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

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

		return $response;
	}


	/**
	 * Prepares the object for the database.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_Error|array Response object.
	 *
	 * @since 2.0
	 */
	public function prepare_item_for_database( $request ): WP_Error|array {

		// Is this an update or create?
		$create = str_ends_with( $request->get_route(), 'webhooks' );

		// Check for empty fields.
		if ( $create && ( empty( $request['name'] ) || empty( $request['url'] ) || empty( $request['topic'] ) || empty( $request['secret'] ) ) ) {
			return new WP_Error( 'failed', __( 'Empty fields are not allowed', 'fast-events' ), array( 'status' => 400 ) );
		}

		$webhook = array();
		if ( isset( $request['name'] ) ) {
			if ( '' === trim( $request['name'] ) ) {
				return new WP_Error( 'empty_field', __( 'Empty "name" field is not allowed', 'fast-events' ), array( 'status' => 400 ) );
			} else {
				$webhook['name'] = $request['name'];
			}
		}

		if ( isset( $request['url'] ) ) {
			if ( false === wp_http_validate_url( $request['url'] ) || ! str_starts_with( $request['url'], 'https' ) ) {
				return new WP_Error( 'empty_field', __( 'Invalid webhook URL', 'fast-events' ), array( 'status' => 400 ) );
			} else {
				$webhook['url'] = $request['url'];
			}
		}

		if ( isset( $request['topic'] ) ) {
			if ( '' === trim( $request['topic'] ) ) {
				return new WP_Error( 'empty_field', __( 'Empty "topic" field is not allowed', 'fast-events' ), array( 'status' => 400 ) );
			} else {
				$webhook['topic'] = $request['topic'];
			}
		}

		if ( isset( $request['secret'] ) ) {
			if ( '' === trim( $request['secret'] ) ) {
				return new WP_Error( 'empty_field', __( 'Empty "secret" field is not allowed', 'fast-events' ), array( 'status' => 400 ) );
			} else {
				$webhook['secret'] = $request['secret'];
			}
		}

		if ( isset( $request['enabled'] ) ) {
			$webhook['status'] = true === $request['enabled'] ? 1 : 0;
		}

		if ( isset( $request['retry_scheme'] ) ) {
			$webhook['retry_scheme'] = implode( ',', array_map( 'absint', explode( ',', $request['retry_scheme'] ) ) );
		}

		if ( isset( $request['failure_threshold'] ) ) {
			$webhook['failure_threshold'] = empty( $request['failure_threshold'] ) ? 60 : $request['failure_threshold'];
		}

		if ( $create ) {
			$webhook['status']            = true === $request['enabled'] ? 1 : 0;
			$webhook['retry_scheme']      = implode( ',', array_map( 'absint', explode( ',', $request['retry_scheme'] ) ) );
			$webhook['failure_threshold'] = empty( $request['failure_threshold'] ) ? 60 : $request['failure_threshold'];
			$webhook['user_id']           = get_current_user_id();
			$webhook['date_created']      = current_time( 'mysql' );
		}

		if ( ! $create && 0 === count( $webhook ) ) {
			return new WP_Error( 'no_fields_found', __( 'Nothing to update', 'fast-events' ), array( 'status' => 400 ) );
		}

		return $webhook;
	}

	/**
	 * Prepares a single webhook output for response.
	 *
	 * @param mixed           $item    Webhook object.
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response Response object.
	 *
	 * @since 2.0
	 */
	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( 'name', $fields ) ) {
			$data['name'] = $item['name'];
		}

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

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

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

		if ( rest_is_field_included( 'enabled', $fields ) ) {
			$data['enabled'] = 1 === (int) $item['status'];
		}

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

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

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

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

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

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

		if ( rest_is_field_included( 'last_success', $fields ) ) {
			$data['last_success'] = $item['last_success'] ?? self::DATE_ZERO;
		}

		if ( rest_is_field_included( 'last_retry', $fields ) ) {
			$data['last_retry'] = $item['last_retry'] ?? self::DATE_ZERO;
		}

		if ( rest_is_field_included( 'last_failure', $fields ) ) {
			$data['last_failure'] = $item['last_failure'] ?? self::DATE_ZERO;
		}

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

		$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 webhooks request.
	 *
	 * @param array $field Webhook object.
	 * @return array Links for the given order.
	 *
	 * @since 2.0
	 */
	protected function prepare_links( array $field ): array {
		return array(
			'self'       => array(
				'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $field['id'] ) ),
			),
			'collection' => array(
				'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
			),
		);
	}


	/**
	 * Return the webhooks' schema.
	 *
	 * @return array
	 *
	 * @since 2.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'      => 'webhooks',
			'type'       => 'object',
			'properties' => array(
				'id'                => array(
					'description' => __( 'The unique id of the webhook.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'string',
					'readonly'    => true,
				),
				'name'              => array(
					'description' => __( 'The name of the webhook.', 'fast-events' ),
					'context'     => array( 'view', 'edit', 'embed' ),
					'type'        => 'string',
					'minLength'   => 1,
					'maxLength'   => 100,
					'required'    => true,
					'arg_options' => array(
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
				'url'               => array(
					'description' => __( 'A valid URL provided by the webhook consumer.', 'fast-events' ),
					'context'     => array( 'view', 'edit', 'embed' ),
					'type'        => 'string',
					'format'      => 'uri',
					'required'    => true,
				),
				'secret'            => array(
					'description' => __( 'The shared secret.', 'fast-events' ),
					'context'     => array( 'view', 'edit', 'embed' ),
					'type'        => 'string',
					'minLength'   => 8,
					'maxLength'   => 100,
					'required'    => true,
					'arg_options' => array(
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
				'topic'             => array(
					'description' => __( 'Which event is the consumer interested in.', 'fast-events' ),
					'context'     => array( 'view', 'edit', 'embed' ),
					'type'        => 'string',
					'enum'        => array(
						'event.created',
						'event.updated',
						'event.deleted',
						'order.created',
						'order.updated',
						'order.deleted',
						'order.refunded',
						'scan.created',
						'tickets.downloaded',
						'invoice.downloaded',
					),
					'default'     => 'order.created',
				),
				'enabled'           => array(
					'description' => __( 'Is the webhook enabled.', 'fast-events' ),
					'context'     => array( 'view', 'edit', 'embed' ),
					'type'        => 'boolean',
					'default'     => false,
				),
				'retry_scheme'      => array(
					'description' => __( 'Comma separated list of retry minutes.', 'fast-events' ),
					'context'     => array( 'view', 'edit', 'embed' ),
					'type'        => 'string',
					'maxLength'   => 128,
					'pattern'     => '^\d*(,\d+)*$',
					'default'     => '1,5,10,15,30',
				),
				'failure_threshold' => array(
					'description' => __( 'After this number of failures the webhook is disabled.', 'fast-events' ),
					'context'     => array( 'view', 'edit', 'embed' ),
					'type'        => 'integer',
					'default'     => 60,
					'arg_options' => array(
						'sanitize_callback' => 'absint',
					),
				),
				'pending'           => array(
					'description' => __( 'The number of pending requests.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'integer',
					'readonly'    => true,
				),
				'delivered'         => array(
					'description' => __( 'The number of delivered requests.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'integer',
					'readonly'    => true,
				),
				'retries'           => array(
					'description' => __( 'The number of retried requests.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'integer',
					'readonly'    => true,
				),
				'failed'            => array(
					'description' => __( 'The number of failed requests.', 'fast-events' ),
					'context'     => array( 'view', 'embed' ),
					'type'        => 'integer',
					'readonly'    => true,
				),
				'last_success'      => array(
					'description' => __( 'The date of the last succeeded request.' ),
					'type'        => array( 'string', 'null' ),
					'format'      => 'date-time',
					'context'     => array( 'view', 'embed' ),
					'readonly'    => true,
				),
				'last_retry'        => array(
					'description' => __( 'The date of the last retried request.' ),
					'type'        => array( 'string', 'null' ),
					'format'      => 'date-time',
					'context'     => array( 'view', 'embed' ),
					'readonly'    => true,
				),
				'last_failure'      => array(
					'description' => __( 'The date of the last failed request.' ),
					'type'        => array( 'string', 'null' ),
					'format'      => 'date-time',
					'context'     => array( 'view', 'embed' ),
					'readonly'    => true,
				),
				'date_created'      => array(
					'description' => __( 'The date when the webhook was created.' ),
					'type'        => array( 'string', 'null' ),
					'format'      => 'date-time',
					'context'     => array( 'view', 'embed' ),
					'readonly'    => true,
				),
			),
		);

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