<?php
/**
 * System Status REST API controller.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Rest;

use ScheduledChanges\Capabilities\CapabilityManager;
use ScheduledChanges\Database\Migrator;
use ScheduledChanges\Database\TableHealth;
use ScheduledChanges\Extension\PublicHooks;
use ScheduledChanges\Provider\ProviderManager;
use ScheduledChanges\Repository\RecordingSessionRepository;
use ScheduledChanges\Scheduler\QueueMonitor;
use ScheduledChanges\Support\VersionPolicy;

/**
 * Exposes redacted system health over REST.
 */
final class SystemStatusController {
	use RegistersVersionedRoutes;

	private ?ProviderManager $providers;
	private ?QueueMonitor $queue;
	private RecordingSessionRepository $recordings;

	/**
	 * Creates the system status REST controller.
	 *
	 * @param ProviderManager|null       $providers Provider manager.
	 * @param QueueMonitor|null          $queue Queue monitor.
	 * @param RecordingSessionRepository $recordings Recording sessions.
	 */
	public function __construct( ?ProviderManager $providers, ?QueueMonitor $queue, RecordingSessionRepository $recordings ) {
		$this->providers  = $providers;
		$this->queue      = $queue;
		$this->recordings = $recordings;
	}

	/**
	 * Registers system status routes.
	 */
	public function registerRoutes(): void {
		$this->registerVersionedRoute(
			'/system-status',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'getStatus' ),
				'permission_callback' => array( $this, 'canView' ),
				'schema'              => array( $this, 'schema' ),
			)
		);
	}

	/**
	 * Returns redacted platform and scheduler health.
	 */
	public function getStatus(): \WP_REST_Response {
		global $wp_version;

		$migrator          = new Migrator();
		$table_health      = ( new TableHealth() )->summary();
		$queue_status      = null === $this->queue ? array() : $this->queue->status()->toArray();
		$provider_errors   = null === $this->providers ? array() : $this->providers->errors();
		$provider_versions = null === $this->providers ? array() : $this->providers->providers()->versions();
		$database          = VersionPolicy::databaseEnvironment();
		$recommended       = VersionPolicy::recommended();
		$compatibility     = PublicHooks::systemCompatibility(
			array(
				'php'       => array(
					'current'     => PHP_VERSION,
					'minimum'     => VersionPolicy::MIN_PHP,
					'recommended' => VersionPolicy::RECOMMENDED_PHP,
					'status'      => VersionPolicy::classify( PHP_VERSION, VersionPolicy::MIN_PHP, VersionPolicy::RECOMMENDED_PHP, VersionPolicy::forwardTestedPhp() ),
				),
				'wordpress' => array(
					'current'     => (string) $wp_version,
					'minimum'     => VersionPolicy::MIN_WORDPRESS,
					'recommended' => (string) ( $recommended['wordpress'] ?? '' ),
					'status'      => VersionPolicy::classify( (string) $wp_version, VersionPolicy::MIN_WORDPRESS, VersionPolicy::TESTED_WORDPRESS ),
				),
				'database'  => $database,
			),
			$this->providers
		);
		$data              = array(
			'pluginVersion'          => SCHEDULED_CHANGES_VERSION,
			'schemaVersion'          => SCHEDULED_CHANGES_SCHEMA_VERSION,
			'installedSchemaVersion' => $migrator->currentVersion(),
			'requiredSchemaVersion'  => $migrator->latestVersion(),
			'wordpressVersion'       => (string) $wp_version,
			'phpVersion'             => PHP_VERSION,
			'minimumPhp'             => VersionPolicy::MIN_PHP,
			'minimumWordPress'       => VersionPolicy::MIN_WORDPRESS,
			'recommended'            => array_intersect_key(
				$recommended,
				array_flip( array( 'php', 'wordpress', 'mysql', 'mariadb' ) )
			),
			'forwardTestedPhp'       => VersionPolicy::forwardTestedPhp(),
			'compatibility'          => $compatibility,
			'databaseTables'         => array(
				'existing'           => (int) ( $table_health['existing'] ?? 0 ),
				'expected'           => (int) ( $table_health['expected'] ?? 0 ),
				'missing'            => array_values( is_array( $table_health['missing'] ?? null ) ? $table_health['missing'] : array() ),
				'transactionCapable' => (bool) ( $table_health['transaction_capable'] ?? false ),
				'nonTransactional'   => array_values( is_array( $table_health['non_transactional'] ?? null ) ? $table_health['non_transactional'] : array() ),
				'engines'            => is_array( $table_health['tables'] ?? null ) ? $table_health['tables'] : array(),
			),
			'queue'                  => array(
				'available'         => (bool) ( $queue_status['available'] ?? false ),
				'healthy'           => (bool) ( $queue_status['healthy'] ?? false ),
				'pending'           => (int) ( $queue_status['pending'] ?? 0 ),
				'running'           => (int) ( $queue_status['running'] ?? 0 ),
				'failed'            => (int) ( $queue_status['failed'] ?? 0 ),
				'overdue'           => (int) ( $queue_status['overdue'] ?? 0 ),
				'staleLocks'        => (int) ( $queue_status['stale_locks'] ?? 0 ),
				'wpCronDisabled'    => (bool) ( $queue_status['wp_cron_disabled'] ?? false ),
				'repairDiagnostics' => is_array( $queue_status['repair_diagnostics'] ?? null ) ? $queue_status['repair_diagnostics'] : array(),
			),
			'providers'              => array(
				'loaded' => null !== $this->providers && $this->providers->loaded(),
				'count'  => count( $provider_versions ),
				'errors' => array_values( array_map( 'strval', $provider_errors ) ),
			),
			'recordings'             => array(
				'active'             => $this->recordings->activeCount(),
				'stale'              => $this->recordings->staleCount(),
				'orphanedWorkspaces' => $this->recordings->orphanedWorkspaceCount(),
			),
		);

		return rest_ensure_response( PublicHooks::systemStatusPayload( $data, $this->providers ) );
	}

	/**
	 * Checks diagnostic capability.
	 */
	public function canView(): bool {
		return current_user_can( CapabilityManager::MANAGE_SETTINGS );
	}

	/**
	 * Returns the system status schema.
	 *
	 * @return array<string,mixed>
	 */
	public function schema(): array {
		return PublicHooks::systemStatusSchema(
			array(
				'$schema'    => 'http://json-schema.org/draft-04/schema#',
				'title'      => 'scheduled_changes_system_status',
				'type'       => 'object',
				'properties' => array(
					'pluginVersion'          => array( 'type' => 'string' ),
					'schemaVersion'          => array( 'type' => 'string' ),
					'installedSchemaVersion' => array( 'type' => 'integer' ),
					'requiredSchemaVersion'  => array( 'type' => 'integer' ),
					'wordpressVersion'       => array( 'type' => 'string' ),
					'phpVersion'             => array( 'type' => 'string' ),
					'minimumPhp'             => array( 'type' => 'string' ),
					'minimumWordPress'       => array( 'type' => 'string' ),
					'recommended'            => array( 'type' => 'object' ),
					'forwardTestedPhp'       => array( 'type' => 'array' ),
					'compatibility'          => array( 'type' => 'object' ),
					'databaseTables'         => array( 'type' => 'object' ),
					'queue'                  => array( 'type' => 'object' ),
					'providers'              => array( 'type' => 'object' ),
					'recordings'             => array( 'type' => 'object' ),
				),
			)
		);
	}
}
