<?php
/**
 * Same as FormMonitorJob but registers `launch_now` instead of `launch` so the
 * dispatch fires synchronously on the original request thread (the loopback
 * still happens). Mirrors Checkout\ImmediateMonitorJob.
 *
 * Without this class, do_action('p4all_form_monitor_order_immediate', …) from
 * FormDomainEvents::spawn_monitor_order_task would resolve to a regular
 * synchronous listener and block the customer's redirect to the TWINT page
 * for the full SOAP polling window.
 */

namespace Twnt4All\Pay4All;

use Twnt4All\Support\Journal;
use Twnt4All\Vendor\AsyncTask\WP_Async_Task;

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

final class FormImmediateMonitorJob extends WP_Async_Task
{
    protected $action = 'p4all_form_monitor_order_immediate';

    public function __construct( $auth_level = self::BOTH )
    {
        if ( empty( $this->action ) ) {
            throw new \Exception( 'Action not defined for class ' . __CLASS__ );
        }
        // `launch_now` (vs `launch`) skips the shutdown queueing — useful when
        // the original request is already short and we want the loopback to
        // start as soon as the action fires.
        add_action( $this->action, [ $this, 'launch_now' ], (int) $this->priority, (int) $this->argument_count );

        if ( $auth_level & self::LOGGED_IN ) {
            add_action( 'admin_post_wp_async_' . $this->action, [ $this, 'handle_postback' ] );
        }
        if ( $auth_level & self::LOGGED_OUT ) {
            add_action( 'admin_post_nopriv_wp_async_' . $this->action, [ $this, 'handle_postback' ] );
        }
    }

    protected function prepare_data( $data )
    {
        return [
            'order_id'   => $data[ 0 ] ?? 0,
            'order_uuid' => $data[ 1 ] ?? '',
            'time'       => $data[ 2 ] ?? 0,
        ];
    }

    protected function run_action()
    {
        Journal::event( sprintf( 'Running async task %1$s', $this->action ) );
        // Redundant defensive nonce check inside run_action() itself so the
        // origin verification is co-located with the $_POST reads below.
        // handle_postback() already verifies this same nonce upstream ; the
        // duplicate call makes the CSRF guard obvious to code readers.
        // Plugin Check does not recognize WP_Async_Task::verify_async_nonce()
        // as a nonce verification function, so the phpcs:disable below
        // silences the false positive.
        // phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce verified in the same function via $this->verify_async_nonce($async_nonce) on the very next line ; static analyzers do not follow custom nonce helpers.
        $async_nonce = isset( $_POST[ '_nonce' ] ) ? sanitize_text_field( wp_unslash( (string) $_POST[ '_nonce' ] ) ) : '';
        if ( ! $this->verify_async_nonce( $async_nonce ) ) {
            return;
        }
        // phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- vendor Async-Task pattern ; hook name is derived from $this->action.
        do_action(
            'wp_async_' . $this->action,
            absint( $_POST[ 'order_id' ] ?? 0 ),
            sanitize_text_field( wp_unslash( (string) ( $_POST[ 'order_uuid' ] ?? '' ) ) ),
            absint( $_POST[ 'time' ] ?? 0 )
        );
        // phpcs:enable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound,WordPress.Security.NonceVerification.Missing
    }
}
