<?php
/**
 * Activation guard — never let a missing/old WooCommerce produce a white screen,
 * and declare HPOS + cart/checkout-blocks compatibility.
 *
 * @package Hakki\WooCore
 */

namespace ErenLabs\Stocktake\Vendor\Hakki\WooCore\Activation;

use ErenLabs\Stocktake\Vendor\Hakki\WooCore\Core;

defined( 'ABSPATH' ) || exit;

final class Guard {

	/** @var Core */
	private $core;

	public function __construct( Core $core ) {
		$this->core = $core;
	}

	/**
	 * Declare WooCommerce feature compatibility. Safe to call before Woo loads.
	 */
	public function declare_compatibility(): void {
		$file    = $this->core->file();
		$declare = static function () use ( $file ) {
			$util = '\\Automattic\\WooCommerce\\Utilities\\FeaturesUtil';
			if ( class_exists( $util ) ) {
				$util::declare_compatibility( 'custom_order_tables', $file, true );
				$util::declare_compatibility( 'cart_checkout_blocks', $file, true );
			}
		};

		// doing_action(), NOT did_action(). WooCommerce only accepts a
		// declaration WHILE 'before_woocommerce_init' is running; called at any
		// other moment FeaturesUtil raises _doing_it_wrong(). did_action() is true
		// forever once the hook has fired, so activating a plugin AFTER Woo had
		// already booted — which is exactly what happens when a user clicks
		// Activate on the Plugins screen — declared out of turn and printed the
		// notice into the activation response. wp-admin then showed "The plugin
		// generated N characters of unexpected output during activation", which a
		// reviewer sees on any WP_DEBUG site.
		//
		// Missing the window is the safe failure: the declaration is an
		// advisory compatibility flag, and the next page load re-runs this on the
		// hook proper.
		if ( doing_action( 'before_woocommerce_init' ) ) {
			$declare();
			return;
		}
		add_action( 'before_woocommerce_init', $declare );
	}

	/**
	 * Is WooCommerce active and at/above the minimum version?
	 */
	public function woo_ready(): bool {
		if ( ! $this->core->requires_woo() ) {
			return true;
		}
		if ( ! class_exists( 'WooCommerce' ) || ! defined( 'WC_VERSION' ) ) {
			return false;
		}
		return version_compare( WC_VERSION, $this->core->min_woo(), '>=' );
	}

	/**
	 * Run $bootstrap only when Woo is ready; otherwise show a dismissible admin
	 * notice and stay silent on the front end. Never fatals.
	 *
	 * Safe to call late: if plugins_loaded has already fired (e.g. the consumer
	 * boots from a mu-plugin or a lazy include), the check runs immediately
	 * instead of silently never running.
	 *
	 * @param callable $bootstrap Invoked with the Core instance when safe.
	 */
	public function boot_when_ready( callable $bootstrap ): void {
		$check = function () use ( $bootstrap ) {
			if ( $this->woo_ready() ) {
				$bootstrap( $this->core );
				return;
			}
			add_action( 'admin_notices', array( $this, 'render_woo_notice' ) );
		};

		if ( did_action( 'plugins_loaded' ) ) {
			$check();
			return;
		}
		add_action( 'plugins_loaded', $check, 20 );
	}

	/**
	 * Admin notice shown when WooCommerce is missing or too old.
	 */
	public function render_woo_notice(): void {
		// manage_options, not activate_plugins: on stock multisite, subsite admins
		// lack activate_plugins and the warning would be invisible to everyone.
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}
		$plugin = function_exists( 'get_plugin_data' )
			? get_plugin_data( $this->core->file(), false, false )['Name']
			: $this->core->slug();

		printf(
			'<div class="notice notice-warning is-dismissible"><p>%s</p></div>',
			esc_html(
				sprintf(
					/* translators: 1: plugin name, 2: minimum WooCommerce version */
					__( '%1$s needs WooCommerce %2$s or newer to be active. It has paused itself until then.', 'stocktake-for-woocommerce' ),
					$plugin,
					$this->core->min_woo()
				)
			)
		);
	}
}
