<?php

namespace ChinaPayments\RestAPI;

use ChinaPayments\PaymentGateway as CP_PaymentGateway;
use WP_Error;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use ChinaPayments\API\Features as API_Features;

class Webhook {

	public static function register_routes() {
		register_rest_route(
			CHINA_PAYMENTS_REST_API_PREFIX . '/v1',
			'/webhook/stripe-callback/(?P<mode>[\w-]+)',
			array(
				'methods'             => WP_REST_Server::ALLMETHODS,
				'callback'            => '\ChinaPayments\RestAPI\Webhook::stripe_callback',
				'permission_callback' => function () {
					return true;
				},
			)
		);
	}

	public static function stripe_callback( WP_REST_Request $request ) {
		// IMPORTANT: `http_response_code()` is a no-op inside WP REST controllers
		// — WP's REST server overrides it with the WP_REST_Response status. Use
		// `(new WP_REST_Response($body))->set_status($code)` (or WP_Error) so the
		// HTTP status actually reaches the client. Stripe relies on 4xx vs 2xx
		// to decide whether to retry — without this, every failure looks like a
		// success and the event is never re-delivered.
		if ( ! isset( $_SERVER['HTTP_STRIPE_SIGNATURE'] ) ) {
			return new WP_REST_Response(
				array(
					'message' => sprintf( __( '%s not found', 'wp-stripe-global-payments' ), 'HTTP_STRIPE_SIGNATURE' ),
				),
				400
			);
		}

		$mode = $request->get_param( 'mode' );

		if ( ! class_exists( '\Stripe\Stripe' ) ) {
			require_once CHINA_PAYMENTS_BASE_PATH . '/lib/stripe/init.php';
		}

		$payload = $request->get_body();

		$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];

		try {
			$event = \Stripe\Webhook::constructEvent(
				$payload,
				$sig_header,
				china_payments_setting_get( 'stripe_' . $mode . '_webhook_secret' )
			);
		} catch ( \UnexpectedValueException $e ) {
			// Invalid JSON payload.
			return new WP_REST_Response(
				array(
					'message' => __( 'Invalid Payload', 'wp-stripe-global-payments' ),
				),
				400
			);
		} catch ( \Stripe\Exception\SignatureVerificationException $e ) {
			// Bad signature — Stripe must retry, so return 400 (not 200).
			// Without this catch, the exception bubbles up as HTTP 500 which
			// Stripe will also retry, but with noisier downstream behavior.
			return new WP_REST_Response(
				array(
					'message' => __( 'Invalid Signature', 'wp-stripe-global-payments' ),
				),
				400
			);
		}

		if ( ! isset( $event->data->object->metadata->cp_integration ) ) {
			return new WP_REST_Response(
				array(
					'message' => sprintf( __( 'Event not tracked, %s metadata not attached', 'wp-stripe-global-payments' ), 'cp_integration' ),
				),
				200
			);
		}

		if ( ! isset( $event->data->object->metadata->domain_name ) || $event->data->object->metadata->domain_name !== china_payments_domain_name() ) {
			return new WP_REST_Response(
				array(
					'message' => sprintf( __( 'Event not tracked, %s metadata does not match', 'wp-stripe-global-payments' ), 'domain_name' ),
				),
				200
			);
		}

		if ( $event->type != 'payment_intent.succeeded' ) {
			return new WP_REST_Response(
				array(
					'message' => __( 'Event not tracked', 'wp-stripe-global-payments' ),
				),
				200
			);
		}

