<?php

namespace Sitecake\Plugin;

use Sitecake\Api\Exception\MissingPluginException;
use Sitecake\Api\Sitecake;
use Sitecake\Util\ObjectRegistry;
use Sitecake\Util\Text;

class PluginRegistry extends ObjectRegistry
{
    const NAMESPACE_PREFIX = 'Sitecake\\Plugins\\';

    /**
     * Absolute path to plugin directory.
     *
     * @var string
     */
    protected $baseDir;

    /**
     * API provider.
     *
     * @var Sitecake
     */
    protected $api;

    /**
     * Config loader callable: receives a file path, returns an array.
     *
     * @var callable
     */
    protected $configLoader;

    /**
     * @param string   $pluginPath   Absolute path to plugin directory
     * @param Sitecake $api          Public API provider
     * @param callable $configLoader Callable(string $file): array — loads a PHP config file
     */
    public function __construct(string $pluginPath, Sitecake $api, callable $configLoader)
    {
        $this->baseDir      = $pluginPath;
        $this->api          = $api;
        $this->configLoader = $configLoader;
    }

    /**
     * Add a plugin instance directly.
     */
    public function add(string $name, object $pluginInstance): void
    {
        $this->loaded[$name] = $pluginInstance;
    }

    /**
     * {@inheritdoc}
     */
    protected function resolveClassName($class): string
    {
        $className = Text::camelize($class, ['_', '-']);
        $namespace = self::NAMESPACE_PREFIX . $className . '\\';

        // Register namespace so the PSR-4 autoloader can find plugin classes.
        \SitecakeClassLoader::setPsr4($namespace, [
            $this->baseDir . DIRECTORY_SEPARATOR . $class,
            $this->baseDir . DIRECTORY_SEPARATOR . $class . DIRECTORY_SEPARATOR . 'src',
            $this->baseDir . DIRECTORY_SEPARATOR . $class . DIRECTORY_SEPARATOR . 'lib',
        ]);

        return $namespace . $className;
    }

    /**
     * {@inheritdoc}
     */
    protected function throwMissingClassError($class): void
    {
        $className = Text::camelize($class, ['_', '-']);
        $namespace = self::NAMESPACE_PREFIX . $className . '\\';
        throw new MissingPluginException(['plugin' => $namespace . $className]);
    }

    /**
     * {@inheritdoc}
     */
    protected function create($class, $alias, $config)
    {
        return new $class($this->api, $config);
    }

    /**
     * Load and apply configuration for a plugin.
     */
    public function loadConfiguration(string $plugin): void
    {
        $path = $this->baseDir . DIRECTORY_SEPARATOR . $plugin . DIRECTORY_SEPARATOR . 'config.php';
        if (file_exists($path)) {
            ($this->configLoader)($path);
        }
    }
}
