<?php
/**
 * Conditional conflicts between Disable Application Passwords and modules that require app passwords.
 *
 * @package WP_PowerSuite\Core
 * @since 1.0.0
 */

namespace WP_PowerSuite\Core;

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

/**
 * Resolves when Application Passwords must stay available for another enabled module.
 */
final class ApplicationPasswordConflictPolicy {

	public const MODULE_DISABLE_APP_PASSWORDS = 'disable-application-passwords';

	public const MODULE_TWO_FACTOR = 'two-factor-authentication';

	public static function isDisableApplicationPasswordsEnabled(): bool {
		return OptionStoreModuleSettingsRepository::isModuleEnabled( self::MODULE_DISABLE_APP_PASSWORDS );
	}

	public static function isTwoFactorEnabled(): bool {
		return OptionStoreModuleSettingsRepository::isModuleEnabled( self::MODULE_TWO_FACTOR );
	}

	/**
	 * Stored 2FA setting: require application passwords for REST/XML-RPC.
	 *
	 * Used when deciding whether another module may be enabled. When 2FA settings were never saved,
	 * the module default is to require app passwords.
	 */
	public static function isTwoFactorRestrictAppPasswordsEnabled(): bool {
		return self::getStoredTwoFactorRestrictAppPasswords();
	}

	/**
	 * Whether 2FA actively enforces app-password-only REST/XML-RPC auth right now.
	 *
	 * Disable Application Passwords wins at runtime — {@see \TwoFactorAuthentication\Module::getSettings()}.
	 */
	public static function isTwoFactorRestrictAppPasswordsEffective(): bool {
		if ( self::isDisableApplicationPasswordsEnabled() ) {
			return false;
		}

		return self::getStoredTwoFactorRestrictAppPasswords();
	}

	/**
	 * Both modules active and 2FA still enforces app-password-only API auth — enforced roles lose API access.
	 */
	public static function hasRuntimeConflict(): bool {
		return self::isDisableApplicationPasswordsEnabled()
			&& self::isTwoFactorEnabled()
			&& self::isTwoFactorRestrictAppPasswordsEffective();
	}

	/**
	 * Persist 2FA REST/XML-RPC app-password requirement as off when Application Passwords are disabled.
	 */
	public static function clearTwoFactorRestrictWhenDisableEnabled(): void {
		if ( ! self::isTwoFactorEnabled() ) {
			return;
		}

		$repo  = OptionStoreModuleSettingsRepository::forModule( self::MODULE_TWO_FACTOR );
		$saved = $repo->all( [] );
		if ( ! is_array( $saved ) ) {
			$saved = [];
		}

		if ( empty( $saved['restrict_api_login_to_app_passwords'] ) ) {
			return;
		}

		$saved['restrict_api_login_to_app_passwords'] = false;
		$repo->save( $saved );
	}

	/**
	 * @return bool Stored intent from 2FA module settings (ignores runtime deferral).
	 */
	private static function getStoredTwoFactorRestrictAppPasswords(): bool {
		if ( ! self::isTwoFactorEnabled() ) {
			return false;
		}

		$saved = OptionStoreModuleSettingsRepository::forModule( self::MODULE_TWO_FACTOR )->all( [] );
		if ( ! is_array( $saved ) || $saved === [] ) {
			return true;
		}

		return ! empty( $saved['restrict_api_login_to_app_passwords'] );
	}

	/**
	 * Enabled module IDs that block enabling {@see $module_id} due to application-password policy.
	 *
	 * @param array<string> $enabled_list Currently enabled module IDs.
	 * @return array<string>
	 */
	public static function getBlockingModulesForEnable( string $module_id, array $enabled_list ): array {
		$module_id    = sanitize_key( $module_id );
		$enabled_set  = array_flip( $enabled_list );
		$blocking     = [];

		if ( $module_id === self::MODULE_DISABLE_APP_PASSWORDS ) {
			if ( isset( $enabled_set[ self::MODULE_TWO_FACTOR ] ) && self::isTwoFactorRestrictAppPasswordsEnabled() ) {
				$blocking[] = self::MODULE_TWO_FACTOR;
			}
		}

		return array_values( array_unique( $blocking ) );
	}

	/**
	 * Whether saving 2FA settings with REST/XML-RPC app-password requirement should be rejected.
	 *
	 * @param array<string, mixed> $settings Normalized 2FA settings about to be saved.
	 */
	public static function wouldBlockTwoFactorSettingsSave( array $settings ): bool {
		if ( empty( $settings['restrict_api_login_to_app_passwords'] ) ) {
			return false;
		}

		return self::isDisableApplicationPasswordsEnabled();
	}

	/**
	 * Admin-facing explanation when enable is blocked by this policy.
	 *
	 * @param array<string> $blocking Blocking module IDs from {@see getBlockingModulesForEnable()}.
	 */
	public static function getEnableConflictMessage( string $module_id, array $blocking ): string {
		$module_id = sanitize_key( $module_id );

		if ( $module_id === self::MODULE_DISABLE_APP_PASSWORDS && in_array( self::MODULE_TWO_FACTOR, $blocking, true ) ) {
			return __(
				'Cannot enable Disable Application Passwords while 2-Factor Authentication requires application passwords for REST/XML-RPC. Turn off that 2FA setting or disable 2-Factor Authentication first.',
				'wp-powersuite'
			);
		}

		return __(
			'This module conflicts with an enabled module because Application Passwords cannot be both disabled and required.',
			'wp-powersuite'
		);
	}

	/**
	 * Message when 2FA settings save would create a conflict.
	 */
	public static function getTwoFactorSettingsConflictMessage(): string {
		return __(
			'Cannot require application passwords for REST/XML-RPC while Disable Application Passwords is enabled. Turn off Disable Application Passwords or leave this option unchecked.',
			'wp-powersuite'
		);
	}
}
