<?php
/**
 * ModuleRegistry — Central module management system.
 *
 * Module discovery is fully driven by module.json files found in each
 * subdirectory of includes/modules/. No PHP change is needed when adding or
 * removing a module — add the directory with a module.json and it boots
 * automatically, sorted by the `priority` field.
 *
 * MODULE ISOLATION CONTRACT
 *   - Each module receives only $plugin in its constructor.
 *   - No module holds a reference to another module.
 *   - Cross-module communication happens exclusively via WordPress hooks.
 *
 * @package UltraguardPro\modules
 */

namespace UltraguardPro\modules;

use UltraguardPro\Plugin;
use UltraguardPro\contracts\ModuleInterface;

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

class ModuleRegistry {

    /** @var Plugin */
    private Plugin $plugin;

    /** @var ModuleInterface[]  slug => instance */
    private array $instances = [];

    /** @var bool */
    private bool $booted = false;

    /** @var ModuleManager|null */
    private ?ModuleManager $manager = null;

    public function __construct( Plugin $plugin ) {
        $this->plugin = $plugin;
    }

    /**
     * Instantiate and boot all registered modules.
     * Called once by Plugin::init().
     */
    public function boot(): void {
        if ( $this->booted ) { return; }

        // 1. Boot ModuleManager — registers third-party autoloaders
        $this->manager = new ModuleManager( $this->plugin );
        $this->manager->register_autoloaders();

        // 2. Discover built-in definitions from module.json files (via ModuleManager)
        //    then merge third-party definitions and apply the filter.
        $definitions = $this->manager->get_builtin_class_definitions();
        $definitions = array_merge( $definitions, $this->manager->get_extra_definitions() );
        $definitions = apply_filters( 'ultraguard_pro/module_definitions', $definitions );

        do_action( 'ultraguard_pro/modules_init/before', $this->plugin );

        foreach ( $definitions as $id => $class ) {
            $this->load_module( $id, $class );
        }

        $this->booted = true;

        do_action( 'ultraguard_pro/modules_loaded',     $this->plugin );
        do_action( 'ultraguard_pro/modules_init/after', $this->plugin );
    }

    /**
     * Instantiate and conditionally boot a single module.
     */
    private function load_module( string $id, string $class ): void {
        if ( ! class_exists( $class ) ) { return; }

        try {
            /** @var ModuleInterface $module */
            $module = new $class( $this->plugin );

            if ( ! ( $module instanceof ModuleInterface ) ) {
                throw new \LogicException( esc_html( "{$class} must implement ModuleInterface." ) );
            }

            $this->instances[ $id ] = $module;

            $manager_ok = $this->manager ? $this->manager->is_active( $id ) : true;

            if ( $module->is_enabled() && $manager_ok ) {
                $module->boot();
                do_action( 'ultraguard_pro/module_booted', $id, $module );
            }

        } catch ( \Throwable $e ) {
            \UltraguardPro\core\Logger::error(
                "Failed to load module [{$id}]: " . $e->getMessage(),
                [ 'file' => $e->getFile(), 'line' => $e->getLine() ]
            );

            add_action( 'admin_notices', function () use ( $id ) {
                if ( function_exists( '\\UltraguardPro\\ultraguard_current_user_can_manage' ) && \UltraguardPro\ultraguard_current_user_can_manage() ) {
                    echo '<div class="notice notice-error"><p>' .
                        esc_html( sprintf(
                            /* translators: %s: module slug */
                            __( 'UltraGuard Pro: the "%s" module could not be loaded. Check your PHP error log for details.', 'ultraguard-security-suite' ),
                            $id
                        ) ) .
                    '</p></div>';
                }
            } );
        }
    }

    // ── Public API ─────────────────────────────────────────────────────────────

    public function get( string $id ): ?ModuleInterface {
        return $this->instances[ $id ] ?? null;
    }

    public function has( string $id ): bool {
        return isset( $this->instances[ $id ] );
    }

    public function all(): array {
        return $this->instances;
    }

    /** Expose ModuleManager for dashboard UI and AJAX handlers. */
    public function get_module_manager(): ?ModuleManager {
        return $this->manager;
    }

    /**
     * Shortcut to retrieve the DatabaseTables module.
     *
     * @return \UltraguardPro\modules\db_tables\DatabaseTablesModule|null
     */
    public function get_db_tables(): ?\UltraguardPro\modules\db_tables\DatabaseTablesModule {
        return $this->instances['db_tables'] ?? null;
    }
}
