<?php
/**
 * Feature registry for Mail Doctor (free vs Pro).
 *
 * @package MailDoctor
 */

namespace MailDoctor;

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

/**
 * Centralises feature flags so the base plugin and Pro add-on can stay in sync.
 */
class Features {

	/**
	 * Cached features payload.
	 *
	 * @var array<string, mixed>|null
	 */
	protected static $cache = null;

	/**
	 * Boot the registry and expose a constant for quick checks.
	 *
	 * @return void
	 */
	public static function init(): void {
		$features = self::all();

		if ( ! defined( 'MAIL_DOCTOR_PRO_ACTIVE' ) && ! empty( $features['pro'] ) ) {
			// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound -- Constant uses plugin namespace prefix.
			define( 'MAIL_DOCTOR_PRO_ACTIVE', true );
		}
	}

	/**
	 * Retrieve the normalized feature map, filtered by extensions (e.g., Pro).
	 *
	 * @return array<string, mixed>
	 */
	public static function all(): array {
		if ( null !== self::$cache ) {
			return self::$cache;
		}

		$defaults = array(
			'pro'      => false,
			'features' => self::default_flags(),
		);

		$filtered = apply_filters( 'mail_doctor_features', $defaults );

		if ( ! is_array( $filtered ) ) {
			$filtered = $defaults;
		}

		$normalized = array(
			'pro'      => ! empty( $filtered['pro'] ),
			'features' => self::normalize_flags( $filtered['features'] ?? array() ),
		);

		self::$cache = $normalized;

		return $normalized;
	}

	/**
	 * Determine whether a specific feature is enabled.
	 *
	 * @param string $key Feature key (e.g., alerts, rest_api).
	 * @return bool
	 */
	public static function is_enabled( string $key ): bool {
		$features = self::all();

		if ( isset( $features['features'][ $key ] ) ) {
			return (bool) $features['features'][ $key ];
		}

		return false;
	}

	/**
	 * Check if Pro mode is active.
	 *
	 * @return bool
	 */
	public static function is_pro(): bool {
		return ! empty( self::all()['pro'] );
	}

	/**
	 * Reset cached features (mainly for tests).
	 *
	 * @return void
	 */
	public static function reset(): void {
		self::$cache = null;
	}

	/**
	 * Default feature switches for the base plugin (all on for compatibility).
	 *
	 * @return array<string, bool>
	 */
	protected static function default_flags(): array {
		return array(
			'alerts'             => true,
			'digest'             => true,
			'webhooks'           => true,
			'rest_api'           => true,
			'cli'                => true,
			'api_keys'           => true,
			'structured_logging' => true,
			'templates'          => true,
			'profiles'           => true,
			'retry'              => true,
			'queue'              => true,
			'export'             => false, // Requires Pro plugin (Admin_Exporter).
			'eml_download'       => false, // Requires Pro plugin (Admin_Exporter).
		);
	}

	/**
	 * Ensure feature flags are booleans and merge defaults when missing.
	 *
	 * @param mixed $flags Raw feature map.
	 * @return array<string, bool>
	 */
	protected static function normalize_flags( $flags ): array {
		$defaults = self::default_flags();

		if ( ! is_array( $flags ) ) {
			return $defaults;
		}

		$normalized = $defaults;

		foreach ( $flags as $key => $value ) {
			$key = sanitize_key( (string) $key );
			if ( '' === $key ) {
				continue;
			}

			$normalized[ $key ] = (bool) $value;
		}

		return $normalized;
	}
}
