<?php
/**
 * Plugin version upgrade and migration runner.
 *
 * @package WP_PowerSuite\Core
 * @since 1.0.0
 */

namespace WP_PowerSuite\Core;

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

/**
 * Runs idempotent migrations when the plugin version changes.
 */
final class PluginUpgrader {

	/**
	 * Option key for the installed plugin version.
	 */
	public const VERSION_OPTION = 'wp_powersuite_version';

	/**
	 * Run upgrade checks once per request after bootstrap is available.
	 */
	public static function maybe_run(): void {
		if ( wp_installing() ) {
			return;
		}

		if ( ! defined( 'WP_POWERSUITE_VERSION' ) ) {
			return;
		}

		$stored_version = self::get_stored_version();

		if ( $stored_version === WP_POWERSUITE_VERSION ) {
			return;
		}

		if ( $stored_version === false ) {
			self::set_version( WP_POWERSUITE_VERSION );
			return;
		}

		self::run_migrations( $stored_version, WP_POWERSUITE_VERSION );
		self::set_version( WP_POWERSUITE_VERSION );
	}

	/**
	 * @return string|false Stored semver or false when unset.
	 */
	public static function get_stored_version(): string|false {
		if ( NetworkScope::usesNetworkStorage() ) {
			$stored = get_site_option( self::VERSION_OPTION, false );
		} else {
			$stored = get_option( self::VERSION_OPTION, false );
		}

		return is_string( $stored ) && $stored !== '' ? $stored : false;
	}

	/**
	 * Persist the installed plugin version for upgrade checks.
	 */
	public static function set_version( string $version ): void {
		if ( NetworkScope::usesNetworkStorage() ) {
			update_site_option( self::VERSION_OPTION, $version );
			return;
		}

		update_option( self::VERSION_OPTION, $version, false );
	}

	/**
	 * Drop module metadata transients and in-memory option caches.
	 */
	public static function flush_caches(): void {
		DataRegistry::clearCaches();

		OptionStore::getInstance()->clearCache();
		wp_cache_delete( 'alloptions', 'options' );
	}

	/**
	 * @param string $from Previously stored version.
	 * @param string $to   Target version ({@see WP_POWERSUITE_VERSION}).
	 */
	private static function run_migrations( string $from, string $to ): void {
		if ( version_compare( $from, '1.0.0', '<' ) ) {
			OptionStore::getInstance()->seedDefaultsIfMissing();
		}

		self::remove_retired_module_once( 'admin-color-presets' );

		self::flush_caches();
		OptionAutoloadMigration::run();

		/**
		 * Fires after core upgrade routines run for a version bump.
		 *
		 * @since 1.0.0
		 * @param string $from Previously stored version.
		 * @param string $to   Target version.
		 */
		do_action( 'wp_powersuite_upgrade', $from, $to );
	}

	/**
	 * Remove a retired module from enabled lists and delete its settings blob (once per site).
	 */
	private static function remove_retired_module_once( string $module_id ): void {
		$module_id = sanitize_key( $module_id );
		if ( $module_id === '' ) {
			return;
		}

		$flag = 'wp_powersuite_removed_' . str_replace( '-', '_', $module_id );
		if ( NetworkScope::usesNetworkStorage() ) {
			if ( get_site_option( $flag, false ) ) {
				return;
			}
		} elseif ( get_option( $flag, false ) ) {
			return;
		}

		self::remove_retired_module( $module_id );

		if ( NetworkScope::usesNetworkStorage() ) {
			update_site_option( $flag, 1 );
		} else {
			update_option( $flag, 1, false );
		}
	}

	/**
	 * Remove a retired module from enabled lists and delete its settings blob.
	 */
	private static function remove_retired_module( string $module_id ): void {
		$module_id = sanitize_key( $module_id );
		if ( $module_id === '' ) {
			return;
		}

		$option_store = OptionStore::getInstance();
		$option_store->clearCache();
		$settings = $option_store->getAllSettings();
		$changed  = false;

		foreach ( [ 'enabled_modules', 'favorites', 'module_order' ] as $list_key ) {
			if ( ! isset( $settings[ $list_key ] ) || ! is_array( $settings[ $list_key ] ) ) {
				continue;
			}
			$filtered = array_values(
				array_filter(
					$settings[ $list_key ],
					static fn( $id ): bool => sanitize_key( (string) $id ) !== $module_id
				)
			);
			if ( $filtered !== $settings[ $list_key ] ) {
				$settings[ $list_key ] = $filtered;
				$changed               = true;
			}
		}

		if ( isset( $settings[ $module_id ] ) ) {
			unset( $settings[ $module_id ] );
			$changed = true;
		}

		if ( ! $changed ) {
			return;
		}

		if ( NetworkScope::usesNetworkStorage() ) {
			update_site_option( 'wp_powersuite_settings', $settings );
		} else {
			update_option( 'wp_powersuite_settings', $settings, false );
		}

		$option_store->clearCache();
	}
}
