<?php
/**
 * Launch REST API schemas and route arguments.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Rest;

use ScheduledChanges\Extension\PublicHooks;

/**
 * Keeps REST schema definitions separate from route handlers and permissions.
 */
final class LaunchesRestSchemas {
	/**
	 * Returns the collection launch schema.
	 *
	 * @return array<string,mixed>
	 */
	public function schema(): array {
		$properties = array(
			'uuid'             => array( 'type' => 'string' ),
			'name'             => array( 'type' => 'string' ),
			'status'           => array( 'type' => 'string' ),
			'health'           => array( 'type' => 'string' ),
			'healthReason'     => array( 'type' => 'string' ),
			'availableActions' => array( 'type' => 'array' ),
			'diagnostics'      => array( 'type' => 'array' ),
			'targetCount'      => array( 'type' => 'integer' ),
			'startAt'          => array( 'type' => 'string' ),
			'startDate'        => array( 'type' => 'string' ),
			'startTime'        => array( 'type' => 'string' ),
			'endAt'            => array( 'type' => 'string' ),
			'timezone'         => array( 'type' => 'string' ),
			'validationState'  => array( 'type' => 'string' ),
			'lastRunStatus'    => array( 'type' => 'string' ),
			'owner'            => array( 'type' => 'string' ),
			'creationSource'   => array( 'type' => 'string' ),
			'updatedAt'        => array( 'type' => 'string' ),
			'queued'           => array( 'type' => 'boolean' ),
			'canCancel'        => array( 'type' => 'boolean' ),
			'canReschedule'    => array( 'type' => 'boolean' ),
		);

		return PublicHooks::restLaunchSchema(
			array(
				'$schema'    => 'http://json-schema.org/draft-04/schema#',
				'title'      => 'scheduled_changes_launch',
				'type'       => 'object',
				'properties' => $properties,
			)
		);
	}

