<?php
/**
 * Checkout success / cancel return handling (Downloads / Paywall pattern).
 *
 * @package WPDudeProducts
 */

declare(strict_types=1);

namespace WPDude\Products\Frontend;

use WPDude\Products\Checkout\Payment_Completion_Service;
use WPDude\Products\Orders\Order_Repository;
use WPDude\Products\Orders\Statuses;
use WPDude\Products\REST\Confirm_Payment_Controller;
use WPDude\Products\Settings\Settings;

/**
 * Renders return UI via query args on the front end.
 */
final class Return_Pages {

	/**
	 * Whether the return box was already injected this request.
	 */
	private static bool $injected = false;

	/**
	 * Register hooks.
	 */
	public function register(): void {
		// After do_blocks so the product shortcode/block can render inline first.
		add_filter( 'the_content', array( $this, 'maybe_inject' ), 20 );
		add_action( 'wp_enqueue_scripts', array( $this, 'maybe_enqueue' ), 5 );
		add_action( 'wp_footer', array( $this, 'maybe_enqueue' ), 1 );
	}

	/**
	 * Ensure assets load on return URLs.
	 */
	public function maybe_enqueue(): void {
		if ( self::is_checkout_return_request() ) {
			Assets::mark_needed();
		}
	}

	/**
	 * Checkout return status from the request query string.
	 */
	public static function checkout_status_from_request(): string {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only return URL query args.
		return isset( $_GET['wpdude_dc_checkout'] ) ? sanitize_key( wp_unslash( (string) $_GET['wpdude_dc_checkout'] ) ) : '';
	}

	/**
	 * Order UUID from the return URL query string.
	 *
	 * Uses `transaction` (Downloads / Paywall). `order` is a reserved WP query var
	 * and can break the main query / strip the return URL.
	 */
	public static function order_uuid_from_request(): string {
		// phpcs:disable WordPress.Security.NonceVerification.Recommended -- read-only return URL query args.
		$uuid = '';
		if ( isset( $_GET['transaction'] ) ) {
			$uuid = sanitize_text_field( wp_unslash( (string) $_GET['transaction'] ) );
		} elseif ( isset( $_GET['wpdude_dc_order'] ) ) {
			$uuid = sanitize_text_field( wp_unslash( (string) $_GET['wpdude_dc_order'] ) );
		}
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
		if ( '' === $uuid || ! preg_match( '/^[a-f0-9\-]{36}$/i', $uuid ) ) {
			return '';
		}
		return $uuid;
	}

	/**
	 * Checkout return token from the Stripe success/cancel URL.
	 *
	 * This is a high-entropy secret stored on the order. A WP nonce minted
	 * after a UUID-only visit is not a substitute.
	 */
	public static function return_token_from_request(): string {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only return URL query args.
		$token = isset( $_GET['wpdude_dc_rt'] ) ? sanitize_text_field( wp_unslash( (string) $_GET['wpdude_dc_rt'] ) ) : '';
		return Order_Repository::is_return_token_format( $token ) ? strtolower( $token ) : '';
	}

	/**
	 * Order for this return URL when the checkout token matches.
	 *
	 * @return array<string, mixed>|null
	 */
	public static function authorized_order_from_request(): ?array {
		$uuid  = self::order_uuid_from_request();
		$token = self::return_token_from_request();
		if ( '' === $uuid || '' === $token ) {
			return null;
		}

		$order = ( new Order_Repository() )->find_by_uuid( $uuid );
		if ( ! $order || ! Order_Repository::return_token_matches( $order, $token ) ) {
			return null;
		}

		return $order;
	}

	/**
	 * Whether the current request is an authorized checkout return.
	 */
	public static function is_checkout_return_request(): bool {
		$status = self::checkout_status_from_request();
		if ( ! in_array( $status, array( 'success', 'cancel' ), true ) ) {
			return false;
		}

		return null !== self::authorized_order_from_request();
	}

	/**
	 * Product ID for the return order, or 0.
	 */
	public static function return_product_id(): int {
		$order = self::authorized_order_from_request();
		return $order ? (int) $order['product_id'] : 0;
	}

	/**
	 * Whether Buy Now / options should be hidden for a product on this request.
	 */
	public static function should_hide_buy( int $product_id ): bool {
		if ( $product_id <= 0 || ! self::is_checkout_return_request() ) {
			return false;
		}
		if ( 'cancel' === self::checkout_status_from_request() ) {
			return false;
		}
		$return_product = self::return_product_id();
		return $return_product > 0 && $return_product === $product_id;
	}

