<?php
/**
 * ANCP Core - version-negotiation loader.
 *
 * A deliberately tiny, stable registry shared by every plugin that bundles the
 * ANCP Core Library. Each bundle registers its version and root path; the
 * loader boots the HIGHEST registered version once, by requiring that
 * payload's own manifest (includes/ancp-boot.php). Keeping this class minimal
 * and backward-compatible matters: because it is guarded by class_exists, the
 * first-loaded bundle's copy of THIS file is the one that runs, even if a
 * newer bundle is present. It must therefore stay forward-compatible forever.
 * The versioned, changeable code lives in the payload it loads, never here.
 *
 * Pattern mirrors Action Scheduler's ActionScheduler_Versions.
 *
 * @package AncestorPress\Core
 * @since   0.19.0
 */

namespace AncestorPress\Core;

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

if ( ! class_exists( 'AncestorPress\Core\Loader' ) ) {

	/**
	 * Registry + newest-wins boot for the ANCP Core Library.
	 *
	 * @since 0.19.0
	 */
	class Loader {

		/**
		 * Registered bundles: version string => absolute core root path.
		 *
		 * @var array<string,string>
		 */
		private static $bundles = array();

		/**
		 * Whether the core has been booted this request.
		 *
		 * @var bool
		 */
		private static $booted = false;

		/**
		 * The version that won negotiation and was booted.
		 *
		 * @var string|null
		 */
		private static $active_version = null;

		/**
		 * Register a bundled core version.
		 *
		 * @since 0.19.0
		 * @param string $version Semver-ish version of this bundle's core.
		 * @param string $dir     Absolute path to the bundle's core root (the
		 *                        directory containing includes/).
		 * @return void
		 */
		public static function register( $version, $dir ) {
			// If two bundles ship the same version, first registration wins; the
			// payload is identical so the path choice is immaterial.
			if ( ! isset( self::$bundles[ $version ] ) ) {
				self::$bundles[ $version ] = $dir;
			}
		}

		/**
		 * Boot the highest registered core version. Idempotent.
		 *
		 * @since 0.19.0
		 * @return void
		 */
		public static function boot() {
			if ( self::$booted || empty( self::$bundles ) ) {
				return;
			}

			// Highest version wins.
			$versions = array_keys( self::$bundles );
			usort( $versions, 'version_compare' );
			$winner = end( $versions );
			$dir    = self::$bundles[ $winner ];

			// The winning payload lists its own files in its manifest, so a
			// newer payload always loads completely regardless of which
			// bundle's copy of this loader is running.
			require_once $dir . '/includes/ancp-boot.php';

			Core::init( $winner );

			self::$active_version = $winner;
			self::$booted         = true;
		}

		/**
		 * Whether the core has booted this request.
		 *
		 * @since 0.19.0
		 * @return bool
		 */
		public static function is_booted() {
			return self::$booted;
		}

		/**
		 * The booted (winning) core version, or null before boot.
		 *
		 * @since 0.19.0
		 * @return string|null
		 */
		public static function active_version() {
			return self::$active_version;
		}
	}
}
