<?php

namespace Pay4AllForMypos\Checkout;

use Pay4AllForMypos\Backend\ConfigPage;
use Pay4AllForMypos\Support\Journal;

defined( 'ABSPATH' ) || exit;

/**
 * Handles the customer-facing return from myPOS Checkout.
 *
 * myPOS redirects the browser back to our URL_OK or URL_Cancel (both
 * share the same wc-api endpoint as the notify URL - see IpcFormBuilder).
 * WebhookHandler owns the wc-api hook and delegates here when the request
 * is NOT a signed POST with an IPCmethod field.
 *
 *   ?wc-api=wc_gateway_pay4all_for_mypos&ipc=ok&order_id=123     -> success return
 *   ?wc-api=wc_gateway_pay4all_for_mypos&ipc=cancel&order_id=123 -> cancel return
 *
 * The actual money confirmation happens on the SERVER-to-SERVER
 * IPCPurchaseNotify (handled by WebhookHandler) ; this class only sends
 * the customer to the right WooCommerce page.
 */
final class ReturnHandler
{
    /**
     * Kept for API symmetry with WebhookHandler / other handler classes.
     * The actual wc-api hook is owned by WebhookHandler::register().
     */
    public static function register() : void
    {
        // Intentionally empty - WebhookHandler owns the wc-api hook and
        // dispatches here via ReturnHandler::handle_return().
    }

    /**
     * Entry point invoked by WebhookHandler::dispatch() when the incoming
     * request is a customer return (GET or POST without IPCmethod).
     * Never returns.
     */
    public static function handle_return() : void
    {
        // phpcs:disable WordPress.Security.NonceVerification.Recommended -- return URL is signed with a WC order key ; verified via order lookup below.
        $ipc      = isset( $_GET['ipc'] ) ? sanitize_key( (string) wp_unslash( $_GET['ipc'] ) ) : '';
        $order_id = isset( $_GET['order_id'] ) ? (int) $_GET['order_id'] : 0;
        // phpcs:enable WordPress.Security.NonceVerification.Recommended

        if ( $ipc === '' ) {
            // No hint - land the customer safely at the shop home. This can
            // happen if myPOS ever fires a GET on URL_Notify (their spec
            // uses POST but we're defensive).
            wp_safe_redirect( home_url( '/' ) );
            exit;
        }

        $order = $order_id > 0 ? wc_get_order( $order_id ) : null;
        if ( ! $order instanceof \WC_Order ) {
            Journal::error( sprintf( 'Return: order #%d not found (ipc=%s)', $order_id, $ipc ) );
            wp_safe_redirect( wc_get_page_permalink( 'shop' ) ?: home_url( '/' ) );
            exit;
        }

        switch ( $ipc ) {
            case 'ok':
                self::handle_ok( $order );
                break;

            case 'cancel':
                self::handle_cancel( $order );
                break;

            default:
                Journal::error( sprintf( 'Return: unknown ipc value "%s" for order #%d', $ipc, $order_id ) );
                wp_safe_redirect( $order->get_checkout_order_received_url() );
                exit;
        }
    }

    /**
     * Customer came back on URL_OK. The IPCPurchaseNotify webhook is the
     * source of truth for the payment status - here we just send the
     * customer to the WooCommerce thank-you page. Don't try to flip the
     * status ourselves : the webhook may race us either way.
     */
    private static function handle_ok( \WC_Order $order ) : void
    {
        // If the notify already landed the order is paid ; nothing to do
        // here beyond redirecting. Otherwise leave it pending - the notify
        // will finalize it in the background.
        if ( ! $order->is_paid() ) {
            $order->add_order_note( __( 'Pay4All for myPOS: customer returned from myPOS (URL_OK). Waiting for server notification.', 'pay4all-for-mypos' ) );
            $order->save();
        }
        Journal::event( sprintf( 'Return OK order #%d (paid=%s)', (int) $order->get_id(), $order->is_paid() ? 'yes' : 'no' ) );

        wp_safe_redirect( $order->get_checkout_order_received_url() );
        exit;
    }

    /**
     * Customer clicked "Cancel" on the myPOS page. Move the order to the
     * merchant's chosen cancellation status and send the customer back to
     * the checkout with a notice.
     */
    private static function handle_cancel( \WC_Order $order ) : void
    {
        if ( ! $order->is_paid() ) {
            $order->update_status(
                ConfigPage::get_status_cancelled(),
                __( 'Pay4All for myPOS: customer cancelled at myPOS (URL_Cancel).', 'pay4all-for-mypos' )
            );
            $order->save();
        }

        if ( function_exists( 'wc_add_notice' ) ) {
            wc_add_notice( __( 'Payment cancelled. You can pick another method to complete your order.', 'pay4all-for-mypos' ), 'notice' );
        }

        Journal::event( sprintf( 'Return CANCEL order #%d', (int) $order->get_id() ) );

        $checkout = wc_get_checkout_url();
        wp_safe_redirect( $checkout ?: $order->get_cancel_order_url() );
        exit;
    }
}