	/**
	 * Render return UI inline for a product shortcode/block (preferred).
	 */
	public static function render_inline_for_product( int $product_id ): string {
		if ( ! self::is_checkout_return_request() ) {
			return '';
		}

		$status = self::checkout_status_from_request();
		$uuid   = self::order_uuid_from_request();
		$order  = self::authorized_order_from_request();
		if ( '' === $uuid || ! $order || ! in_array( $status, array( 'success', 'cancel' ), true ) ) {
			return '';
		}
		if ( (int) $order['product_id'] !== $product_id ) {
			return '';
		}

		self::$injected = true;
		Assets::mark_needed();

		return ( new self() )->render_box( $status, $uuid, $order );
	}

	/**
	 * Mark that return UI was rendered inline.
	 */
	public static function mark_rendered(): void {
		self::$injected = true;
	}

	/**
	 * Inject success/cancel notice (fallback when no product shortcode matched).
	 */
	public function maybe_inject( string $content ): string {
		if ( self::$injected || is_admin() || ! self::is_checkout_return_request() ) {
			return $content;
		}

		self::$injected = true;
		Assets::mark_needed();

		$status = self::checkout_status_from_request();
		$uuid   = self::order_uuid_from_request();
		$order  = self::authorized_order_from_request();
		if ( ! $order ) {
			return $content;
		}

		return $this->render_box( $status, $uuid, $order ) . $content;
	}

	/**
	 * Status box markup — same pattern as Downloads / Paywall.
	 *
	 * @param array<string, mixed> $order Authorized order.
	 */
	private function render_box( string $status, string $uuid, array $order ): string {
		$local_confirm = Settings::allows_local_payment_confirm();
		$nonce         = '' !== $uuid ? wp_create_nonce( Confirm_Payment_Controller::nonce_action( $uuid ) ) : '';
		$token         = self::return_token_from_request();
		$paid          = Statuses::NEW === (string) $order['status'];
		$payload       = $paid ? Payment_Completion_Service::public_success_payload( $order ) : null;

		ob_start();
		?>
		<div
			class="wpdude-dc-return<?php echo ( 'success' === $status ) ? ' wpdude-dc-return--success' : ''; ?><?php echo $paid ? ' wpdude-dc-return--paid' : ''; ?>"
			data-wpdude-dc-return="<?php echo esc_attr( $status ); ?>"
			data-status="<?php echo esc_attr( $status ); ?>"
			data-uuid="<?php echo esc_attr( $uuid ); ?>"
			<?php if ( $order ) : ?>
				data-product-id="<?php echo esc_attr( (string) (int) $order['product_id'] ); ?>"
			<?php endif; ?>
			<?php echo $local_confirm ? ' data-local-confirm="1"' : ''; ?>
			data-confirm-nonce="<?php echo esc_attr( $nonce ); ?>"
			data-return-token="<?php echo esc_attr( $token ); ?>"
			role="status"
			aria-live="polite"
		>
			<?php if ( 'cancel' === $status ) : ?>
				<p class="wpdude-dc-return__message"><?php echo esc_html__( 'Checkout was cancelled. You have not been charged.', 'dude-commerce' ); ?></p>
			<?php elseif ( $payload ) : ?>
				<p class="wpdude-dc-return__message"><?php echo esc_html( (string) $payload['success_message'] ); ?></p>
				<?php echo $payload['summary_html']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- built with esc_html. ?>
				<p class="wpdude-dc-return__status" aria-live="polite"></p>
			<?php else : ?>
				<p class="wpdude-dc-return__message" data-wpdude-dc-pending>
					<?php echo esc_html__( 'Your payment is being confirmed. This page will update shortly.', 'dude-commerce' ); ?>
				</p>
				<p class="wpdude-dc-return__status" aria-live="polite"></p>
				<div class="wpdude-dc-return__summary" data-wpdude-dc-summary hidden></div>
				<?php if ( $local_confirm && 'success' === $status ) : ?>
					<p class="wpdude-dc-return__local">
						<span class="description"><?php echo esc_html__( 'Local development: webhooks cannot reach this site. After paying in Stripe, click below to confirm the payment with Stripe directly.', 'dude-commerce' ); ?></span>
					</p>
					<p class="wpdude-dc-return__actions">
						<button type="button" class="button wpdude-dc-return__confirm" data-wpdude-dc-confirm-payment>
							<?php echo esc_html__( 'Confirm payment (local test)', 'dude-commerce' ); ?>
						</button>
					</p>
					<p class="wpdude-dc-return__confirm-message" hidden role="status" aria-live="polite"></p>
				<?php endif; ?>
			<?php endif; ?>
		</div>
		<?php
		return (string) ob_get_clean();
	}
}
