<?php
/**
 * Storzen Module — Quick Checkout (Pro)
 *
 * Streamlined checkout modal that bypasses the cart page for single-product
 * purchases. Customer clicks "Buy Now" → modal opens with minimum required
 * fields → AJAX submits → WC creates order → redirect.
 *
 * Payment gateway scope:
 *   Direct gateways (COD, BACS, Cheque) — fully supported, process via AJAX.
 *   Hosted/redirect gateways (PayPal Standard) — supported via redirect_url.
 *   Embedded gateways (Stripe Elements, etc.) — NOT supported; module shows
 *   "Continue to Full Checkout" link as a graceful fallback.
 *
 * @package storzen
 * @since   1.6.1
 */

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

if ( ! class_exists( 'Storzen_Module_Quick_Checkout' ) ) {

	class Storzen_Module_Quick_Checkout {

		const AJAX_PLACE = 'storzen_qc_place';
		const AJAX_PREP  = 'storzen_qc_prep';
		const NONCE      = 'storzen_qc_nonce';

		/** @var array|null */
		private $settings = null;

		public function __construct() {
			if ( ! function_exists( 'WC' ) ) {
				return;
			}

			add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ) );
			add_action( 'wp_footer',           array( $this, 'render_modal_shell' ), 22 );

			// "Buy Now" button — placement depends on the button_position setting.
			$this->bind_button_hooks();

			// AJAX endpoints.
			add_action( 'wp_ajax_'        . self::AJAX_PREP,  array( $this, 'ajax_prep' ) );
			add_action( 'wp_ajax_nopriv_' . self::AJAX_PREP,  array( $this, 'ajax_prep' ) );
			add_action( 'wp_ajax_'        . self::AJAX_PLACE, array( $this, 'ajax_place_order' ) );
			add_action( 'wp_ajax_nopriv_' . self::AJAX_PLACE, array( $this, 'ajax_place_order' ) );
		}

		// ─────────────────────────────────────────────────────────────────
		// Settings
		// ─────────────────────────────────────────────────────────────────

		private function get_settings() {
			if ( null !== $this->settings ) return $this->settings;

			$valid_positions = array( 'after_add_to_cart', 'replace_add_to_cart', 'shop_cards', 'both' );
			$position = (string) storzen_module_setting( 'quick_checkout', 'button_position' );
			if ( ! in_array( $position, $valid_positions, true ) ) {
				$position = 'after_add_to_cart';
			}

			$valid_success = array( 'thank_you', 'stay', 'custom' );
			$success = (string) storzen_module_setting( 'quick_checkout', 'success_action' );
			if ( ! in_array( $success, $valid_success, true ) ) {
				$success = 'thank_you';
			}

			$label = (string) storzen_module_setting( 'quick_checkout', 'button_label' );
			$title = (string) storzen_module_setting( 'quick_checkout', 'modal_title' );

			$this->settings = array(
				'button_label'      => $label !== '' ? $label : __( 'Buy Now', 'storzen' ),
				'button_position'   => $position,
				'modal_title'       => $title !== '' ? $title : __( 'Quick Checkout', 'storzen' ),
				'require_phone'     => (bool) storzen_module_setting( 'quick_checkout', 'require_phone' ),
				'require_address'   => (bool) storzen_module_setting( 'quick_checkout', 'require_address' ),
				'require_account'   => (bool) storzen_module_setting( 'quick_checkout', 'require_account' ),
				'show_order_notes'  => (bool) storzen_module_setting( 'quick_checkout', 'show_order_notes' ),
				'show_coupon_field' => (bool) storzen_module_setting( 'quick_checkout', 'show_coupon_field' ),
				'success_action'    => $success,
				'custom_redirect'   => esc_url_raw( (string) storzen_module_setting( 'quick_checkout', 'custom_redirect' ) ),
				'clear_cart'        => (bool) storzen_module_setting( 'quick_checkout', 'clear_cart' ),
			);
			return $this->settings;
		}

		// ─────────────────────────────────────────────────────────────────
		// Button placement
		// ─────────────────────────────────────────────────────────────────

		private function bind_button_hooks() {
			$s   = $this->get_settings();
			$pos = $s['button_position'];

			$show_single = in_array( $pos, array( 'after_add_to_cart', 'replace_add_to_cart', 'both' ), true );
			$show_loop   = in_array( $pos, array( 'shop_cards', 'both' ), true );

			if ( $show_single ) {
				if ( 'replace_add_to_cart' === $pos ) {
					add_filter( 'body_class', array( $this, 'add_body_class_replace' ) );
				}
				add_action( 'woocommerce_after_add_to_cart_button',  array( $this, 'render_single_button' ), 5 );
				add_action( 'storzen_product_single_after_price', array( $this, 'render_single_button_compat' ), 30, 1 );
			}

			if ( $show_loop ) {
				// WooCommerce default shop loop.
				add_action( 'woocommerce_after_shop_loop_item', array( $this, 'render_loop_button' ), 12 );
			}
			// Storzen-native card overlay — always registered; widget toggle controls visibility.
			add_action( 'storzen_shop_card_overlay', array( $this, 'render_loop_button_compat' ), 17, 1 );
		}

		public function add_body_class_replace( $classes ) {
			$classes[] = 'storzen-qc-replace-atc';
			return $classes;
		}

		/**
		 * Render the Buy Now button on the single product page.
		 */
		public function render_single_button() {
			global $product;
			if ( ! $product instanceof WC_Product || ! $product->is_purchasable() ) {
				return;
			}
			$this->render_button( $product, 'single' );
		}

		public function render_single_button_compat( $product = null ) {
			if ( ! $product instanceof WC_Product || ! $product->is_purchasable() ) return;
			// Avoid double-render: native hook already fired this iteration.
			static $rendered = array();
			$id = $product->get_id();
			if ( isset( $rendered[ $id ] ) ) return;
			$rendered[ $id ] = true;
			$this->render_button( $product, 'single' );
		}

		public function render_loop_button() {
			global $product;
			if ( ! $product instanceof WC_Product || ! $product->is_purchasable() ) {
				return;
			}
			$this->render_button( $product, 'loop' );
		}

		public function render_loop_button_compat( $product = null ) {
			if ( ! $product instanceof WC_Product || ! $product->is_purchasable() ) return;
			if ( class_exists( '\Elementor\Storzen_Archive_Grid' ) && false === \Elementor\Storzen_Archive_Grid::is_module_active( 'quick_checkout' ) ) {
				return;
			}
			$this->render_button( $product, 'loop' );
		}

		/**
		 * Actual button HTML — variable products get a "view product" link
		 * because they need variation selection which requires the full form.
		 */
		private function render_button( $product, $context ) {
			$s        = $this->get_settings();
			$is_variable = $product->is_type( 'variable' );
			$classes  = 'storzen-qc-btn storzen-qc-btn--' . $context;
			if ( $is_variable ) {
				$classes .= ' storzen-qc-btn--variable';
			}
			?>
			<button
				type="button"
				class="<?php echo esc_attr( $classes ); ?>"
				data-product-id="<?php echo esc_attr( $product->get_id() ); ?>"
				data-product-type="<?php echo esc_attr( $product->get_type() ); ?>"
				title="<?php echo esc_attr( $s['button_label'] ); ?>"
				aria-label="<?php echo esc_attr( $s['button_label'] ); ?>"
			>
				<span class="storzen-qc-btn__icon" aria-hidden="true">
					<?php if ( 'loop' === $context ) : ?>
						<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"/><line x1="3" y1="6" x2="21" y2="6"/><path d="M16 10a4 4 0 0 1-8 0"/></svg>
					<?php else : ?>
						⚡
					<?php endif; ?>
				</span>
				<?php if ( 'single' === $context ) : ?>
					<span class="storzen-qc-btn__label"><?php echo esc_html( $s['button_label'] ); ?></span>
				<?php endif; ?>
			</button>
			<?php
		}

		// ─────────────────────────────────────────────────────────────────
		// Modal shell — populated by JS
		// ─────────────────────────────────────────────────────────────────

		public function render_modal_shell() {
			if ( is_admin() || is_checkout() ) {
				return;
			}
			$s = $this->get_settings();
			?>
			<div class="storzen-qc-modal" id="storzen-qc-modal" role="dialog" aria-modal="true" aria-hidden="true" aria-labelledby="storzen-qc-title">
				<div class="storzen-qc-modal__overlay" data-storzen-qc-close></div>
				<div class="storzen-qc-modal__panel">
					<header class="storzen-qc-modal__header">
						<h2 class="storzen-qc-modal__title" id="storzen-qc-title"><?php echo esc_html( $s['modal_title'] ); ?></h2>
						<button type="button" class="storzen-qc-modal__close" data-storzen-qc-close aria-label="<?php esc_attr_e( 'Close', 'storzen' ); ?>">&times;</button>
					</header>
					<div class="storzen-qc-modal__body" data-storzen-qc-body>
						<div class="storzen-qc-loading"><?php esc_html_e( 'Loading…', 'storzen' ); ?></div>
					</div>
				</div>
			</div>
			<?php
		}

		// ─────────────────────────────────────────────────────────────────
		// Assets
		// ─────────────────────────────────────────────────────────────────

		public function enqueue_assets() {
			if ( is_admin() ) return;
			$s = $this->get_settings();

			wp_enqueue_style(
				'storzen-quick-checkout',
				STORZEN_ROOT_URL . 'assets/css/modules/quick-checkout.css',
				array(),
				STORZEN_VERSION
			);
			wp_enqueue_script(
				'storzen-quick-checkout',
				STORZEN_ROOT_URL . 'assets/js/modules/quick-checkout.js',
				array( 'jquery' ),
				STORZEN_VERSION,
				true
			);

			wp_localize_script( 'storzen-quick-checkout', 'szQuickCheckout', array(
				'ajaxUrl'  => admin_url( 'admin-ajax.php' ),
				'nonce'    => wp_create_nonce( self::NONCE ),
				'isLoggedIn' => is_user_logged_in(),
				'i18n' => array(
					'loading'       => __( 'Loading…', 'storzen' ),
					'placing'       => __( 'Placing your order…', 'storzen' ),
					'success'       => __( 'Order placed! Redirecting…', 'storzen' ),
					'fullCheckout'  => __( 'Continue to Full Checkout', 'storzen' ),
					'variableNote'  => __( 'This product has variations — please use the full checkout to choose them.', 'storzen' ),
					'errorGeneric'  => __( 'Could not complete your order. Please try again.', 'storzen' ),
					'required'      => __( 'This field is required.', 'storzen' ),
				),
			) );
		}

		// ─────────────────────────────────────────────────────────────────
		// AJAX: prepare modal HTML (form + summary for the chosen product)
		// ─────────────────────────────────────────────────────────────────

		public function ajax_prep() {
			if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), self::NONCE ) ) {
				wp_send_json_error( array( 'message' => __( 'Security check failed.', 'storzen' ) ), 403 );
			}
			$product_id = isset( $_POST['product_id'] ) ? absint( wp_unslash( $_POST['product_id'] ) ) : 0;
			$product    = wc_get_product( $product_id );
			if ( ! $product || ! $product->is_purchasable() ) {
				wp_send_json_error( array( 'message' => __( 'Product unavailable.', 'storzen' ) ), 400 );
			}
			if ( $product->is_type( 'variable' ) ) {
				wp_send_json_error( array(
					'message' => __( 'Variable products require full checkout.', 'storzen' ),
					'fallback_url' => wc_get_checkout_url(),
				), 422 );
			}

			wp_send_json_success( array(
				'html' => $this->render_modal_form( $product ),
			) );
		}

		/**
		 * Build the form HTML for a single-product quick checkout.
		 */
		private function render_modal_form( $product ) {
			$s        = $this->get_settings();
			$gateways = $this->get_supported_gateways();
			$thumb    = $product->get_image_id() ? wp_get_attachment_image( $product->get_image_id(), 'woocommerce_thumbnail' ) : '';

			ob_start();
			?>
			<form class="storzen-qc-form" data-storzen-qc-form data-product-id="<?php echo esc_attr( $product->get_id() ); ?>">
				<div class="storzen-qc-summary">
					<?php if ( $thumb ) : ?>
						<div class="storzen-qc-summary__thumb"><?php echo $thumb; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
					<?php endif; ?>
					<div class="storzen-qc-summary__body">
						<div class="storzen-qc-summary__name"><?php echo esc_html( $product->get_name() ); ?></div>
						<div class="storzen-qc-summary__price"><?php echo wp_kses_post( $product->get_price_html() ); ?></div>
					</div>
				</div>

				<div class="storzen-qc-fields">
					<div class="storzen-qc-row">
						<label class="storzen-qc-label">
							<?php esc_html_e( 'First Name', 'storzen' ); ?> <span class="req">*</span>
							<input type="text" name="first_name" required>
						</label>
						<label class="storzen-qc-label">
							<?php esc_html_e( 'Last Name', 'storzen' ); ?> <span class="req">*</span>
							<input type="text" name="last_name" required>
						</label>
					</div>

					<label class="storzen-qc-label">
						<?php esc_html_e( 'Email', 'storzen' ); ?> <span class="req">*</span>
						<input type="email" name="email" required>
					</label>

					<?php if ( $s['require_phone'] ) : ?>
						<label class="storzen-qc-label">
							<?php esc_html_e( 'Phone', 'storzen' ); ?> <span class="req">*</span>
							<input type="tel" name="phone" required>
						</label>
					<?php endif; ?>

					<?php if ( $s['require_address'] ) : ?>
						<label class="storzen-qc-label">
							<?php esc_html_e( 'Address', 'storzen' ); ?> <span class="req">*</span>
							<input type="text" name="address_1" required>
						</label>
						<div class="storzen-qc-row">
							<label class="storzen-qc-label">
								<?php esc_html_e( 'City', 'storzen' ); ?> <span class="req">*</span>
								<input type="text" name="city" required>
							</label>
							<label class="storzen-qc-label">
								<?php esc_html_e( 'Postcode', 'storzen' ); ?>
								<input type="text" name="postcode">
							</label>
						</div>
						<label class="storzen-qc-label">
							<?php esc_html_e( 'Country', 'storzen' ); ?> <span class="req">*</span>
							<select name="country" required>
								<?php
								$countries = WC()->countries->get_allowed_countries();
								$default   = WC()->countries->get_base_country();
								foreach ( $countries as $code => $name ) {
									printf(
										'<option value="%s"%s>%s</option>',
										esc_attr( $code ),
										selected( $code, $default, false ),
										esc_html( $name )
									);
								}
								?>
							</select>
						</label>
					<?php endif; ?>

					<?php if ( $s['show_order_notes'] ) : ?>
						<label class="storzen-qc-label">
							<?php esc_html_e( 'Order Notes', 'storzen' ); ?>
							<textarea name="order_notes" rows="2"></textarea>
						</label>
					<?php endif; ?>

					<?php if ( $s['show_coupon_field'] ) : ?>
						<label class="storzen-qc-label">
							<?php esc_html_e( 'Coupon Code', 'storzen' ); ?>
							<input type="text" name="coupon_code" autocomplete="off">
						</label>
					<?php endif; ?>

					<?php if ( $s['require_account'] && ! is_user_logged_in() ) : ?>
						<label class="storzen-qc-label">
							<?php esc_html_e( 'Account Password', 'storzen' ); ?> <span class="req">*</span>
							<input type="password" name="account_password" required minlength="6">
						</label>
					<?php endif; ?>

					<fieldset class="storzen-qc-payment">
						<legend><?php esc_html_e( 'Payment Method', 'storzen' ); ?></legend>
						<?php if ( empty( $gateways ) ) : ?>
							<p class="storzen-qc-empty-gateways">
								<?php esc_html_e( 'No quick-checkout-compatible payment gateways found. Use full checkout instead.', 'storzen' ); ?>
								<br>
								<a href="<?php echo esc_url( wc_get_checkout_url() ); ?>"><?php esc_html_e( 'Go to Full Checkout', 'storzen' ); ?></a>
							</p>
						<?php else : ?>
							<?php foreach ( $gateways as $gw_id => $gw ) : ?>
								<label class="storzen-qc-gateway">
									<input type="radio" name="payment_method" value="<?php echo esc_attr( $gw_id ); ?>" required>
									<span><?php echo esc_html( $gw->get_title() ); ?></span>
								</label>
							<?php endforeach; ?>
						<?php endif; ?>
					</fieldset>
				</div>

				<div class="storzen-qc-actions">
					<button type="submit" class="storzen-qc-submit" <?php echo empty( $gateways ) ? 'disabled' : ''; ?>>
						<?php esc_html_e( 'Place Order', 'storzen' ); ?>
					</button>
					<a class="storzen-qc-full-link" href="<?php echo esc_url( wc_get_checkout_url() ); ?>">
						<?php esc_html_e( 'Use Full Checkout', 'storzen' ); ?>
					</a>
				</div>

				<div class="storzen-qc-error" data-storzen-qc-error hidden></div>
			</form>
			<?php
			return ob_get_clean();
		}

		/**
		 * Return WC gateways that are enabled AND known-compatible with our
		 * AJAX flow. Excludes embedded gateways like Stripe Elements that
		 * require their own iframe lifecycle.
		 *
		 * @return WC_Payment_Gateway[]
		 */
		private function get_supported_gateways() {
			$compatible_ids = apply_filters( 'storzen_qc_compatible_gateways', array(
				'cod', 'bacs', 'cheque', 'paypal',
			) );
			$out = array();
			$gateways = WC()->payment_gateways() ? WC()->payment_gateways()->get_available_payment_gateways() : array();
			foreach ( $gateways as $id => $gw ) {
				if ( in_array( $id, $compatible_ids, true ) ) {
					$out[ $id ] = $gw;
				}
			}
			return $out;
		}

		// ─────────────────────────────────────────────────────────────────
		// AJAX: place the order
		// ─────────────────────────────────────────────────────────────────

		public function ajax_place_order() {
			if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), self::NONCE ) ) {
				wp_send_json_error( array( 'message' => __( 'Security check failed.', 'storzen' ) ), 403 );
			}

			$product_id     = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
			$product        = wc_get_product( $product_id );
			if ( ! $product || ! $product->is_purchasable() ) {
				wp_send_json_error( array( 'message' => __( 'Product unavailable.', 'storzen' ) ), 400 );
			}
			if ( $product->is_type( 'variable' ) ) {
				wp_send_json_error( array( 'message' => __( 'Variable products require full checkout.', 'storzen' ) ), 422 );
			}

			$data = $this->sanitize_submission( $_POST );
			$err  = $this->validate_submission( $data );
			if ( $err ) {
				wp_send_json_error( array( 'message' => $err ), 422 );
			}

			// Optionally create + log-in a customer account.
			$customer_id = $this->maybe_create_account( $data );
			if ( is_wp_error( $customer_id ) ) {
				wp_send_json_error( array( 'message' => $customer_id->get_error_message() ), 422 );
			}

			// Build the order with WC's API directly — no cart involved.
			$order = $this->build_order( $product, $data, $customer_id );
			if ( is_wp_error( $order ) ) {
				wp_send_json_error( array( 'message' => $order->get_error_message() ), 500 );
			}

			// Pass to payment gateway.
			$gateway_id = $data['payment_method'];
			$gateway    = WC()->payment_gateways()->payment_gateways()[ $gateway_id ] ?? null;
			if ( ! $gateway ) {
				wp_send_json_error( array( 'message' => __( 'Invalid payment method.', 'storzen' ) ), 422 );
			}

			$payment_result = $gateway->process_payment( $order->get_id() );

			if ( ! is_array( $payment_result ) || empty( $payment_result['result'] ) || 'success' !== $payment_result['result'] ) {
				wp_send_json_error( array( 'message' => __( 'Payment could not be processed.', 'storzen' ) ), 500 );
			}

			// Optional: clear cart contents.
			$s = $this->get_settings();
			if ( $s['clear_cart'] && WC()->cart ) {
				WC()->cart->empty_cart();
			}

			// Determine redirect.
			$redirect = $payment_result['redirect'] ?? '';
			if ( ! $redirect ) {
				if ( 'stay' === $s['success_action'] ) {
					$redirect = '';
				} elseif ( 'custom' === $s['success_action'] && $s['custom_redirect'] ) {
					$redirect = $s['custom_redirect'];
				} else {
					$redirect = $order->get_checkout_order_received_url();
				}
			}

			do_action( 'storzen_qc_order_placed', $order );

			wp_send_json_success( array(
				'order_id' => $order->get_id(),
				'redirect' => $redirect,
				'order_received_url' => $order->get_checkout_order_received_url(),
			) );
		}

		/**
		 * Sanitize the submitted form data.
		 */
		private function sanitize_submission( $post ) {
			$d = array();
			$d['first_name']     = isset( $post['first_name'] ) ? sanitize_text_field( wp_unslash( $post['first_name'] ) ) : '';
			$d['last_name']      = isset( $post['last_name'] ) ? sanitize_text_field( wp_unslash( $post['last_name'] ) ) : '';
			$d['email']          = isset( $post['email'] ) ? sanitize_email( wp_unslash( $post['email'] ) ) : '';
			$d['phone']          = isset( $post['phone'] ) ? sanitize_text_field( wp_unslash( $post['phone'] ) ) : '';
			$d['address_1']      = isset( $post['address_1'] ) ? sanitize_text_field( wp_unslash( $post['address_1'] ) ) : '';
			$d['city']           = isset( $post['city'] ) ? sanitize_text_field( wp_unslash( $post['city'] ) ) : '';
			$d['postcode']       = isset( $post['postcode'] ) ? sanitize_text_field( wp_unslash( $post['postcode'] ) ) : '';
			$d['country']        = isset( $post['country'] ) ? sanitize_text_field( wp_unslash( $post['country'] ) ) : '';
			$d['order_notes']    = isset( $post['order_notes'] ) ? sanitize_textarea_field( wp_unslash( $post['order_notes'] ) ) : '';
			$d['coupon_code']    = isset( $post['coupon_code'] ) ? sanitize_text_field( wp_unslash( $post['coupon_code'] ) ) : '';
			$d['account_password'] = isset( $post['account_password'] ) ? (string) $post['account_password'] : '';
			$d['payment_method'] = isset( $post['payment_method'] ) ? sanitize_text_field( wp_unslash( $post['payment_method'] ) ) : '';
			return $d;
		}

		private function validate_submission( $d ) {
			$s = $this->get_settings();
			if ( '' === $d['first_name'] || '' === $d['last_name'] ) return __( 'Name is required.', 'storzen' );
			if ( '' === $d['email'] || ! is_email( $d['email'] ) )    return __( 'A valid email is required.', 'storzen' );
			if ( $s['require_phone'] && '' === $d['phone'] )          return __( 'Phone is required.', 'storzen' );
			if ( $s['require_address'] && ( '' === $d['address_1'] || '' === $d['city'] || '' === $d['country'] ) ) {
				return __( 'Complete shipping address is required.', 'storzen' );
			}
			if ( '' === $d['payment_method'] ) return __( 'Please choose a payment method.', 'storzen' );
			if ( $s['require_account'] && ! is_user_logged_in() && strlen( $d['account_password'] ) < 6 ) {
				return __( 'Password must be at least 6 characters.', 'storzen' );
			}
			return null;
		}

		/**
		 * If account creation is required, create one. Otherwise return current
		 * user id (or 0 for guest).
		 *
		 * @return int|WP_Error
		 */
		private function maybe_create_account( $d ) {
			if ( is_user_logged_in() ) {
				return get_current_user_id();
			}
			$s = $this->get_settings();
			if ( ! $s['require_account'] ) {
				return 0;
			}

			if ( email_exists( $d['email'] ) ) {
				return new WP_Error( 'storzen_qc_email_exists', __( 'An account with this email already exists. Please log in first.', 'storzen' ) );
			}

			$user_id = wc_create_new_customer( $d['email'], '', $d['account_password'], array(
				'first_name' => $d['first_name'],
				'last_name'  => $d['last_name'],
			) );
			if ( is_wp_error( $user_id ) ) {
				return $user_id;
			}

			// Auto-login.
			wc_set_customer_auth_cookie( $user_id );
			return $user_id;
		}

		/**
		 * Build the WC_Order directly. Apply coupon if provided.
		 *
		 * @return WC_Order|WP_Error
		 */
		private function build_order( $product, $d, $customer_id ) {
			try {
				$order = wc_create_order( array( 'customer_id' => (int) $customer_id ) );
				if ( is_wp_error( $order ) ) {
					return $order;
				}
				$order->add_product( $product, 1 );

				// Apply coupon if provided.
				if ( ! empty( $d['coupon_code'] ) ) {
					$applied = $order->apply_coupon( $d['coupon_code'] );
					// Ignore coupon errors — order goes through without it.
					unset( $applied );
				}

				// Billing.
				$order->set_billing_first_name( $d['first_name'] );
				$order->set_billing_last_name( $d['last_name'] );
				$order->set_billing_email( $d['email'] );
				if ( $d['phone'] )     $order->set_billing_phone( $d['phone'] );
				if ( $d['address_1'] ) $order->set_billing_address_1( $d['address_1'] );
				if ( $d['city'] )      $order->set_billing_city( $d['city'] );
				if ( $d['postcode'] )  $order->set_billing_postcode( $d['postcode'] );
				if ( $d['country'] )   $order->set_billing_country( $d['country'] );

				// Shipping = same as billing.
				$order->set_shipping_first_name( $d['first_name'] );
				$order->set_shipping_last_name( $d['last_name'] );
				if ( $d['address_1'] ) $order->set_shipping_address_1( $d['address_1'] );
				if ( $d['city'] )      $order->set_shipping_city( $d['city'] );
				if ( $d['postcode'] )  $order->set_shipping_postcode( $d['postcode'] );
				if ( $d['country'] )   $order->set_shipping_country( $d['country'] );

				if ( $d['order_notes'] ) {
					$order->set_customer_note( $d['order_notes'] );
				}

				$order->set_payment_method( $d['payment_method'] );
				$order->update_meta_data( '_storzen_quick_checkout', 'yes' );

				$order->calculate_totals();
				$order->save();
				return $order;
			} catch ( Exception $e ) {
				return new WP_Error( 'storzen_qc_build_failed', $e->getMessage() );
			}
		}

	} // end class

} // end class_exists
