<?php
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals -- Template/class file; variables are widget-scoped, not true globals.
/**
 * Thank You (order received) Elementor widgets — Thank You tab toggles in plugin settings.
 *
 * @package storzen
 */

namespace Elementor;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Helpers for thank you / order-received context.
 */
trait Storzen_Thankyou_Widget_Helpers {

	/**
	 * @return bool
	 */
	protected function szp_thankyou_wc_ready() {
		return function_exists( 'WC' ) && function_exists( 'wc_get_order' );
	}

	/**
	 * Resolves the current order on the order-received screen (same rules as WC checkout shortcode).
	 *
	 * Elementor / theme templates sometimes leave `order-received` out of `$wp->query_vars` even when
	 * the URL is `/checkout/order-received/123/?key=...`. Fall back to `get_query_var`, order-key
	 * lookup, and parsing the request path using the configured endpoint slug.
	 *
	 * @return \WC_Order|false
	 */
	protected function szp_thankyou_get_order() {
		if ( ! $this->szp_thankyou_wc_ready() ) {
			return false;
		}
		global $wp;

		$order_id = isset( $wp->query_vars['order-received'] ) ? absint( $wp->query_vars['order-received'] ) : 0;
		if ( ! $order_id ) {
			$order_id = absint( get_query_var( 'order-received' ) );
		}

		$key_raw = empty( $_GET['key'] ) ? '' : wc_clean( wp_unslash( $_GET['key'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized via wc_clean().
		if ( ! $order_id && $key_raw && function_exists( 'wc_get_order_id_by_order_key' ) ) {
			$by_key = wc_get_order_id_by_order_key( $key_raw );
			if ( $by_key ) {
				$order_id = absint( $by_key );
			}
		}

		if ( ! $order_id && ! empty( $_SERVER['REQUEST_URI'] ) ) {
			$endpoint = get_option( 'woocommerce_checkout_order_received_endpoint', 'order-received' );
			$path       = wp_unslash( $_SERVER['REQUEST_URI'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Used only for regex matching to extract numeric order ID.
			if ( preg_match( '#/' . preg_quote( $endpoint, '#' ) . '/(\d+)#', $path, $m ) ) {
				$order_id = absint( $m[1] );
			}
		}

		$order_id = (int) apply_filters( 'woocommerce_thankyou_order_id', $order_id );

		$order_key = apply_filters(
			'woocommerce_thankyou_order_key',
			$key_raw
		);
		if ( $order_id <= 0 ) {
			return false;
		}
		$order = wc_get_order( $order_id );
		if ( ! $order instanceof \WC_Order || ! hash_equals( $order->get_order_key(), $order_key ) ) {
			return false;
		}
		return $order;
	}

	/**
	 * Elementor editor canvas or preview iframe.
	 *
	 * @return bool
	 */
	protected function szp_thankyou_in_elementor_builder() {
		$ed = \Elementor\Plugin::$instance->editor;
		$is_edit = $ed && method_exists( $ed, 'is_edit_mode' ) && $ed->is_edit_mode();
		$preview = \Elementor\Plugin::$instance->preview;
		$is_preview = $preview && method_exists( $preview, 'is_preview_mode' ) && $preview->is_preview_mode();
		return $is_edit || $is_preview;
	}

	/**
	 * Latest order for editor preview when the current URL is not an order-received screen.
	 *
	 * @return \WC_Order|false
	 */
	protected function szp_thankyou_get_latest_order_for_editor_preview() {
		if ( ! function_exists( 'wc_get_orders' ) ) {
			return false;
		}
		$orders = wc_get_orders(
			array(
				'limit'   => 1,
				'orderby' => 'date',
				'order'   => 'DESC',
				'status'  => array( 'completed', 'processing', 'on-hold' ),
				'return'  => 'objects',
			)
		);
		if ( empty( $orders ) ) {
			return false;
		}
		$order = $orders[0];
		return $order instanceof \WC_Order ? $order : false;
	}

	/**
	 * Real order-received order, or a store order used only in the Elementor builder for preview.
	 *
	 * @return array{ order: \WC_Order|false, editor_preview: bool }
	 */
	protected function szp_thankyou_get_order_for_display() {
		$order = $this->szp_thankyou_get_order();
		if ( $order ) {
			return array(
				'order'          => $order,
				'editor_preview' => false,
			);
		}
		if ( ! $this->szp_thankyou_in_elementor_builder() ) {
			return array(
				'order'          => false,
				'editor_preview' => false,
			);
		}
		$preview_order = $this->szp_thankyou_get_latest_order_for_editor_preview();
		if ( $preview_order ) {
			return array(
				'order'          => $preview_order,
				'editor_preview' => true,
			);
		}
		return array(
			'order'          => false,
			'editor_preview' => false,
		);
	}

	/**
	 * Small notice above preview content in Elementor.
	 *
	 * @param bool $using_store_order True when preview uses a real order from the database.
	 */
	protected function szp_thankyou_print_editor_preview_notice( $using_store_order ) {
		if ( $using_store_order ) {
			$msg = __( 'Editor preview: showing your most recent order. On the live site, each customer sees their own order.', 'storzen' );
		} else {
			$msg = __( 'Editor preview: sample layout. Add a test order in WooCommerce to preview real data here.', 'storzen' );
		}
		echo '<p class="szp-thankyou-editor-notice">' . esc_html( $msg ) . '</p>';
	}

	/**
	 * Static sample when the builder is open and the shop has no orders yet.
	 */
	protected function szp_thankyou_render_sample_order_summary() {
		echo '<div class="szp-thankyou-skin szp-thankyou-order-summary szp-thankyou--sample woocommerce">';
		$this->szp_thankyou_print_editor_preview_notice( false );
	echo '<ul class="woocommerce-order-overview woocommerce-thankyou-order-details order_details">';
	echo '<li class="woocommerce-order-overview__order order">';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	esc_html_e( 'Order number:', 'woocommerce' );
	echo ' <strong>12345</strong></li>';
	echo '<li class="woocommerce-order-overview__date date">';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	esc_html_e( 'Date:', 'woocommerce' );
	echo ' <strong>' . esc_html( wp_date( wc_date_format() ) ) . '</strong></li>';
	echo '<li class="woocommerce-order-overview__email email">';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	esc_html_e( 'Email:', 'woocommerce' );
	echo ' <strong>customer@example.com</strong></li>';
	echo '<li class="woocommerce-order-overview__total total">';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	esc_html_e( 'Total:', 'woocommerce' );
	echo ' <strong>' . wp_kses_post( wc_price( 99 ) ) . '</strong></li>';
	echo '<li class="woocommerce-order-overview__payment-method method">';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	esc_html_e( 'Payment method:', 'woocommerce' );
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	echo ' <strong>' . esc_html__( 'Direct bank transfer', 'woocommerce' ) . '</strong></li>';
	echo '</ul></div>';
	}

	/**
	 * Static sample order details table for the editor when no orders exist.
	 */
	protected function szp_thankyou_render_sample_order_details() {
	echo '<div class="szp-thankyou-skin szp-thankyou-order-details-wrap szp-thankyou--sample woocommerce">';
	$this->szp_thankyou_print_editor_preview_notice( false );
	echo '<section class="woocommerce-order-details">';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	echo '<h2 class="woocommerce-order-details__title">' . esc_html__( 'Order details', 'woocommerce' ) . '</h2>';
	echo '<table class="woocommerce-table woocommerce-table--order-details shop_table order_details">';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	echo '<thead><tr><th class="woocommerce-table__product-name product-name">' . esc_html__( 'Product', 'woocommerce' ) . '</th>';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	echo '<th class="woocommerce-table__product-table product-total">' . esc_html__( 'Total', 'woocommerce' ) . '</th></tr></thead><tbody>';
	echo '<tr class="woocommerce-table__line-item order_item"><td class="woocommerce-table__product-name product-name">' . esc_html__( 'Sample product', 'storzen' ) . ' &times; <strong>1</strong></td>';
	echo '<td class="woocommerce-table__product-total product-total">' . wp_kses_post( wc_price( 99 ) ) . '</td></tr>';
	echo '</tbody><tfoot>';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	echo '<tr><th scope="row">' . esc_html__( 'Subtotal:', 'woocommerce' ) . '</th><td>' . wp_kses_post( wc_price( 99 ) ) . '</td></tr>';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	echo '<tr><th scope="row">' . esc_html__( 'Total:', 'woocommerce' ) . '</th><td>' . wp_kses_post( wc_price( 99 ) ) . '</td></tr>';
	echo '</tfoot></table>';
	echo '<section class="woocommerce-columns woocommerce-columns--addresses col2-set addresses">';
	echo '<div class="woocommerce-column woocommerce-column--1 woocommerce-column--billing-address col-1">';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	echo '<h2 class="woocommerce-column__title">' . esc_html__( 'Billing address', 'woocommerce' ) . '</h2>';
	echo '<address>' . esc_html__( 'Sample billing address — preview only.', 'storzen' ) . '</address></div>';
	echo '<div class="woocommerce-column woocommerce-column--2 woocommerce-column--shipping-address col-2">';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	echo '<h2 class="woocommerce-column__title">' . esc_html__( 'Shipping address', 'woocommerce' ) . '</h2>';
	echo '<address>' . esc_html__( 'Sample shipping address — preview only.', 'storzen' ) . '</address></div>';
	echo '</section></section></div>';
	}

	/**
	 * @param string $label Placeholder text.
	 * @return bool True if placeholder was printed.
	 */
	protected function szp_thankyou_maybe_placeholder( $label ) {
		if ( $this->szp_thankyou_wc_ready() ) {
			return false;
		}
		$ed = \Elementor\Plugin::$instance->editor;
		if ( $ed && method_exists( $ed, 'is_edit_mode' ) && $ed->is_edit_mode() ) {
			printf(
				'<div class="szp-thankyou-widget-placeholder" style="padding:16px;border:1px dashed #ccc;border-radius:6px;background:#f9f9f9;font-size:13px;color:#555;">%s</div>',
				esc_html( $label )
			);
			return true;
		}
		return false;
	}
}

/**
 * Order overview: number, date, email, total, payment method (thank you summary strip).
 */
class Storzen_Thankyou_Order_Summary_Widget extends Widget_Base {
	use Storzen_Thankyou_Widget_Helpers;

	public function get_name() {
		return 'storzen-thankyou-order-summary';
	}

	public function get_title() {
		return esc_html__( 'Order Summary', 'storzen' );
	}

	public function get_icon() {
		return 'eicon-editor-list-ul';
	}

	public function get_categories() {
		return array( 'storzen-thankyou' );
	}

	public function get_style_depends() {
		return array( 'storzen-thankyou-widgets' );
	}

	protected function register_controls() {}

	protected function render() {
		if ( $this->szp_thankyou_maybe_placeholder( esc_html__( 'WooCommerce order summary (requires WooCommerce).', 'storzen' ) ) ) {
			return;
		}

		$data            = $this->szp_thankyou_get_order_for_display();
		$order           = $data['order'];
		$editor_preview = $data['editor_preview'];

		if ( ! $order ) {
			if ( $this->szp_thankyou_in_elementor_builder() ) {
				$this->szp_thankyou_render_sample_order_summary();
			}
			return;
		}

		if ( $order->has_status( 'failed' ) ) {
			return;
		}

		$wrap_classes = 'szp-thankyou-skin szp-thankyou-order-summary woocommerce';
		if ( $editor_preview ) {
			$wrap_classes .= ' szp-thankyou--editor-preview';
		}
		echo '<div class="' . esc_attr( $wrap_classes ) . '">';
		if ( $editor_preview ) {
			$this->szp_thankyou_print_editor_preview_notice( true );
		}
		echo '<ul class="woocommerce-order-overview woocommerce-thankyou-order-details order_details">';

	echo '<li class="woocommerce-order-overview__order order">';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	esc_html_e( 'Order number:', 'woocommerce' );
	echo ' <strong>' . esc_html( $order->get_order_number() ) . '</strong>';
	echo '</li>';

	echo '<li class="woocommerce-order-overview__date date">';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	esc_html_e( 'Date:', 'woocommerce' );
	echo ' <strong>' . esc_html( wc_format_datetime( $order->get_date_created() ) ) . '</strong>';
	echo '</li>';

	$show_email = $order->get_billing_email() && ( $editor_preview || ( is_user_logged_in() && $order->get_user_id() === get_current_user_id() ) );
	if ( $show_email ) {
		echo '<li class="woocommerce-order-overview__email email">';
		// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
		esc_html_e( 'Email:', 'woocommerce' );
			echo ' <strong>' . esc_html( $order->get_billing_email() ) . '</strong>';
			echo '</li>';
		}

	echo '<li class="woocommerce-order-overview__total total">';
	// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
	esc_html_e( 'Total:', 'woocommerce' );
	echo ' <strong>' . wp_kses_post( $order->get_formatted_order_total() ) . '</strong>';
	echo '</li>';

	if ( $order->get_payment_method_title() ) {
		echo '<li class="woocommerce-order-overview__payment-method method">';
		// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Using WooCommerce's own translations
		esc_html_e( 'Payment method:', 'woocommerce' );
		echo ' <strong>' . wp_kses_post( $order->get_payment_method_title() ) . '</strong>';
			echo '</li>';
		}

		echo '</ul></div>';
	}
}

/**
 * Full order details table + addresses (same output as core thank you order details).
 */
class Storzen_Thankyou_Order_Details_Widget extends Widget_Base {
	use Storzen_Thankyou_Widget_Helpers;

	public function get_name() {
		return 'storzen-thankyou-order-details';
	}

	public function get_title() {
		return esc_html__( 'Order Details', 'storzen' );
	}

	public function get_icon() {
		return 'eicon-table';
	}

	public function get_categories() {
		return array( 'storzen-thankyou' );
	}

	public function get_style_depends() {
		return array( 'storzen-thankyou-widgets' );
	}

	protected function register_controls() {}

	protected function render() {
		if ( $this->szp_thankyou_maybe_placeholder( esc_html__( 'WooCommerce order details (requires WooCommerce).', 'storzen' ) ) ) {
			return;
		}

		$data            = $this->szp_thankyou_get_order_for_display();
		$order           = $data['order'];
		$editor_preview = $data['editor_preview'];

		if ( ! $order ) {
			if ( $this->szp_thankyou_in_elementor_builder() ) {
				$this->szp_thankyou_render_sample_order_details();
			}
			return;
		}

		if ( $order->has_status( 'failed' ) ) {
			return;
		}

		$wrap_classes = 'szp-thankyou-skin szp-thankyou-order-details-wrap woocommerce';
		if ( $editor_preview ) {
			$wrap_classes .= ' szp-thankyou--editor-preview';
		}
		echo '<div class="' . esc_attr( $wrap_classes ) . '">';
		if ( $editor_preview ) {
			$this->szp_thankyou_print_editor_preview_notice( true );
		}
		if ( function_exists( 'woocommerce_order_details_table' ) ) {
			woocommerce_order_details_table( $order->get_id() );
		}
		echo '</div>';
	}
}

/**
 * Upsell / related products based on items in the order.
 */
class Storzen_Thankyou_Upsell_After_Widget extends Widget_Base {
	use Storzen_Thankyou_Widget_Helpers;

	public function get_name() {
		return 'storzen-thankyou-upsell-after';
	}

	public function get_title() {
		return esc_html__( 'Upsell After Purchase', 'storzen' );
	}

	public function get_icon() {
		return 'eicon-product-upsell';
	}

	public function get_categories() {
		return array( 'storzen-thankyou' );
	}

	public function get_style_depends() {
		return array( 'storzen-thankyou-widgets' );
	}

	protected function register_controls() {
		$this->start_controls_section(
			'upsell_general',
			array(
				'label' => esc_html__( 'General Settings', 'storzen' ),
			)
		);

		$this->add_control(
			'section_title',
			array(
				'label'       => esc_html__( 'Section title', 'storzen' ),
				'type'        => Controls_Manager::TEXT,
				'default'     => 'You may also like',
				'placeholder' => esc_html__( 'You may also like', 'storzen' ),
			)
		);

		$this->add_control(
			'style',
			array(
				'label'   => esc_html__( 'Select Style', 'storzen' ),
				'type'    => Controls_Manager::SELECT,
				'options' => array(
					'style-1' => esc_html__( 'Style 1', 'storzen' ),
				),
				'default' => 'style-1',
			)
		);

		$this->add_control(
			'column',
			array(
				'label'   => esc_html__( 'Column', 'storzen' ),
				'type'    => Controls_Manager::SELECT,
				'options' => array(
					'2' => esc_html__( '6', 'storzen' ),
					'3' => esc_html__( '4', 'storzen' ),
					'4' => esc_html__( '3', 'storzen' ),
					'6' => esc_html__( '2', 'storzen' ),
				),
				'default' => '4',
			)
		);

		$this->add_control(
			'ppr',
			array(
				'label'   => esc_html__( 'Amount of products to display', 'storzen' ),
				'type'    => Controls_Manager::NUMBER,
				'min'     => 1,
				'max'     => 48,
				'default' => 8,
			)
		);

		$this->end_controls_section();

		$this->start_controls_section(
			'upsell_title_settings',
			array(
				'label' => esc_html__( 'Title Settings', 'storzen' ),
			)
		);

		$this->add_control(
			'dtitle',
			array(
				'label'   => esc_html__( 'Display', 'storzen' ),
				'type'    => Controls_Manager::SELECT,
				'options' => array(
					'full'    => esc_html__( 'Full Title', 'storzen' ),
					'excerpt' => esc_html__( 'Excerpt', 'storzen' ),
				),
				'default' => 'full',
			)
		);

		$this->add_control(
			'title_excerpt_length',
			array(
				'label'     => esc_html__( 'Title Excerpt Length', 'storzen' ),
				'type'      => Controls_Manager::NUMBER,
				'default'   => 8,
				'condition' => array(
					'dtitle' => 'excerpt',
				),
			)
		);

		$this->add_control(
			'titltag',
			array(
				'label'   => esc_html__( 'Product title tag', 'storzen' ),
				'type'    => Controls_Manager::SELECT,
				'options' => array(
					'h1' => 'H1',
					'h2' => 'H2',
					'h3' => 'H3',
					'h4' => 'H4',
					'h5' => 'H5',
					'h6' => 'H6',
				),
				'default' => 'h6',
			)
		);

		$this->add_control(
			'open-url',
			array(
				'label'   => esc_html__( 'Open product in', 'storzen' ),
				'type'    => Controls_Manager::SELECT,
				'options' => array(
					'same-window' => esc_html__( 'Same window', 'storzen' ),
					'new-window'  => esc_html__( 'New window', 'storzen' ),
				),
				'default' => 'same-window',
			)
		);

		$this->end_controls_section();
	}

	/**
	 * Collect product IDs to suggest after purchase (upsells first, then related).
	 *
	 * @param \WC_Order $order Order.
	 * @param int       $limit Max products.
	 * @return int[]
	 */
	protected function szp_thankyou_get_suggested_product_ids( $order, $limit = 8 ) {
		$purchased = array();
		foreach ( $order->get_items() as $item ) {
			/** @var \WC_Order_Item_Product $item */
			$purchased[] = $item->get_product_id();
			if ( $item->get_variation_id() ) {
				$purchased[] = $item->get_variation_id();
			}
		}
		$purchased = array_unique( array_map( 'absint', $purchased ) );

		$candidate_ids = array();
		foreach ( $order->get_items() as $item ) {
			/** @var \WC_Order_Item_Product $item */
			$product = $item->get_product();
			if ( ! $product ) {
				continue;
			}
			$base = $product->is_type( 'variation' ) ? wc_get_product( $product->get_parent_id() ) : $product;
			if ( ! $base ) {
				continue;
			}
			$ups = $base->get_upsell_ids();
			if ( ! empty( $ups ) ) {
				$candidate_ids = array_merge( $candidate_ids, $ups );
			}
		}

		$candidate_ids = array_unique( array_map( 'absint', $candidate_ids ) );
		$candidate_ids = array_diff( $candidate_ids, $purchased );

		if ( count( $candidate_ids ) < $limit && $order->get_items() ) {
			$first_item = null;
			foreach ( $order->get_items() as $item ) {
				/** @var \WC_Order_Item_Product $item */
				$first_item = $item;
				break;
			}
			if ( $first_item && $first_item->get_product() ) {
				/** @var \WC_Order_Item_Product $first_item */
				$prod = $first_item->get_product();
				$pid  = $prod->is_type( 'variation' ) ? $prod->get_parent_id() : $first_item->get_product_id();
				$related = function_exists( 'wc_get_related_products' )
					? wc_get_related_products( $pid, $limit, $purchased )
					: array();
				$candidate_ids = array_merge( $candidate_ids, $related );
			}
		}

		$candidate_ids = array_unique( array_map( 'absint', $candidate_ids ) );
		$candidate_ids = array_diff( $candidate_ids, $purchased );
		$candidate_ids = array_slice( $candidate_ids, 0, $limit );

		$visible = array();
		foreach ( $candidate_ids as $pid ) {
			$p = wc_get_product( $pid );
			if ( $p && wc_products_array_filter_visible( $p ) ) {
				$visible[] = $pid;
			}
		}
		return $visible;
	}

	/**
	 * Product IDs for the upsell grid: suggestions from the order, or random products in the editor when empty.
	 *
	 * @param \WC_Order|false $order Order or false when showing editor sample only.
	 * @param int             $limit Max products.
	 * @return int[]
	 */
	protected function szp_thankyou_get_upsell_product_ids_for_render( $order, $limit = 8 ) {
		$limit = max( 1, min( 48, (int) $limit ) );
		$ids   = array();
		if ( $order && ! $order->has_status( 'failed' ) ) {
			$ids = $this->szp_thankyou_get_suggested_product_ids( $order, $limit );
		}
		if ( ! empty( $ids ) || ! $this->szp_thankyou_in_elementor_builder() ) {
			return array_slice( array_unique( array_map( 'absint', $ids ) ), 0, $limit );
		}
		if ( function_exists( 'wc_get_products' ) ) {
			$products = wc_get_products(
				array(
					'limit'   => $limit,
					'status'  => 'publish',
					'orderby' => 'rand',
					'return'  => 'objects',
				)
			);
			foreach ( $products as $p ) {
				if ( $p && $p->get_id() ) {
					$ids[] = $p->get_id();
				}
			}
		}
		return array_slice( array_unique( array_map( 'absint', $ids ) ), 0, $limit );
	}

	protected function render() {
		if ( $this->szp_thankyou_maybe_placeholder( esc_html__( 'WooCommerce upsells (requires WooCommerce).', 'storzen' ) ) ) {
			return;
		}

		$data            = $this->szp_thankyou_get_order_for_display();
		$order           = $data['order'];
		$editor_preview = $data['editor_preview'];

		if ( ! $order && ! $this->szp_thankyou_in_elementor_builder() ) {
			return;
		}

		if ( $order && $order->has_status( 'failed' ) && ! $this->szp_thankyou_in_elementor_builder() ) {
			return;
		}

		$display = $this->get_settings_for_display();
		$limit   = isset( $display['ppr'] ) ? max( 1, min( 48, (int) $display['ppr'] ) ) : 8;

		$ids = $this->szp_thankyou_get_upsell_product_ids_for_render( $order, $limit );
		if ( empty( $ids ) ) {
			return;
		}

		$storzen_posts_query = new \WP_Query(
			array(
				'post_type'           => 'product',
				'post_status'         => 'publish',
				'ignore_sticky_posts' => true,
				'posts_per_page'      => count( $ids ),
				'post__in'            => $ids,
				'orderby'             => 'post__in',
			)
		);

		if ( ! $storzen_posts_query->have_posts() ) {
			return;
		}

		$col = isset( $display['column'] ) ? (string) $display['column'] : '4';
		$col = in_array( $col, array( '2', '3', '4', '6' ), true ) ? $col : '4';

		$grid_settings = array(
			'style'                => isset( $display['style'] ) ? $display['style'] : 'style-1',
			'column'               => $col,
			'titltag'              => isset( $display['titltag'] ) ? $display['titltag'] : 'h6',
			'open-url'             => isset( $display['open-url'] ) ? $display['open-url'] : 'same-window',
			'dtitle'               => isset( $display['dtitle'] ) ? $display['dtitle'] : 'full',
			'title_excerpt_length' => isset( $display['title_excerpt_length'] ) ? (int) $display['title_excerpt_length'] : 8,
			'enable_pagination'    => 'no',
		);

		$wrap_classes = 'szp-thankyou-skin szp-thankyou-upsell woocommerce';
		if ( $editor_preview || ( ! $order && $this->szp_thankyou_in_elementor_builder() ) ) {
			$wrap_classes .= ' szp-thankyou--editor-preview';
		}

		echo '<div class="' . esc_attr( $wrap_classes ) . '">';
		if ( $editor_preview ) {
			$this->szp_thankyou_print_editor_preview_notice( (bool) $order );
		} elseif ( ! $order && $this->szp_thankyou_in_elementor_builder() ) {
			$this->szp_thankyou_print_editor_preview_notice( false );
		}

		$title = isset( $display['section_title'] ) && $display['section_title'] !== ''
			? $display['section_title']
			: esc_html__( 'You may also like', 'storzen' );
		echo '<h2 class="szp-thankyou-upsell__title">' . esc_html( $title ) . '</h2>';

		$settings                   = $grid_settings;
		$szp_grid_hide_pagination   = true;
		$szp_grid_section_extra_class = 'szp-thankyou-upsell-grid';

		$grid_tpl = function_exists( 'storzen_get_template' ) ? storzen_get_template( 'grid.php' ) : false;
		if ( $grid_tpl ) {
			include $grid_tpl;
		} else {
			wc_set_loop_prop( 'columns', apply_filters( 'szp_thankyou_upsell_columns', 4 ) ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Hook uses the plugin's szp_ short prefix.
			woocommerce_product_loop_start();
			while ( $storzen_posts_query->have_posts() ) {
				$storzen_posts_query->the_post();
				wc_get_template_part( 'content', 'product' );
			}
			woocommerce_product_loop_end();
			wp_reset_postdata();
		}

		echo '</div>';
	}
}