	/**
	 * Returns the expanded launch detail schema.
	 *
	 * @return array<string,mixed>
	 */
	public function detailSchema(): array {
		$launch_schema = $this->schema();

		return array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'scheduled_changes_launch_detail',
			'type'       => 'object',
			'properties' => ( is_array( $launch_schema['properties'] ?? null ) ? $launch_schema['properties'] : array() ) + array(
				'targets'    => array( 'type' => 'array' ),
				'operations' => array( 'type' => 'array' ),
				'runs'       => array( 'type' => 'array' ),
				'timeline'   => array( 'type' => 'array' ),
			),
		);
	}

	/**
	 * Returns the target discovery item schema.
	 *
	 * @return array<string,mixed>
	 */
	public function targetSchema(): array {
		return array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'scheduled_changes_target',
			'type'       => 'object',
			'properties' => array(
				'targetReference' => array( 'type' => 'string' ),
				'targetId'        => array( 'type' => 'integer' ),
				'targetType'      => array( 'type' => 'string' ),
				'subtype'         => array( 'type' => 'string' ),
				'name'            => array( 'type' => 'string' ),
				'providerId'      => array( 'type' => 'string' ),
				'providerLabel'   => array( 'type' => 'string' ),
				'typeLabel'       => array( 'type' => 'string' ),
				'canEdit'         => array( 'type' => 'boolean' ),
				'upcomingCount'   => array( 'type' => 'integer' ),
				'failedCount'     => array( 'type' => 'integer' ),
				'nextChange'      => array( 'type' => 'string' ),
			),
		);
	}

	/**
	 * Returns the provider item schema.
	 *
	 * @return array<string,mixed>
	 */
	public function providerSchema(): array {
		return array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'scheduled_changes_provider',
			'type'       => 'object',
			'properties' => array(
				'id'      => array( 'type' => 'string' ),
				'version' => array( 'type' => 'string' ),
				'status'  => array( 'type' => 'string' ),
			),
		);
	}

	/**
	 * Returns the validation report schema.
	 *
	 * @return array<string,mixed>
	 */
	public function validationSchema(): array {
		return array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'scheduled_changes_launch_validation',
			'type'       => 'object',
			'properties' => array(
				'valid'                => array( 'type' => 'boolean' ),
				'blocking_error_count' => array( 'type' => 'integer' ),
				'warning_count'        => array( 'type' => 'integer' ),
				'informational_count'  => array( 'type' => 'integer' ),
				'issues'               => array( 'type' => 'array' ),
			),
		);
	}

	/**
	 * Returns the dry-run or execution response schema.
	 *
	 * @return array<string,mixed>
	 */
	public function runSchema(): array {
		return array(
			'$schema' => 'http://json-schema.org/draft-04/schema#',
			'title'   => 'scheduled_changes_launch_run',
			'type'    => 'object',
		);
	}

	/**
	 * Returns the manual retry response schema.
	 *
	 * @return array<string,mixed>
	 */
	public function retrySchema(): array {
		return array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'scheduled_changes_launch_retry',
			'type'       => 'object',
			'properties' => array(
				'uuid'            => array( 'type' => 'string' ),
				'sourceRunId'     => array( 'type' => 'integer' ),
				'versionId'       => array( 'type' => 'integer' ),
				'actionId'        => array( 'type' => 'integer' ),
				'attemptNumber'   => array( 'type' => 'integer' ),
				'occurrenceAtUtc' => array( 'type' => 'string' ),
				'status'          => array( 'type' => 'string' ),
			),
		);
	}

	/**
	 * Returns the rollback response schema.
	 *
	 * @return array<string,mixed>
	 */
	public function rollbackSchema(): array {
		return array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'scheduled_changes_launch_rollback',
			'type'       => 'object',
			'properties' => array(
				'uuid'             => array( 'type' => 'string' ),
				'sourceRunId'      => array( 'type' => 'integer' ),
				'rollbackRunId'    => array( 'type' => 'integer' ),
				'status'           => array( 'type' => 'string' ),
				'conflictPolicy'   => array( 'type' => 'string' ),
				'createdTargets'   => array( 'type' => 'string' ),
				'operationSummary' => array( 'type' => 'object' ),
			),
		);
	}

	/**
	 * Returns the schedule response schema.
	 *
	 * @return array<string,mixed>
	 */
	public function scheduleSchema(): array {
		return array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'scheduled_changes_schedule_launch',
			'type'       => 'object',
			'properties' => array(
				'actionId'       => array( 'type' => 'integer' ),
				'versionId'      => array( 'type' => 'integer' ),
				'scheduledAtUtc' => array( 'type' => 'string' ),
				'launch'         => array( 'type' => array( 'object', 'null' ) ),
			),
		);
	}

	/**
	 * Returns the cancel response schema.
	 *
	 * @return array<string,mixed>
	 */
	public function cancelSchema(): array {
		return array(
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
			'title'      => 'scheduled_changes_cancel_launch',
			'type'       => 'object',
			'properties' => array(
				'cancelledActionCount' => array( 'type' => 'integer' ),
				'versionId'            => array( 'type' => 'integer' ),
				'launch'               => array( 'type' => array( 'object', 'null' ) ),
			),
		);
	}

	/**
	 * Validates a Y-m-d date string.
	 *
	 * @param mixed $value Request value.
	 */
	public function isDateString( $value ): bool {
		return is_string( $value ) && 1 === preg_match( '/^\d{4}-\d{2}-\d{2}$/', $value );
	}

	/**
	 * Validates an H:i time string.
	 *
	 * @param mixed $value Request value.
	 */
	public function isTimeString( $value ): bool {
		return is_string( $value ) && 1 === preg_match( '/^\d{2}:\d{2}$/', $value );
	}

	/**
	 * Returns pagination route arguments.
	 *
	 * @return array<string,array<string,mixed>>
	 */
	public function paginationArgs(): array {
		return array(
			'page'     => array(
				'description'       => __( 'Current page of the launch collection.', 'jjs-post-scheduler' ),
				'type'              => 'integer',
				'default'           => 1,
				'minimum'           => 1,
				'sanitize_callback' => 'absint',
			),
			'per_page' => array(
				'description'       => __( 'Maximum number of launches to return.', 'jjs-post-scheduler' ),
				'type'              => 'integer',
				'default'           => 25,
				'minimum'           => 1,
				'maximum'           => 100,
				'sanitize_callback' => 'absint',
			),
		);
	}

	/**
	 * Returns UUID route arguments.
	 *
	 * @return array<string,array<string,mixed>>
	 */
	public function uuidArgs(): array {
		return array(
			'uuid' => array(
				'description'       => __( 'Launch UUID.', 'jjs-post-scheduler' ),
				'type'              => 'string',
				'required'          => true,
				'validate_callback' => static function ( $value ): bool {
					return is_string( $value ) && 1 === preg_match( '/^[0-9a-fA-F-]{36}$/', $value );
				},
			),
		);
	}
}
