<?php
/**
 * Recording comment/review mutation guard.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChangesWooCommerce\CoreCompat\Recording;

use ScheduledChanges\Repository\RecordingSessionRepository;

/**
 * Prevents separate WordPress comment AJAX actions from mutating a recording source.
 */
final class RecordingCommentGuard {
	private RecordingSessionRepository $sessions;
	public function __construct( RecordingSessionRepository $sessions ) {
		$this->sessions = $sessions;
	}

	/**
	 * Registers guards before WordPress's priority-1 core AJAX handlers.
	 */
	public function register(): void {
		foreach ( array( 'replyto-comment', 'edit-comment', 'delete-comment', 'dim-comment' ) as $action ) {
			add_action( 'wp_ajax_' . $action, array( $this, 'guardRequest' ), 0 );
		}
	}

	/**
	 * Stops an unsupported review mutation while its product is being recorded.
	 */
	public function guardRequest(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Core AJAX handlers verify their action-specific nonces immediately after this mutation guard.
		if ( ! $this->shouldBlock( $_POST ) ) {
			return;
		}

		wp_die(
			esc_html__(
				'Product reviews and comments cannot be changed while this product is being recorded. Finish or abandon the recording first.',
				'jjs-post-scheduler'
			),
			'',
			array( 'response' => 409 )
		);
	}

	/**
	 * Determines whether a comment request targets a product with an active recording.
	 *
	 * @param array<string,mixed> $request AJAX request fields.
	 */
	public function shouldBlock( array $request ): bool {
		$product_id = $this->productId( $request );

		return $product_id > 0
			&& 'product' === get_post_type( $product_id )
			&& null !== $this->sessions->findActiveBySourceIdentity(
				'woocommerce-core',
				'product',
				'product:' . $product_id
			);
	}

	/**
	 * Resolves the request's product ID.
	 *
	 * @param array<string,mixed> $request AJAX request fields.
	 */
	private function productId( array $request ): int {
		$product_id = absint( $request['comment_post_ID'] ?? 0 );

		if ( $product_id > 0 ) {
			return $product_id;
		}

		$comment_id = absint( $request['comment_ID'] ?? $request['id'] ?? 0 );
		$comment    = $comment_id > 0 ? get_comment( $comment_id ) : null;

		return $comment instanceof \WP_Comment ? (int) $comment->comment_post_ID : 0;
	}
}
