<?php
/**
 * Class Database_Upgrader.
 *
 * @package JWP_STK
 */

namespace JWP_STK;

defined( 'ABSPATH' ) || exit;

/**
 * Walks through versioned upgrade routines and keeps the DB schema in sync
 * with the installed plugin version.
 *
 * Usage:
 *   add_action( 'admin_init', array( Database_Upgrader::get_instance(), 'init' ) );
 *
 * To add a new upgrade routine for e.g. version 1.2.0:
 *   1. Add '1.2.0' => 'upgrade_1_2_0' to the $routines array in init().
 *   2. Implement the protected method upgrade_1_2_0().
 */
class Database_Upgrader {

	/**
	 * WP option key that stores the current DB version.
	 *
	 * @var string
	 */
	const OPTION = 'jwp_stk_db_version';

	/**
	 * WP option key that stores the previous DB version (for rollback awareness).
	 *
	 * @var string
	 */
	const PREVIOUS_OPTION = 'jwp_stk_previous_db_version';

	/**
	 * Singleton instance.
	 *
	 * @var static|null
	 */
	protected static $instance = null;

	/**
	 * Get or create the singleton instance.
	 *
	 * @return static
	 */
	public static function get_instance(): static {
		if ( null === static::$instance ) {
			static::$instance = new static();
		}
		return static::$instance;
	}

	/**
	 * Hooked into admin_init — walks through the upgrade routines array and
	 * runs any routine whose version is higher than the stored DB version.
	 *
	 * @return void
	 */
	public function init(): void {
		$routines = array();

		$version = get_option( self::OPTION, '0.0.0' );

		if ( version_compare( JWP_STK_VERSION, $version, '=' ) ) {
			return;
		}

		array_walk( $routines, array( $this, 'run_upgrade_routine' ), $version );

		$this->finish_up( $version );
	}

	/**
	 * Runs a single upgrade routine if the stored version is lower than the
	 * routine's target version.
	 *
	 * @param string $routine         Method name to call.
	 * @param string $version         The version this routine targets.
	 * @param string $current_version The currently stored DB version.
	 *
	 * @return void
	 */
	protected function run_upgrade_routine( string $routine, string $version, string $current_version ): void {
		if ( version_compare( $current_version, $version, '<' ) ) {
			$this->$routine( $current_version );
		}
	}

	/**
	 * Finishes an upgrade cycle by persisting the new DB version and saving the
	 * previous version for diagnostic / rollback purposes.
	 *
	 * @param string $previous_version The version that was active before upgrade.
	 *
	 * @return void
	 */
	protected function finish_up( string $previous_version ): void {
		update_option( self::PREVIOUS_OPTION, $previous_version );
		update_option( self::OPTION, JWP_STK_VERSION );
	}

	// ─── Upgrade routines ─────────────────────────────────────────────────────
	// Add one protected method per version that requires DB changes.
	// Each method receives the $previous_version string as its only argument.
}
