<?php // phpcs:ignore WordPress.Files.FileName.NotHyphenatedLowercase, WordPress.Files.FileName.InvalidClassFileName
/**
 * WordPress implementation of the feature manager.
 *
 * @package Autoship
 * @since 2.11.0
 */

namespace Autoship\Core\Implementations;

use Autoship\Core\FeatureManagerInterface;
use Autoship\Services\Logging\Logger;

/**
 * WordPress implementation of the feature manager.
 *
 * For remotely toggleable flags, this implementation supports a two-tier
 * priority chain:
 *
 * 1. QPilot remote flags (authoritative when available, cached 5 minutes)
 * 2. Hardcoded defaults (fallback) - the $features array below
 *
 * @package Autoship
 * @since 2.11.0
 */
class WordPressFeatureManager implements FeatureManagerInterface {

	/**
	 * Feature names that can be toggled via QPilot remote flags
	 * without a deploy.
	 *
	 * @var array<string>
	 */
	protected array $remotely_toggleable = array(
		'wholesale_pricing',
	);

	/**
	 * The features enabled.
	 *
	 * @var array|string[]
	 */
	protected array $features = array(
		'development_mode'                     => false,
		'quicklaunch'                          => true,
		'quicklaunch_lead_registration'        => true,
		'quicklaunch_account_login'            => true,
		'quicklaunch_account_logout'           => true,
		'quicklaunch_account_register'         => true,
		'quicklaunch_product_setup'            => true,
		'quicklaunch_payment_method_installer' => true,
		'quicklaunch_reset'                    => false,
		'quicklaunch_display_beacon'           => true,
		'product_sync'                         => true,
		'nextime'                              => true,
		'quicklaunch_phone_required'           => true,
		'quicklinks'                           => true,
		'snooze'                               => true,
		'qmc_components'                       => true,
		'healthcheck'                          => true,
		'utilities'                            => true,
		'wholesale_pricing'                    => true,
	);

	/**
	 * A callable that returns an array of remotely enabled feature flag names,
	 * or null if remote flags are unavailable.
	 *
	 * @var callable|null
	 */
	private $remote_flags_provider = null;

	/**
	 * Cached result from the remote flags provider.
	 *
	 * @var array<string>|null
	 */
	private ?array $remote_flags = null;

	/**
	 * Whether remote flags have already been resolved.
	 *
	 * @var bool
	 */
	private bool $remote_flags_resolved = false;

	/**
	 * Set the remote flags provider.
	 *
	 * The provider is a callable that returns an array of enabled feature flag
	 * names from QPilot, or null if remote flags are unavailable.
	 *
	 * @param callable $provider A callable returning array<string>|null.
	 *
	 * @return void
	 */
	public function set_remote_flags_provider( callable $provider ): void {
		$this->remote_flags_provider = $provider;
		$this->remote_flags          = null;
		$this->remote_flags_resolved = false;
	}

	/**
	 * Gets the value indicating if the feature is enabled or not.
	 *
	 * For remotely toggleable flags, the priority chain is:
	 * 1. QPilot remote flags (authoritative when available, cached 5 min)
	 * 2. Hardcoded default in $features array
	 *
	 * For all other flags, returns the hardcoded default.
	 *
	 * @param string $feature The name of the feature.
	 *
	 * @return bool
	 */
	public function is_enabled( string $feature ): bool {
		if ( in_array( $feature, $this->remotely_toggleable, true ) ) {
			$remote_flags = $this->resolve_remote_flags();

			if ( Logger::is_tracing_enabled() ) {
				Logger::log( 'Feature Manager', "Checking feature '{$feature}' - Remote flags: " . ( is_array( $remote_flags ) ? implode( ', ', $remote_flags ) : 'null' ) );
			}

			if ( null !== $remote_flags ) {
				return in_array( $feature, $remote_flags, true );
			}
		}

		return ! empty( $this->features[ $feature ] );
	}

	/**
	 * Lazily resolve remote feature flags from the provider.
	 *
	 * The provider is only called once per request. Subsequent calls
	 * return the cached result.
	 *
	 * @return array<string>|null The list of enabled flag names, or null if unavailable.
	 */
	private function resolve_remote_flags(): ?array {
		if ( $this->remote_flags_resolved ) {
			return $this->remote_flags;
		}

		$this->remote_flags_resolved = true;

		if ( null === $this->remote_flags_provider ) {
			return null;
		}

		$this->remote_flags = call_user_func( $this->remote_flags_provider );

		return $this->remote_flags;
	}
}