		if ( $event->data->object->metadata->cp_integration === 'woocommerce' && function_exists( 'wc_get_payment_gateway_by_order' ) ) {
			$order = wc_get_order( $event->data->object->metadata->order_id );

			if ( ! $order instanceof \WC_Order ) {
				// Order metadata pointed at a non-existent / non-WC order. Acknowledge
				// the event with 200 so Stripe stops retrying — don't 500.
				return new WP_REST_Response(
					array(
						'message' => sprintf( __( 'Event not tracked, %s metadata refers to unknown order', 'wp-stripe-global-payments' ), 'order_id' ),
					),
					200
				);
			}

			// Already settled (a prior delivery, or the 15-minute reconciliation
			// sweep). Acknowledge so Stripe stops retrying.
			if ( $order->is_paid() ) {
				return new WP_REST_Response(
					array(
						'message' => __( 'Order already paid', 'wp-stripe-global-payments' ),
					),
					200
				);
			}

			$is_live = ( $mode === 'live' ? 1 : 0 );

			// Acknowledge Stripe immediately and finish the work — the Stripe API
			// round-trip plus order completion — in the background via Action
			// Scheduler. Keeping the webhook response sub-second means a burst of
			// deliveries can't exhaust PHP-FPM workers, and a slow/late response
			// can't trip Stripe's retry escalation. The async worker re-checks the
			// order before completing (idempotent), and the existing 15-minute
			// reconciliation sweep remains as a fallback.
			if ( \ChinaPayments\ActionScheduler::enqueue_webhook_payment( $order->get_id(), $is_live ) ) {
				return new WP_REST_Response(
					array(
						'message' => sprintf( __( 'Queued %s payment for processing', 'wp-stripe-global-payments' ), 'WooCommerce' ),
					),
					202
				);
			}

			// Fallback when Action Scheduler is unavailable: process inline
			// (the pre-3.5.6 behaviour).
			$stripeIntegration = CP_PaymentGateway::get_integration_from_settings( 'stripe', $is_live );
			$payment_intent_id = $order->get_meta( 'china_payments_payment_intent_id' );

			try {
				$payment_intent = $stripeIntegration->stripeClient()->paymentIntents->retrieve( $payment_intent_id );

				if ( $payment_intent->status !== 'succeeded' ) {
					return rest_ensure_response(
						array(
							'message' => __( 'Order Payment Intent Failed', 'wp-stripe-global-payments' ),
						)
					);
				}
			} catch ( \Exception $e ) {
				error_log( '[China Payments] Stripe webhook WooCommerce error: ' . $e->getMessage() );
				return rest_ensure_response(
					array(
						'message' => __( 'Payment verification failed', 'wp-stripe-global-payments' ),
					)
				);
			}

			if ( ! $order->is_paid() ) {
				$order->payment_complete( $payment_intent->id );
			}

			return new WP_REST_Response(
				array(
					'message' => sprintf( __( 'Handled %s Callback', 'wp-stripe-global-payments' ), 'WooCommerce' ),
				),
				201
			);
		}

		// @todo here.
		if ( $event->data->object->metadata->cp_integration === 'memberpress' && function_exists( 'wc_get_payment_gateway_by_order' ) ) {
			/**
			$stripeIntegration = CP_PaymentGateway::get_integration_from_settings( 'stripe', ( $mode === 'live' ? 1 : 0 ) );
			$order = wc_get_order( $event->data->object->metadata->order_id );
			$payment_intent_id = $order->get_meta( 'china_payments_payment_intent_id' );
			try {
				$payment_intent = $stripeIntegration->stripeClient()->paymentIntents->retrieve( $payment_intent_id );
				if( $payment_intent->status !== 'succeeded' )
				return rest_ensure_response( [
					'message' => __( "Order Payment Intent Failed", "china-payments" )
				] );
			} catch ( \Exception $e ) {
				exit( $e->getMessage() );
			}
			if( !$order->is_paid() )
				$order->payment_complete( $payment_intent->id );
			*/

			return new WP_REST_Response(
				array(
					'message' => sprintf( __( 'Handled %s Callback', 'wp-stripe-global-payments' ), 'MemberPress' ),
				),
				201
			);
		}

		if ( $event->data->object->metadata->cp_integration === 'lifterlms' && class_exists( '\LLMS_Order' ) ) {
			$stripeIntegration = CP_PaymentGateway::get_integration_from_settings( 'stripe', ( $mode === 'live' ? 1 : 0 ) );
			$order             = new \LLMS_Order( $event->data->object->metadata->order_id );
			$payment_intent_id = get_post_meta( $order->id, 'china_payments_payment_intent_id', true );

			try {
				$payment_intent = $stripeIntegration->stripeClient()->paymentIntents->retrieve( $payment_intent_id );

				if ( $payment_intent->status !== 'succeeded' ) {
					return rest_ensure_response(
						array(
							'message' => __( 'Order Payment Intent Failed', 'wp-stripe-global-payments' ),
						)
					);
				}
			} catch ( \Exception $e ) {
				error_log( '[China Payments] Stripe webhook LifterLMS error: ' . $e->getMessage() );
				return rest_ensure_response(
					array(
						'message' => __( 'Payment verification failed', 'wp-stripe-global-payments' ),
					)
				);
			}

			if ( $order->status !== 'completed' && $order->status !== 'llms-completed' ) {
				$order->record_transaction(
					array(
						'amount'         => $order->total,
						'transaction_id' => ( ! empty( $payment_intent->latest_charge ) ? $payment_intent->latest_charge : $payment_intent->id ),
					)
				);
				$order->set_status( 'completed' );
			}

			return new WP_REST_Response(
				array(
					'message' => sprintf( __( 'Handled %s Callback', 'wp-stripe-global-payments' ), 'WooCommerce' ),
				),
				201
			);
		}

		return new WP_REST_Response(
			array(
				'message' => __( 'Handled Callback', 'wp-stripe-global-payments' ),
			),
			201
		);
	}
}
