<?php

declare(strict_types=1);

namespace Signocore\Multilanguage\Application;

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

use Signocore\Multilanguage\Infrastructure\Traits\Singleton;

/**
 * Runs sequential database migrations from the stored version up to
 * {@see Migrator::CURRENT_VERSION}. Migrations are versioned strings (e.g.
 * "1.0", "1.1") and each is idempotent — running them twice must not break
 * data. The current version is persisted in the {sml_db_version} option.
 */
final class Migrator
{
	use Singleton;

	/**
	 * Bump this when adding a new migration. The version stored in the
	 * sml_db_version option is compared against this; any registered
	 * migration whose key is greater than the stored version will run.
	 */
	public const CURRENT_VERSION = '1.0';

	/**
	 * Migrations registered as version => callable. Run in order, so keep
	 * the array sorted by ascending version. Each callable must be
	 * idempotent (safe to re-run) and should not throw.
	 *
	 * @return array<string, callable():void>
	 */
	private function migrations(): array
	{
		return [
			'1.0' => function (): void {
				Database::load()->createTables();
			},
		];
	}

	/**
	 * Run every migration newer than the currently stored version, in order.
	 * Returns true if any migration ran.
	 */
	public function migrate(): bool
	{
		$current = (string) get_option(Constants::OPTION_PREFIX . 'db_version', '');
		$target = self::CURRENT_VERSION;

		if (version_compare($current, $target, '>=')) {
			return false;
		}

		$ran = false;

		foreach ($this->migrations() as $version => $migration) {
			if (version_compare($current, $version, '>=')) {
				continue;
			}

			$migration();
			update_option(Constants::OPTION_PREFIX . 'db_version', $version);
			$ran = true;
		}

		return $ran;
	}

	/**
	 * Force the stored version to a specific value. Useful for tests or
	 * recovery; not used during normal plugin operation.
	 */
	public function setVersion(string $version): void
	{
		update_option(Constants::OPTION_PREFIX . 'db_version', $version);
	}

	public function currentVersion(): string
	{
		return (string) get_option(Constants::OPTION_PREFIX . 'db_version', '');
	}
}
