<?php
/**
 * ModuleManager class.
 *
 * Handles discovery, registration, booting, and asset loading of internal modules.
 *
 * @package Ilabs\Firevert\Core
 */

declare( strict_types=1 );

namespace Ilabs\Firevert\Core;

use Ilabs\Firevert\Core\Exceptions\ModuleBootException;
use Ilabs\Firevert\Core\Settings\Form\SettingsStorageService;

/**
 * Handles module discovery and lifecycle.
 */
class ModuleManager {

	/**
	 * Loaded module instances.
	 *
	 * @var ModuleInterface[]
	 */
	private array $modules = array();

	/**
	 * Maps slug to folder name, e.g. 'power_widget' => 'PowerWidget'.
	 *
	 * @var array<string, string>
	 */
	private array $slug_to_folder_map = array();

	/**
	 * Registers and boots all modules from the Modules directory.
	 *
	 * @param ServiceContainer       $container Service container instance.
	 * @param SettingsStorageService $storage Settings storage service instance.
	 *
	 * @return void
	 */
	public function register_modules( ServiceContainer $container, SettingsStorageService $storage ): void {
		$modules_path = dirname( __DIR__, 2 ) . '/src/Modules';

		foreach ( glob( $modules_path . '/*/ModuleInit.php' ) as $module_file ) {
			require_once $module_file;

			$module_folder = basename( dirname( $module_file ) );
			$class         = sprintf(
				'Ilabs\\Firevert\\Modules\\%s\\ModuleInit',
				$module_folder
			);

			if ( class_exists( $class ) ) {
				$module = new $class();

				if ( ! $module instanceof ModuleInterface ) {
					continue;
				}

				$is_enabled = '1' === $storage->get_module_setting( $module->get_slug(), 'enabled' );

				$module->register_settings( $container, $is_enabled );

				if ( $is_enabled ) {
					$this->register_single_module( $module, $container, $module_folder );

					add_action(
						'init',
						function () use ( $module, $container ) {
							if ( function_exists( 'post_type_exists' )
								&& post_type_exists( $module->get_cpt_slug() ) ) {
								$module->install_default_settings( $container );
							}
						},
						20
					);
				}
			}
		}
	}

	/**
	 * Registers and boots a single module (internal or external).
	 *
	 * @param ModuleInterface  $module Module instance.
	 * @param ServiceContainer $container Dependency injection container.
	 * @param string|null      $module_folder Optional folder name override.
	 *
	 * @return void
	 *
	 * @throws ModuleBootException If boot fails.
	 */
	public function register_single_module(
		ModuleInterface $module,
		ServiceContainer $container,
		?string $module_folder = null
	): void {
		if ( $module->requires_licence() ) {
			// todo: Integrate with LicenseManager.
			return;
		}

		try {
			$module->register_services( $container );
			$module->register_hooks( $container );

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

			if ( null === $module_folder ) {
				$module_folder = $module->get_folder_name();
			}

			$this->slug_to_folder_map[ $slug ] = $module_folder;

			$module->enqueue_assets( $container );
		} catch ( \Throwable $e ) {
			throw new ModuleBootException(
				sprintf( 'Failed to boot module: %s', esc_html( $module->get_slug() ) ),
				0,
				// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
				$e
			);
		}
	}

	/**
	 * Returns all registered modules.
	 *
	 * @return ModuleInterface[]
	 */
	public function get_modules(): array {
		return $this->modules;
	}

	/**
	 * Returns ModuleInterface for a given module slug.
	 *
	 * @param string $slug Module slug.
	 *
	 * @return ModuleInterface|null Module instance or null if not found.
	 */
	public function get_module_by_slug( string $slug ): ?ModuleInterface {
		foreach ( $this->modules as $module ) {
			if ( $module->get_slug() === $slug ) {
				return $module;
			}
		}

		return null;
	}

	/**
	 * Returns folder name for a given slug (e.g. 'power_widget' => 'PowerWidget').
	 *
	 * @param string $slug Module slug.
	 *
	 * @return string|null Folder name or null if not mapped.
	 */
	public function get_folder_by_slug( string $slug ): ?string {
		return $this->slug_to_folder_map[ $slug ] ?? null;
	}
}
