<?php
/** WP-CLI diagnostics for the durable local BYOK queue foundation. */

defined( 'ABSPATH' ) || exit;

class Costudio_BYOK_Jobs_CLI {

	public static function register(): void {
		if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
			return;
		}

		WP_CLI::add_command( 'costudio byok jobs status', array( self::class, 'status' ) );
		WP_CLI::add_command( 'costudio byok jobs list', array( self::class, 'list_jobs' ) );
		WP_CLI::add_command( 'costudio byok jobs inspect', array( self::class, 'inspect' ) );
		WP_CLI::add_command( 'costudio byok jobs mode', array( self::class, 'mode' ) );
		WP_CLI::add_command( 'costudio byok jobs cleanup', array( self::class, 'cleanup' ) );
		WP_CLI::add_command( 'costudio byok jobs work', array( self::class, 'work' ) );
		WP_CLI::add_command( 'costudio byok jobs cancel', array( self::class, 'cancel' ) );
		WP_CLI::add_command( 'costudio byok jobs canary-add', array( self::class, 'canary_add' ) );
		WP_CLI::add_command( 'costudio byok jobs canary-remove', array( self::class, 'canary_remove' ) );
		WP_CLI::add_command( 'costudio byok jobs canary-list', array( self::class, 'canary_list' ) );
		WP_CLI::add_command( 'costudio byok jobs current-license-hash', array( self::class, 'current_license_hash' ) );
	}

	public static function status(): void {
		WP_CLI::log(
			wp_json_encode(
				Costudio_BYOK_Jobs::status_summary(),
				JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
			)
		);
	}

	/**
	 * ## OPTIONS
	 * [--status=<status>]
	 * [--limit=<number>]
	 */
	public static function list_jobs( array $args, array $assoc ): void {
		$limit  = max( 1, min( 200, (int) ( $assoc['limit'] ?? 20 ) ) );
		$status = sanitize_key( (string) ( $assoc['status'] ?? '' ) );
		$rows   = Costudio_BYOK_Jobs::list_rows( $limit, $status );
		$fields = array(
			'job_id', 'status', 'production_id', 'agent_id', 'provider', 'model',
			'driver', 'claim_count', 'worker_id', 'created_at', 'updated_at', 'finished_at',
		);
		WP_CLI\Utils\format_items( 'table', $rows, $fields );
	}

	/**
	 * ## OPTIONS
	 * <job_id>
	 */
	public static function inspect( array $args ): void {
		$job_id = sanitize_text_field( (string) ( $args[0] ?? '' ) );
		$job    = Costudio_BYOK_Jobs::get( $job_id );
		if ( ! $job ) {
			WP_CLI::error( 'BYOK job not found.' );
		}

		$allowed = array(
			'job_id', 'queue_version', 'production_id', 'production_uid', 'agent_id',
			'attempt_id', 'provider', 'model', 'driver', 'status', 'available_at',
			'worker_id', 'claim_count', 'claimed_at', 'processing_started_at',
			'heartbeat_at', 'lease_expires_at', 'provider_dispatched_at', 'first_byte_at',
			'response_received_at', 'error_code', 'error_public', 'retry_safe',
			'terminal_source', 'applied_at', 'usage_recorded_at', 'superseded_at', 'finished_at',
			'payload_purged_at', 'created_at', 'updated_at',
		);
		$safe = array_intersect_key( $job, array_flip( $allowed ) );
		WP_CLI::log( wp_json_encode( $safe, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) );
	}

	/**
	 * Inspect or change the BYOK execution mode.
	 *
	 * Phase 3 requires external_cli plus an explicit license canary. Changing
	 * back to legacy stops new durable submissions without abandoning accepted
	 * jobs.
	 *
	 * ## OPTIONS
	 * [<mode>]
	 * : legacy, durable_loopback, or external_cli.
	 */
	public static function mode( array $args ): void {
		$requested = (string) ( $args[0] ?? '' );
		if ( '' === $requested ) {
			WP_CLI::log( Costudio_BYOK_Jobs::mode() );
			return;
		}

		$normalized = Costudio_BYOK_Jobs::normalize_mode( $requested );
		if ( $normalized !== sanitize_key( $requested ) || ! in_array( $normalized, Costudio_BYOK_Jobs::allowed_modes(), true ) ) {
			WP_CLI::error( 'Mode must be legacy, durable_loopback, or external_cli.' );
		}
		if ( defined( 'COSTUDIO_BYOK_EXECUTION_MODE' ) ) {
			WP_CLI::error( 'COSTUDIO_BYOK_EXECUTION_MODE is defined in wp-config.php and overrides the database option.' );
		}
		if ( Costudio_BYOK_Jobs::MODE_LEGACY !== $normalized && ! Costudio_BYOK_Jobs::pipeline_connected() ) {
			WP_CLI::error( 'Durable BYOK execution is not connected in this phase. Keep the mode on legacy.' );
		}
		if ( ! Costudio_BYOK_Jobs::set_mode( $normalized ) ) {
			WP_CLI::error( 'Could not persist the BYOK execution mode.' );
		}
		WP_CLI::success( "BYOK execution mode set to {$normalized}." );
	}

	public static function cleanup(): void {
		$result = Costudio_BYOK_Jobs::cleanup();
		WP_CLI::success(
			sprintf(
				'BYOK cleanup complete: %d payload(s) purged, %d audit row(s) deleted.',
				(int) $result['payloads_purged'],
				(int) $result['rows_deleted']
			)
		);
	}

	/**
	 * Run the isolated durable BYOK worker. Phase 2 does not submit production
	 * traffic to it yet, so this command is safe while mode remains `legacy`.
	 *
	 * ## OPTIONS
	 * [--max-runtime=<seconds>]
	 * : Maximum process lifetime. Default: 720.
	 *
	 * [--idle-timeout=<seconds>]
	 * : Stop after this many continuously idle seconds. Default: 90.
	 *
	 * [--poll-interval=<seconds>]
	 * : Queue polling interval. Default: 2.
	 */
	public static function work( array $args, array $assoc ): void {
		$worker = new Costudio_BYOK_Worker();
		$result = $worker->run( array(
			'max_runtime' => (int) ( $assoc['max-runtime'] ?? Costudio_BYOK_Worker::DEFAULT_MAX_RUNTIME ),
			'idle_timeout' => (int) ( $assoc['idle-timeout'] ?? Costudio_BYOK_Worker::DEFAULT_IDLE_TIMEOUT ),
			'poll_interval' => (int) ( $assoc['poll-interval'] ?? Costudio_BYOK_Worker::DEFAULT_POLL_INTERVAL ),
		) );
		if ( ! $result['started'] && 'lock_busy' === $result['reason'] ) {
			WP_CLI::success( 'A healthy durable BYOK worker already owns the singleton lock.' );
			return;
		}
		WP_CLI::success(
			sprintf(
				'Durable BYOK worker stopped: reason=%s, processed=%d, elapsed=%ds.',
				(string) $result['reason'],
				(int) $result['processed'],
				(int) $result['elapsed']
			)
		);
	}

	/**
	 * Request cancellation without deleting the audit row.
	 *
	 * ## OPTIONS
	 * <job_id>
	 */
	public static function cancel( array $args ): void {
		$job_id = sanitize_text_field( (string) ( $args[0] ?? '' ) );
		if ( ! Costudio_BYOK_Jobs::request_cancel( $job_id, 'wp_cli' ) ) {
			WP_CLI::error( 'The BYOK job was not found or is already terminal.' );
		}
		WP_CLI::success( 'BYOK cancellation recorded.' );
	}

	/** ## OPTIONS <sha256-license> */
	public static function canary_add( array $args ): void {
		$hash = strtolower( trim( (string) ( $args[0] ?? '' ) ) );
		if ( ! Costudio_BYOK_Jobs::add_canary_hash( $hash ) ) {
			WP_CLI::error( 'Provide a valid 64-character SHA-256 license hash.' );
		}
		WP_CLI::success( 'BYOK durable canary hash added.' );
	}

	/** ## OPTIONS <sha256-license> */
	public static function canary_remove( array $args ): void {
		$hash = strtolower( trim( (string) ( $args[0] ?? '' ) ) );
		if ( ! Costudio_BYOK_Jobs::remove_canary_hash( $hash ) ) {
			WP_CLI::error( 'Could not update the BYOK canary list.' );
		}
		WP_CLI::success( 'BYOK durable canary hash removed.' );
	}

	public static function canary_list(): void {
		foreach ( Costudio_BYOK_Jobs::canary_hashes() as $hash ) {
			WP_CLI::log( $hash );
		}
	}

	public static function current_license_hash(): void {
		$hash = Costudio_BYOK_Jobs::current_license_hash();
		if ( '' === $hash ) {
			WP_CLI::error( 'No Contentosapp license is stored on this installation.' );
		}
		WP_CLI::log( $hash );
	}
}
