<?php
/**
 * Filters the repo config by the current set of plugins.
 *
 * @package Ealab\Deployer
 */

namespace EaLab\WP_Deployer\vendor\Ealab\Deployer\Utility\DeployerConfigRepository;

use EaLab\WP_Deployer\vendor\Ealab\Deployer\Utility\Plugin;

/**
 * Filters the repo config by the current set of plugins.
 *
 * This is useful to filter by installed plugins and core version.
 *
 * See the "tracker" or "value_handler.option" config types for the expected structure.
 */
class InstalledPluginsConfigFilter implements ConfigFilterInterface {
	/**
	 * {@inheritDoc}
	 */
	public static function filter( $config = null, ?array $options = null ) {
		if ( empty( $config ) || ! is_array( $config ) ) {
			return $config;
		}

		// Get the most suitable payload version by checking the plugin versions.
		// In theory, there should be only one payload version per plugin range.
		// Indeed, a payload version is added only when the plugin performs an upgrade
		// resulting in a change in the payload.
		// Note: if no plugin name, it means core. The selection rules are the same:
		// we select the payload version for the current core version.
		$repo_config = $config;

		$installed_plugins = Plugin::getInstalledPlugins( array( 'include_deployer' => true ) );

		foreach ( $repo_config as &$repo_config_item ) {
			// First: filter out the configs that do not match the installed plugin / core version.
			$repo_config_item = array_filter(
				$repo_config_item,
				function ( $config ) use ( $installed_plugins ) {
					$is_compatible = $config['isCompatible'] ?? null;
					$config_plugin = $config['plugin'] ?? null;
					$min_version   = $config['minVersion'] ?? null;
					$max_version   = $config['maxVersion'] ?? null;

					if ( empty( $is_compatible ) ) {
						// Not compatible with the deployer system.
						return false;
					}

					if ( empty( $config_plugin ) ) {
						// "Core" config.
						// Get the current core version.
						global $wp_version;

						return ( empty( $min_version ) || version_compare( $min_version, $wp_version, '<=' ) )
							&& ( empty( $max_version ) || version_compare( $max_version, $wp_version, '>' ) );
					}

					$plugin_version = $installed_plugins[ $config_plugin ]['Version'] ?? null;

					return ! empty( $plugin_version )
						&& ( empty( $min_version ) || version_compare( $min_version, $plugin_version, '<=' ) )
						&& ( empty( $max_version ) || version_compare( $max_version, $plugin_version, '>' ) );
				}
			);

			if ( empty( $repo_config_item ) ) {
				// No config for the current plugin / core version.
				continue;
			}

			// Second: When multiple entries are found for the same config
			// (which should never happen in theory), keep only the last,
			// which is supposed to be the most recent.
			$repo_config_item = array_slice( array_reverse( $repo_config_item, true ), 0, 1 );
		}

		// Remove entries that have no config available.
		return array_filter( $repo_config );
	}
}
