<?php
/**
 * Order status endpoint for checkout return polling.
 *
 * @package WPDudeProducts
 */

declare(strict_types=1);

namespace WPDude\Products\REST;

use WPDude\Products\Checkout\Payment_Completion_Service;
use WPDude\Products\Orders\Order_Repository;
use WPDude\Products\Orders\Statuses;
use WP_REST_Request;
use WP_REST_Response;

/**
 * GET /order-status/{uuid}
 *
 * Guests on the Stripe return page may poll, but must present the checkout
 * return token from the Stripe success URL. A UUID (or a WP nonce minted on a
 * UUID-only URL) is not authorization.
 */
final class Order_Status_Controller {

	/**
	 * Register routes.
	 */
	public function register_routes(): void {
		register_rest_route(
			REST_Loader::NAMESPACE,
			'/order-status/(?P<uuid>[a-f0-9\-]{36})',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'status' ),
				'permission_callback' => array( $this, 'permissions' ),
				'args'                => array(
					'uuid'  => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					),
					'token' => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
			)
		);
	}

	/**
	 * Checkout return token + known order. UUID alone is not enough.
	 *
	 * @return true|\WP_Error
	 */
	public function permissions( WP_REST_Request $request ) {
		$uuid  = sanitize_text_field( (string) $request->get_param( 'uuid' ) );
		$token = sanitize_text_field( (string) $request->get_param( 'token' ) );

		if ( '' === $uuid || ! preg_match( '/^[a-f0-9\-]{36}$/i', $uuid ) ) {
			return new \WP_Error(
				'wpdude_dc_invalid_order',
				__( 'Invalid order.', 'dude-commerce' ),
				array( 'status' => 400 )
			);
		}

		if ( ! Order_Repository::is_return_token_format( $token ) ) {
			return new \WP_Error(
				'wpdude_dc_invalid_token',
				__( 'Please refresh the page and try again.', 'dude-commerce' ),
				array( 'status' => 403 )
			);
		}

		$order = ( new Order_Repository() )->find_by_uuid( $uuid );
		if ( ! $order || ! Order_Repository::return_token_matches( $order, $token ) ) {
			return new \WP_Error(
				'wpdude_dc_invalid_token',
				__( 'Please refresh the page and try again.', 'dude-commerce' ),
				array( 'status' => 403 )
			);
		}

		return true;
	}

	/**
	 * Status payload for the checkout return page.
	 *
	 * @return WP_REST_Response|\WP_Error
	 */
	public function status( WP_REST_Request $request ) {
		$uuid  = sanitize_text_field( (string) $request->get_param( 'uuid' ) );
		$token = sanitize_text_field( (string) $request->get_param( 'token' ) );
		$order = ( new Order_Repository() )->find_by_uuid( $uuid );

		if ( ! $order || ! Order_Repository::return_token_matches( $order, $token ) ) {
			return new \WP_Error(
				'wpdude_dc_invalid_token',
				__( 'Please refresh the page and try again.', 'dude-commerce' ),
				array( 'status' => 403 )
			);
		}

		$status  = (string) $order['status'];
		$payload = array(
			'uuid'       => (string) $order['uuid'],
			'status'     => $status,
			'product_id' => (int) $order['product_id'],
		);

		if ( Statuses::NEW === $status ) {
			$payload = array_merge( $payload, Payment_Completion_Service::public_success_payload( $order ) );
		} elseif ( Statuses::EXPIRED === $status || Statuses::FAILED === $status ) {
			$payload['success_message'] = __( 'Payment was not completed.', 'dude-commerce' );
		}

		return new WP_REST_Response( $payload, 200 );
	}
}
