<?php
/**
 * BaseCloud Boost — WooCommerce Compatibility
 *
 * @package BaseCloud\Boost\Compatibility
 */

declare( strict_types=1 );

namespace BaseCloud\Boost\Compatibility;

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

/**
 * Ensures BaseCloud Boost does not cache WooCommerce dynamic pages.
 */
class WooCommerce_Compat {

	/**
	 * Boot WooCommerce compatibility.
	 *
	 * @return void
	 */
	public function boot(): void {
		if ( ! class_exists( 'WooCommerce' ) ) {
			return;
		}

		add_filter( 'BCBOOST_cache_reject_uri',     [ $this, 'add_cache_exclusions' ] );
		add_filter( 'BCBOOST_cache_reject_cookies', [ $this, 'add_cookie_exclusions' ] );
		add_action( 'template_redirect',        [ $this, 'add_no_cache_headers' ], 1 );

		// Keep the dynamic cart scripts out of defer/delay so the mini-cart, cart
		// fragments and add-to-cart still update on cached pages.
		add_filter( 'BCBOOST_never_defer_handles', [ $this, 'protect_cart_scripts' ] );
		add_filter( 'BCBOOST_never_delay_handles', [ $this, 'protect_cart_scripts' ] );
	}

	/**
	 * Add WooCommerce's dynamic cart-related script handles to a skip list.
	 *
	 * @param string[] $handles Existing skip handles.
	 * @return string[]
	 */
	public function protect_cart_scripts( array $handles ): array {
		return array_merge( $handles, [
			// jQuery must keep running immediately: the cart-fragments / add-to-cart
			// scripts below are protected from delay, but they depend on jQuery. If
			// jQuery itself were delayed, those protected scripts would run at parse and
			// call an undefined `jQuery`, breaking the mini-cart and add-to-cart on
			// cached pages. (On non-WooCommerce sites jQuery is still delayed for the TBT
			// win — this compat layer only boots when WooCommerce is active.)
			'jquery',
			'jquery-core',
			'jquery-migrate',
			'wc-cart-fragments',
			'woocommerce',
			'wc-add-to-cart',
			'wc-add-to-cart-variation',
			'wc-cart',
			'wc-checkout',
			'cart-fragments',
		] );
	}

	/**
	 * Add WooCommerce pages to cache exclusion list.
	 *
	 * @param string[] $excluded_urls Existing excluded URL patterns.
	 * @return string[]
	 */
	public function add_cache_exclusions( array $excluded_urls ): array {
		$wc_pages = [
			wc_get_page_permalink( 'cart' ),
			wc_get_page_permalink( 'checkout' ),
			wc_get_page_permalink( 'myaccount' ),
		];

		foreach ( $wc_pages as $url ) {
			if ( $url && $url !== '#' ) {
				$path = wp_parse_url( $url, PHP_URL_PATH );
				if ( $path ) {
					$excluded_urls[] = $path;
				}
			}
		}

		return $excluded_urls;
	}

	/**
	 * Add WooCommerce session cookies to bypass cache.
	 *
	 * @param string[] $excluded_cookies Existing excluded cookie patterns.
	 * @return string[]
	 */
	public function add_cookie_exclusions( array $excluded_cookies ): array {
		$excluded_cookies[] = 'woocommerce_items_in_cart';
		$excluded_cookies[] = 'woocommerce_cart_hash';
		$excluded_cookies[] = 'woocommerce_session_';
		return $excluded_cookies;
	}

	/**
	 * Add no-cache headers on WooCommerce dynamic pages.
	 *
	 * @return void
	 */
	public function add_no_cache_headers(): void {
		if ( $this->should_bypass_cache() ) {
			nocache_headers();
			header( 'X-BaseCloud-Boost: BYPASS-WOOCOMMERCE' );
		}
	}

	/**
	 * Check if the current request should bypass cache.
	 *
	 * @return bool
	 */
	public function should_bypass_cache(): bool {
		if ( function_exists( 'is_cart' ) && is_cart() ) {
			return true;
		}
		if ( function_exists( 'is_checkout' ) && is_checkout() ) {
			return true;
		}
		if ( function_exists( 'is_account_page' ) && is_account_page() ) {
			return true;
		}

		// Cart has items.
		foreach ( $_COOKIE as $name => $value ) {
			if ( strpos( $name, 'woocommerce_items_in_cart' ) !== false && $value ) {
				return true;
			}
		}

		return false;
	}
}
