<?php
/**
 * WP-CLI: `wp seo-flight-recorder check|status`.
 *
 * JSON output is part of the free plugin — no artificial gate.
 *
 * @package SEO_Flight_Recorder
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Records and reports SEO-critical output changes.
 */
class SFRec_CLI {

	/**
	 * Run a check now (synchronously, all pages, no batch chaining).
	 *
	 * ## OPTIONS
	 *
	 * [--format=<format>]
	 * : Output format: table or json. Default: table.
	 *
	 * ## EXAMPLES
	 *
	 *     wp seo-flight-recorder check
	 *     wp seo-flight-recorder check --format=json
	 *
	 * @param array $args       Positional args (unused).
	 * @param array $assoc_args Associative args.
	 */
	public function check( $args, $assoc_args ) {
		unset( $args );

		// CLI runs synchronously: process every batch inline until done.
		$token = SFRec_Scanner::start_run( 'manual' );
		if ( is_wp_error( $token ) ) {
			// A stuck run older than its transient TTL self-heals; report as-is.
			WP_CLI::error( $token->get_error_message() );
		}

		$guard = 0;
		while ( get_transient( 'sfrec_active_run' ) && $guard < 500 ) {
			$run = get_transient( 'sfrec_active_run' );
			if ( ! is_array( $run ) || empty( $run['token'] ) ) {
				break;
			}
			// Find the next scheduled batch for this token and run it inline.
			$next = false;
			$crons = _get_cron_array();
			if ( is_array( $crons ) ) {
				foreach ( $crons as $hooks ) {
					if ( isset( $hooks['sfrec_run_batch'] ) ) {
						foreach ( $hooks['sfrec_run_batch'] as $event ) {
							if ( isset( $event['args'][0] ) && $event['args'][0] === $run['token'] ) {
								$next = $event['args'];
								break 2;
							}
						}
					}
				}
			}
			if ( false === $next ) {
				break; // Run finished (or finishing) with no pending batch.
			}
			wp_clear_scheduled_hook( 'sfrec_run_batch', $next );
			SFRec_Scanner::process_batch( $next[0], (int) $next[1] );
			$guard++;
		}

		$this->status( array(), $assoc_args );
	}

	/**
	 * Show open findings and monitoring state.
	 *
	 * ## OPTIONS
	 *
	 * [--format=<format>]
	 * : Output format: table or json. Default: table.
	 *
	 * ## EXAMPLES
	 *
	 *     wp seo-flight-recorder status --format=json
	 *
	 * @param array $args       Positional args (unused).
	 * @param array $assoc_args Associative args.
	 */
	public function status( $args, $assoc_args ) {
		unset( $args );
		global $wpdb;

		$format = isset( $assoc_args['format'] ) ? $assoc_args['format'] : 'table';
		$state  = get_option( 'sfrec_state', array() );
		$rows   = $wpdb->get_results( "SELECT id, page_id, field, before_val, after_val, severity, classification, status, detected_at FROM {$wpdb->prefix}sfrec_changes WHERE status IN ('new','seen') ORDER BY id DESC LIMIT 100", ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- own table.

		if ( 'json' === $format ) {
			WP_CLI::line(
				wp_json_encode(
					array(
						'loopback_ok'   => isset( $state['loopback_ok'] ) ? (bool) $state['loopback_ok'] : null,
						'last_check'    => isset( $state['last_check'] ) ? (int) $state['last_check'] : 0,
						'sitemap_url'   => isset( $state['sitemap_url'] ) ? $state['sitemap_url'] : '',
						'sitemap_count' => isset( $state['sitemap_count'] ) ? (int) $state['sitemap_count'] : 0,
						'open_findings' => $rows,
					)
				)
			);
			return;
		}

		if ( isset( $state['loopback_ok'] ) && false === $state['loopback_ok'] ) {
			WP_CLI::warning( 'Monitoring impaired: loopback self-check failed — ' . ( isset( $state['loopback_error'] ) ? $state['loopback_error'] : '' ) );
		}

		if ( empty( $rows ) ) {
			WP_CLI::success( 'No open findings.' );
			return;
		}

		WP_CLI\Utils\format_items( 'table', $rows, array( 'id', 'severity', 'field', 'after_val', 'classification', 'status', 'detected_at' ) );
	}
}
