<?php

namespace App\Core;

/**
 * Autoloader — PSR-4 Style Class Autoloader
 *
 * Registers a custom SPL autoload function that maps the App\ namespace
 * to the app/ directory structure.
 *
 * Namespace-to-directory mapping (case-sensitive):
 *   App\Core\       → app/core/
 *   App\Middleware\ → app/middleware/
 *   App\Services\   → app/services/
 *   App\Modules\    → app/modules/
 *   App\Helpers\    → app/helpers/
 *
 * NOTE: Global function helpers (env.php, config.php) are NOT autoloaded.
 * They are explicitly required by Bootstrap::loadHelpers() because they
 * are functions, not classes.
 *
 * NOTE: This file must be required manually in public/index.php before
 * Autoloader::register() can be called — it cannot load itself.
 *
 * @package Inveetaire
 * @ref     DBP v1.0 Ch.5, SAD v1.1 Ch.4, INIT-003
 */
class Autoloader
{
    /**
     * Namespace prefix → base directory map.
     * Ordered from most-specific to least-specific prefix.
     * Uses ROOT_PATH (defined in public/index.php) for absolute paths.
     *
     * @var array<string, string>
     */
    private static array $prefixes = [
        'App\\Core\\'       => '/app/core/',
        'App\\Middleware\\' => '/app/middleware/',
        'App\\Services\\'   => '/app/services/',
        'App\\Modules\\'    => '/app/modules/',
        'App\\Helpers\\'    => '/app/helpers/',
    ];

    /**
     * Register this autoloader with PHP's SPL autoload stack.
     *
     * Called once from public/index.php immediately after this file
     * is manually required.
     *
     * @return void
     */
    public static function register(): void
    {
        spl_autoload_register([self::class, 'load'], true, false);
    }

    /**
     * Resolve a fully-qualified class name to a file path and require it.
     *
     * Called automatically by PHP when an unresolved class is referenced.
     *
     * @param string $class Fully-qualified class name (e.g. App\Core\Bootstrap).
     * @return void
     */
    public static function load(string $class): void
    {
        foreach (self::$prefixes as $prefix => $baseDirectory) {

            // Skip if class does not start with this namespace prefix.
            if (strncmp($prefix, $class, strlen($prefix)) !== 0) {
                continue;
            }

            // Strip the matched namespace prefix and convert remaining
            // namespace separators to directory separators.
            $relativeClass = substr($class, strlen($prefix));
            $file = ROOT_PATH
                  . $baseDirectory
                  . str_replace('\\', DIRECTORY_SEPARATOR, $relativeClass)
                  . '.php';

            if (file_exists($file)) {
                require_once $file;
                return;
            }

            // File not found for this prefix — stop searching
            // (a class can only match one prefix).
            return;
        }
    }
}
