<?php
/**
 * Registry Class
 *
 * @version     1.0.$Revision:$
 * @version     SVN: $Id:$
 * @package     bplan-base/globals
 * @subpackage  Registries
 * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
 * @copyright   Copyright (C) 2025, 2026 bplan-solutions GmbH & Co. KG <https://www.bplan-solutions.de/>
 * /Δ\
 */

namespace BplanBase\Globals\Registries;


use BadMethodCallException;
use BplanBase\Globals\Repositories\ModuleRepository;


/**
 * Registry für Extension-Pakete (Components)
 *
 * Ermöglicht es Extension-Paketen, sich und ihre Navigationseinträge für ein
 * oder mehrere Zielmodule zu registrieren. Das Globals-Paket verwendet diese
 * Registry um die Navigationseinträge in die Sidebar des jeweils aktiven
 * Zielmoduls einzuhängen.
 *
 * @version     1.1.0 / 2026-06-08
 * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
 */
class ExtensionRegistry extends Registry
{


/* +++ TRAITS +++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ CLASS CONSTANTS +++ ++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ OBJECT MEMBERS +++ +++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ CLASS MEMBERS +++ ++++++++++++++++++++++++++++++++++++++++++++++++++++ */


    /**
     * @var     string
     */
    private static string $_registryKey = 'extensions';


/* +++ OBJECT METHODS +++ +++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ CLASS METHODS +++ ++++++++++++++++++++++++++++++++++++++++++++++++++++ */


    /**
     * Gibt den ersten verfügbaren Zielmodul-Präfix aus einer Liste zurück
     *
     * @param       array $targetModules
     *
     * @return      string|null
     *
     * @version     1.0.0 / 2026-06-06
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    private static function _resolveTargetModule(array $targetModules): string|null
    {
        foreach ($targetModules as $candidate) {
            $Module = ModuleRepository::getByRoutePrefix($candidate);

            if ($Module !== null) {
                return $candidate;
            }
        }
        return null;

    } // _resolveTargetModule()


    /**
     * Gibt alle registrierten Extension-Einträge zurück
     *
     * @return      array
     *
     * @version     1.0.0 / 2026-06-06
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public static function all(): array
    {
        return parent::get(self::$_registryKey, []);

    } // all()


    /**
     * Gibt alle Extensions zurück, für die $moduleKey der aktive Zielmodul wäre
     *
     * Für jeden registrierten Eintrag wird geprüft welches Modul aus der
     * target-modules-Liste als erstes verfügbar ist. Stimmt dieses mit
     * $moduleKey überein, wird der Eintrag in die Ergebnisliste aufgenommen.
     *
     * @param       string $moduleKey
     *
     * @return      array
     *
     * @version     1.0.0 / 2026-06-06
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public static function allForModule(string $moduleKey): array
    {
        $result = [];

        foreach (self::all() as $routePrefix => $entry) {
            $targetModule = self::_resolveTargetModule($entry['target-modules']);

            if ($targetModule === $moduleKey) {
                $result[$routePrefix] = $entry;
            }
        }
        return $result;

    } // allForModule()


    /**
     * Schlüssel und zugehörigen Wert löschen
     *
     * @param       string $key
     *
     * @param       bool $force
     *
     * @return      mixed
     *
     * @version     1.0.0 / 2026-06-06
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public static function forget(string $key, bool $force = false): mixed
    {
        $value = parent::get(self::$_registryKey.'.'.$key, null);

        parent::forget(self::$_registryKey.'.'.$key, $force);

        return $value;

    } // forget()


    /**
     * Gibt den ersten verfügbaren Zielmodul-Präfix für einen Route-Präfix zurück
     *
     * Wird von der Middleware verwendet um den Modul-Kontext für Component-Routen
     * zu bestimmen.
     *
     * @param       string $routePrefix
     *
     * @return      string|null
     *
     * @version     1.0.0 / 2026-06-06
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public static function getTargetModule(string $routePrefix): string|null
    {
        $entry = parent::get(self::$_registryKey.'.'.$routePrefix, null);

        if ($entry === null) {
            return null;
        }
        return self::_resolveTargetModule($entry['target-modules']);

    } // getTargetModule()


    /**
     *
     * @param       string $key
     *
     * @param       mixed $default
     *
     * @return      bool
     *
     * @version     1.0.0 / 2026-06-06
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public static function has(string $key, mixed $default = null): bool
    {
        return parent::has(self::$_registryKey.'.'.$key);

    } // has()


    /**
     * Wert(e) setzen – gesperrt, nur register() verwenden
     *
     * @param       string $key
     *
     * @param       mixed $value
     *
     * @param       bool $readonly
     *
     * @throws      BadMethodCallException
     *
     * @return      void
     *
     * @version     1.0.0 / 2026-06-06
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public static function put(string $key, mixed $value, bool $readonly = false): void
    {
        throw new BadMethodCallException('Use '.__CLASS__.'::register() to register extensions.');

    } // put()


    /**
     * Registriert eine Extension mit ihren Navigationseinträgen
     *
     * @param       string $routePrefix
     *              Eigener Route-Präfix der Extension (z. B. 'tattile')
     *
     * @param       string|array $targetModules
     *              Zielmodul oder geordnete Liste von Zielmodulen (erster Treffer gewinnt)
     *
     * @param       string $localeKey
     *              Übersetzungsschlüssel für den Elterneintrag in der Sidebar
     *
     * @param       null|string $icon
     *
     * @param       null|string $permission
     *              Permission-Name (z. B. 'tattile-targets.read') — nur User mit dieser Permission sehen den Eintrag.
     *
     * @param       array $items
     *              Navigationseinträge: [['key'=>..., 'locale-key'=>..., 'route'=>..., 'permission'=>...], ...]
     *
     * @return      void
     *
     * @version     1.1.0 / 2026-06-08
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public static function register(string $routePrefix, string|array $targetModules, string $localeKey, null|string $icon = null, null|string $permission = null, array $items = []): void
    {
        if (is_array($targetModules) === false) {
            $targetModules = (array) $targetModules;
        }
        parent::put(self::$_registryKey.'.'.$routePrefix, [
            'icon'           => $icon,
            'items'          => $items,
            'locale-key'     => $localeKey,
            'permission'     => $permission,
            'target-modules' => $targetModules,
        ]);

    } // register()


} // class ExtensionRegistry extends Registry {}
