<?php
/**
 * Module registry.
 *
 * @package MonitorCat\Module
 */

declare(strict_types=1);

namespace MonitorCat\Module;

defined( 'ABSPATH' ) || exit;

use MonitorCat\Container;
use MonitorCat\Modules\ComingSoon\ComingSoonModule;
use MonitorCat\Modules\Diagnostics\DiagnosticsModule;
use MonitorCat\Modules\Seo\SeoModule;
use MonitorCat\Modules\Speed\SpeedModule;

/**
 * Manages registration, booting, and retrieval of all plugin modules.
 */
final class ModuleRegistry {

	/**
	 * Ordered list of module class names to register.
	 *
	 * @var string[]
	 */
	private const MODULE_CLASSES = array(
		SeoModule::class,
		SpeedModule::class,
		DiagnosticsModule::class,
		ComingSoonModule::class,
	);

	/**
	 * DI container.
	 *
	 * @var Container
	 */
	private Container $container;

	/**
	 * Registered module instances keyed by slug.
	 *
	 * @var array<string, ModuleInterface>
	 */
	private array $modules = array();

	/**
	 * Constructor.
	 *
	 * @param Container $container DI container.
	 */
	public function __construct( Container $container ) {
		$this->container = $container;
	}

	/**
	 * Instantiate and boot all registered modules.
	 */
	public function boot_all(): void {
		foreach ( self::MODULE_CLASSES as $class ) {
			/** @var ModuleInterface $module */
			$module = new $class( $this->container ); // @phpstan-ignore varTag.nativeType

			$this->modules[ $module->slug() ] = $module;

			$module->boot();
		}
	}

	/**
	 * Get all registered modules.
	 *
	 * @return array<string, ModuleInterface> Modules keyed by slug.
	 */
	public function all(): array {
		return $this->modules;
	}

	/**
	 * Get all active modules.
	 *
	 * @return array<string, ModuleInterface> Active modules keyed by slug.
	 */
	public function active(): array {
		return array_filter(
			$this->modules,
			static function ( ModuleInterface $module ): bool {
				return true === $module->is_active();
			}
		);
	}

	/**
	 * Get all coming-soon (inactive) modules.
	 *
	 * @return array<string, ModuleInterface> Inactive modules keyed by slug.
	 */
	public function coming_soon(): array {
		return array_filter(
			$this->modules,
			static function ( ModuleInterface $module ): bool {
				return false === $module->is_active();
			}
		);
	}

	/**
	 * Get a specific module by slug.
	 *
	 * @param string $slug Module slug.
	 * @return ModuleInterface|null Module instance or null if not found.
	 */
	public function get( string $slug ): ?ModuleInterface {
		return $this->modules[ $slug ] ?? null;
	}

	/**
	 * Register REST API routes for all active modules.
	 */
	public function register_all_routes(): void {
		foreach ( $this->active() as $module ) {
			$module->register_routes();
		}
	}
}
