<?php
/**
 * Supported platform versions.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Support;

/**
 * Centralizes platform version policy for bootstrap and diagnostics.
 */
final class VersionPolicy {
	public const MIN_PHP             = '7.4';
	public const MIN_WORDPRESS       = '6.8';
	public const MIN_WOOCOMMERCE     = '8.2';
	public const MIN_MYSQL           = '5.7';
	public const MIN_MARIADB         = '10.4';
	public const RECOMMENDED_PHP     = '8.3';
	public const RECOMMENDED_MYSQL   = '8.0';
	public const RECOMMENDED_MARIADB = '10.6';
	public const TESTED_WORDPRESS    = '7.0';

	/**
	 * Determines whether a version meets a minimum.
	 *
	 * @param string $version Version under test.
	 * @param string $minimum Minimum supported version.
	 */
	public static function meets( string $version, string $minimum ): bool {
		return version_compare( $version, $minimum, '>=' );
	}

	/**
	 * Classifies a runtime version against the supported policy.
	 *
	 * @param string            $version Version under test.
	 * @param string            $minimum Minimum supported version.
	 * @param string            $recommended Recommended version.
	 * @param array<int,string> $forward_tested Forward-tested major/minor versions.
	 */
	public static function classify( string $version, string $minimum, string $recommended, array $forward_tested = array() ): string {
		if ( ! self::meets( $version, $minimum ) ) {
			return 'unsupported';
		}

		foreach ( $forward_tested as $forward_version ) {
			if ( 0 === strpos( $version, $forward_version ) ) {
				return 'forward_tested';
			}
		}

		if ( ! self::meets( $version, $recommended ) ) {
			return 'supported_legacy';
		}

		return 'recommended';
	}

	/**
	 * Returns the active database engine and compatibility level.
	 *
	 * @return array<string,string>
	 */
	public static function databaseEnvironment(): array {
		$wpdb = WpdbConnection::current();

		$server_info = '';
		$version     = '';

		if ( is_object( $wpdb ) ) {
			if ( method_exists( $wpdb, 'db_server_info' ) ) {
				$server_info = (string) $wpdb->db_server_info();
			}

			if ( method_exists( $wpdb, 'db_version' ) ) {
				$version = (string) $wpdb->db_version();
			}
		}

		$engine      = false !== stripos( $server_info, 'mariadb' ) ? 'mariadb' : 'mysql';
		$version     = self::normalizeDatabaseVersion( $server_info, $version );
		$minimum     = 'mariadb' === $engine ? self::MIN_MARIADB : self::MIN_MYSQL;
		$recommended = 'mariadb' === $engine ? self::RECOMMENDED_MARIADB : self::RECOMMENDED_MYSQL;
		$status      = '' === $version ? 'unknown' : self::classify( $version, $minimum, $recommended );

		return array(
			'engine'      => $engine,
			'version'     => $version,
			'minimum'     => $minimum,
			'recommended' => $recommended,
			'status'      => $status,
		);
	}

	/**
	 * Normalizes database versions reported by WordPress and the server.
	 *
	 * MariaDB commonly reports a MySQL compatibility prefix such as
	 * 5.5.5-10.4.x-MariaDB. The compatibility prefix must not be used for
	 * support checks.
	 *
	 * @param string $server_info Full server version string.
	 * @param string $reported_version Version returned by wpdb::db_version().
	 */
	public static function normalizeDatabaseVersion( string $server_info, string $reported_version ): string {
		if ( false !== stripos( $server_info, 'mariadb' ) ) {
			if ( preg_match_all( '/\d+\.\d+(?:\.\d+)?/', $server_info, $matches ) ) {
				foreach ( $matches[0] as $candidate ) {
					if ( '5.5.5' !== $candidate ) {
						return $candidate;
					}
				}

				return (string) end( $matches[0] );
			}
		}

		if ( '' !== $reported_version ) {
			return $reported_version;
		}

		if ( preg_match( '/(\d+\.\d+(?:\.\d+)?)/', $server_info, $matches ) ) {
			return $matches[1];
		}

		return '';
	}

	/**
	 * Returns the minimum supported platform matrix.
	 *
	 * @return array<string,string>
	 */
	public static function minimumSupported(): array {
		return array(
			'php'       => self::MIN_PHP,
			'wordpress' => self::MIN_WORDPRESS,
			'mysql'     => self::MIN_MYSQL,
			'mariadb'   => self::MIN_MARIADB,
		);
	}

	/**
	 * Returns the recommended production matrix.
	 *
	 * @return array<string,string>
	 */
	public static function recommended(): array {
		return array(
			'php'       => self::RECOMMENDED_PHP,
			'wordpress' => self::TESTED_WORDPRESS,
			'mysql'     => self::RECOMMENDED_MYSQL,
			'mariadb'   => self::RECOMMENDED_MARIADB,
		);
	}

	/**
	 * Returns the forward-tested PHP versions.
	 *
	 * @return array<int,string>
	 */
	public static function forwardTestedPhp(): array {
		return array( '8.4', '8.5' );
	}
}
