<?php
/**
 * REST endpoint hit by checkout JS after the browser completes the 3-D Secure
 * method or challenge flow. Drives the server-side finalize round-trip through
 * {@see \WeeConnectPay\Integrations\WeeConnectPayOrderProcessor::finalizeThreeDSCharge()}
 * and returns the same envelope shape the checkout JS expects from the initial
 * `process_payment` call.
 *
 * @since 4.2.0
 */

use WeeConnectPay\Integrations\IntegrationSettings;
use WeeConnectPay\Integrations\LogService;
use WeeConnectPay\WordPress\Plugin\includes\WeeConnectPayOrderProcessor;

class WC_ThreeDSFinalizeController extends WP_REST_Controller {

	protected $namespace = 'weeconnectpay/v1';

	public function register_routes() {
		register_rest_route(
			$this->namespace,
			'/woocommerce/3ds/finalize',
			array(
				array(
					'methods'             => 'POST',
					'callback'            => array( $this, 'finalize' ),
					'permission_callback' => array( $this, 'permissions_check' ),
					'args'                => array(
						'order_id'    => array(
							'required' => true,
							'type'     => 'integer',
						),
						'order_key'   => array(
							'required' => true,
							'type'     => 'string',
						),
						'nonce'       => array(
							'required' => true,
							'type'     => 'string',
						),
						'charge_id'   => array(
							'required' => true,
							'type'     => 'string',
						),
						'flow_status' => array(
							'required' => true,
							'type'     => 'string',
						),
					),
				),
			)
		);
	}

	/**
	 * Verify the per-order nonce plus the order key — checkout is open to
	 * guests, so we can't gate on `current_user_can`. Both are minted at
	 * interim-detection time and travel through the browser in the
	 * weeconnectpay_threeds_interim payload.
	 */
	public function permissions_check( WP_REST_Request $request ): bool {
		$orderId  = (int) $request->get_param( 'order_id' );
		$orderKey = (string) $request->get_param( 'order_key' );
		$nonce    = (string) $request->get_param( 'nonce' );

		if ( $orderId <= 0 || $orderKey === '' || $nonce === '' ) {
			return false;
		}

		if ( ! wp_verify_nonce( $nonce, 'wcp_3ds_finalize_' . $orderId ) ) {
			LogService::warning( sprintf( '3-D Secure finalize rejected — bad nonce for WooCommerce order (#%d)', $orderId ) );
			return false;
		}

		$order = wc_get_order( $orderId );
		if ( ! $order instanceof WC_Order ) {
			return false;
		}

		if ( ! hash_equals( (string) $order->get_order_key(), $orderKey ) ) {
			LogService::warning( sprintf( '3-D Secure finalize rejected — order_key mismatch for WooCommerce order (#%d)', $orderId ) );
			return false;
		}

		if ( $order->get_payment_method() !== 'weeconnectpay' ) {
			LogService::warning( sprintf( '3-D Secure finalize rejected — wrong payment method on WooCommerce order (#%d)', $orderId ) );
			return false;
		}

		return true;
	}

	/**
	 * Run the finalize round-trip and convert the processor's
	 * process_payment-shaped result into a JSON response the checkout JS can
	 * act on.
	 *
	 * Shape contract:
	 *   - Terminal success → `{ success: true, redirect: <thank-you-url> }`
	 *   - Escalation       → `{ weeconnectpay_threeds_interim: {...} }`
	 *                         (same shape as the initial interim — JS re-enters
	 *                         the flow controller for the next ACS round)
	 *   - Failure          → `{ success: false, message: <user-facing string> }`
	 */
	public function finalize( WP_REST_Request $request ): WP_REST_Response {
		$orderId    = (int) $request->get_param( 'order_id' );
		$chargeId   = (string) $request->get_param( 'charge_id' );
		$flowStatus = (string) $request->get_param( 'flow_status' );

		$order = wc_get_order( $orderId );
		if ( ! $order instanceof WC_Order ) {
			return new WP_REST_Response(
				array( 'success' => false, 'message' => __( 'Order not found.', 'weeconnectpay' ) ),
				404
			);
		}

		$processor = new WeeConnectPayOrderProcessor( new IntegrationSettings() );
		$result    = $processor->finalizeThreeDSCharge( $order, $chargeId, $flowStatus );

		// Escalation: the finalize call surfaced another interim state.
		// Relay the new payload back to the browser so it can run the next
		// method or challenge round.
		if ( is_array( $result ) && ! empty( $result['weeconnectpay_threeds_interim'] ) ) {
			return new WP_REST_Response(
				array(
					'weeconnectpay_threeds_interim' => $result['weeconnectpay_threeds_interim'],
				),
				200
			);
		}

		$resultStatus = $result['result'] ?? 'fail';

		if ( $resultStatus === 'success' ) {
			return new WP_REST_Response(
				array(
					'success'  => true,
					'redirect' => $result['redirect'] ?? $order->get_checkout_order_received_url(),
				),
				200
			);
		}

		// Failure path — processor already logged + added the order note.
		return new WP_REST_Response(
			array(
				'success' => false,
				'message' => __( 'Payment verification failed. Please try again or use a different card.', 'weeconnectpay' ),
			),
			200
		);
	}
}
