<?php
/**
 * Local/dev payment confirmation without webhooks (Downloads / Paywall pattern).
 *
 * @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\Settings\Settings;
use WP_REST_Request;
use WP_REST_Response;

/**
 * POST /confirm-payment
 *
 * Dev/local only (test mode + setting). Requires the checkout return token
 * (Stripe success URL) plus an order-bound nonce. A UUID alone cannot confirm.
 */
final class Confirm_Payment_Controller {

	/**
	 * Nonce action for a checkout return order (status poll + local confirm).
	 */
	public static function nonce_action( string $uuid ): string {
		return 'wpdude_dc_confirm_payment_' . sanitize_text_field( $uuid );
	}

	/**
	 * Register routes.
	 */
	public function register_routes(): void {
		register_rest_route(
			REST_Loader::NAMESPACE,
			'/confirm-payment',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'confirm' ),
				'permission_callback' => array( $this, 'permissions' ),
				'args'                => array(
					'order'       => array(
						'required'          => false,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					),
					'transaction' => array(
						'required'          => false,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					),
					'nonce'       => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					),
					'token'       => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
			)
		);
	}

	/**
	 * Read a param from request, including JSON body (permission_callback safe).
	 */
	private function param( WP_REST_Request $request, string $key ): string {
		$value = (string) $request->get_param( $key );
		if ( '' !== $value ) {
			return sanitize_text_field( $value );
		}
		$json = $request->get_json_params();
		if ( is_array( $json ) && isset( $json[ $key ] ) ) {
			return sanitize_text_field( (string) $json[ $key ] );
		}
		return '';
	}

	/**
	 * Local confirm only: test-mode setting + valid per-order nonce + known order.
	 *
	 * @return true|\WP_Error
	 */
	public function permissions( WP_REST_Request $request ) {
		if ( ! Settings::allows_local_payment_confirm() ) {
			return new \WP_Error(
				'wpdude_dc_local_confirm_disabled',
				__( 'Local payment confirmation is disabled.', 'dude-commerce' ),
				array( 'status' => 403 )
			);
		}

		$uuid = $this->param( $request, 'order' );
		if ( '' === $uuid ) {
			$uuid = $this->param( $request, 'transaction' );
		}
		$nonce = $this->param( $request, 'nonce' );
		$token = $this->param( $request, '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 ( '' === $nonce || ! wp_verify_nonce( $nonce, self::nonce_action( $uuid ) ) ) {
			return new \WP_Error(
				'wpdude_dc_invalid_nonce',
				__( '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;
	}

	/**
	 * Confirm payment by asking Stripe directly (simulates webhook on Local).
	 *
	 * @return WP_REST_Response|\WP_Error
	 */
	public function confirm( WP_REST_Request $request ) {
		$uuid = $this->param( $request, 'order' );
		if ( '' === $uuid ) {
			$uuid = $this->param( $request, 'transaction' );
		}

		$result = ( new Payment_Completion_Service() )->confirm_from_stripe( $uuid );
		if ( is_wp_error( $result ) ) {
			$status = (int) ( $result->get_error_data()['status'] ?? 400 );
			return new \WP_Error( $result->get_error_code(), $result->get_error_message(), array( 'status' => $status ) );
		}

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