<?php
/**
 * Form-scoped DomainEvents listener.
 *
 * Overrides the three lifecycle hooks the TWINT TransactionService fires when
 * a transaction lands on a p4all_order, so that we never hit the shop order
 * lookup / WooBridge::update_order_successful (which would silently fail or worse).
 *
 *   on_before_handle_successful_payment  → mark the p4all_order as "TWINT in flight"
 *   on_successful_payment                → mark payment_status = 'paid' + add note
 *   on_failed_payment                    → mark payment_status = 'failed' + add note
 *
 * Also overrides spawn_monitor_order_task so the background polling fires
 * Form-scoped actions (p4all_form_monitor_order[_immediate]) that
 * FormBackgroundMonitor handles, instead of TwintGateway's WC handler.
 */

namespace Twnt4All\Pay4All;

use Twnt4All\Engine\Adapter\DomainEvents;

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

final class FormDomainEvents extends DomainEvents
{
    /**
     * The parent uses a `ConfigAwareTrait` whose $data_provider property is
     * `private` - subclasses can't see it. Without this shadow copy any
     * `$this->data_provider->...` access from here would resolve to a fresh
     * dynamic null property, breaking every lifecycle hook with a
     *   "Call to a member function get_order_id() on null"
     * fatal as soon as start_order() fires the first event.
     *
     * @var \Twnt4All\Engine\Contract\ConfigProviderInterface
     */
    protected $form_provider;

    public function __construct( $data_provider )
    {
        parent::__construct( $data_provider );
        $this->form_provider = $data_provider;
    }

    // -----------------------------------------------------------------
    // Lifecycle hooks
    // -----------------------------------------------------------------

    public function on_before_handle_successful_payment()
    {
        $order_id = (int) $this->form_provider->get_order_id();
        update_post_meta( $order_id, '_p4all_twint_payment_in_flight', time() );
    }

    public function on_successful_payment( $lock = null )
    {
        $order_id = (int) $this->form_provider->get_order_id();
        if ( $order_id <= 0 ) { return; }

        // Idempotency: skip if we've already finalized this order.
        if ( (string) get_post_meta( $order_id, '_p4all_twint_payment_status', true ) === 'SUCCESS' ) {
            return;
        }

        if ( ! class_exists( '\\Pay4All\\Form\\Domain\\Order' ) ) {
            return;
        }

        $this->mark_payment_paid( $order_id );
        update_post_meta( $order_id, '_p4all_twint_payment_status', 'SUCCESS' );
    }

    public function on_failed_payment( $reason )
    {
        $order_id = (int) $this->form_provider->get_order_id();
        if ( $order_id <= 0 ) { return; }

        $this->mark_payment_failed( $order_id, (string) $reason );
    }

    // -----------------------------------------------------------------
    // Background polling - route to Form-scoped actions, not WC's.
    // -----------------------------------------------------------------

    public function spawn_monitor_order_task( $time = 0 )
    {
        $order_id   = $this->form_provider->get_order_id();
        $order_uuid = $this->form_provider->get_order_uuid();

        $bg_immediate = get_option( 't4a_twint_async_bg_immediate' ) ?: T4A_DEFAULT_ASYNC_REQUEST_IMMEDIATE;
        if ( $bg_immediate === 'yes' ) {
            // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- vendor Async-Task action name for Pay4All Form ; must match FormImmediateMonitorJob's listener string.
            do_action( 'p4all_form_monitor_order_immediate', $order_id, $order_uuid, $time );
        }

        $bg_shutdown = get_option( 't4a_twint_async_bg_shutdown' ) ?: T4A_DEFAULT_ASYNC_REQUEST_SHUTDOWN;
        if ( $bg_shutdown === 'yes' ) {
            // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- vendor Async-Task action name for Pay4All Form ; must match FormMonitorJob's listener string.
            do_action( 'p4all_form_monitor_order', $order_id, $order_uuid, $time );
        }
    }

    // -----------------------------------------------------------------
    // Helpers - write through to Pay4All Form's domain layer.
    // -----------------------------------------------------------------

    private function mark_payment_paid( int $order_id ) : void
    {
        if ( class_exists( '\\Pay4All\\Form\\Domain\\Order' ) ) {
            \Pay4All\Form\Domain\Order::update_payment_status( $order_id, 'paid' );

            // Route the ORDER post_status to whatever the merchant configured
            // on the wizard's "Pay4All Shop" tab : virtual/ticket-only ->
            // merchant's 'virtual' status, any physical item -> merchant's
            // 'physical' status. The helper returns a Pay4All Shop post-
            // status slug directly (p4all_processing / p4all_completed / ...).
            $target = \Twnt4All\Backend\ConfigPage::paid_status_for_p4all_form_order( $order_id );
            \Pay4All\Form\Domain\Order::update_status( $order_id, $target );

            $when = function_exists( 'wp_date' )
                ? wp_date( get_option( 'date_format', 'F j, Y' ) . ' \a\t G\hi', current_time( 'timestamp' ) )
                : date_i18n( get_option( 'date_format', 'F j, Y' ) . ' \a\t G\hi' );
            \Pay4All\Form\Domain\Order::add_note(
                $order_id,
                /* translators: %s: localized date and time when TWINT confirmed the payment */
                sprintf( __( 'TWINT payment confirmed on %s.', 'pay4all-for-twint' ), $when ),
                false
            );
        }
    }

    private function mark_payment_failed( int $order_id, string $reason ) : void
    {
        if ( class_exists( '\\Pay4All\\Form\\Domain\\Order' ) ) {
            \Pay4All\Form\Domain\Order::update_payment_status( $order_id, 'failed' );
            \Pay4All\Form\Domain\Order::add_note(
                $order_id,
                /* translators: %s: reason string returned by the TWINT SOAP layer */
                sprintf( __( 'TWINT payment failed (%s).', 'pay4all-for-twint' ), $reason ),
                false
            );
        }
    }
}
