<?php

namespace apexl\Io\modules\menu\services;

use apexl\Io\includes\HookManager;
use apexl\Io\modules\display\components\Menu;
use apexl\Io\modules\menu\entities\menuEntity;
use apexl\Io\modules\menu\includes\menuItem;
use apexl\Io\modules\user\entities\userEntity;
use UnitEnum;
use function apexl\Io\container;

/**
 * Class Menu
 * @package apexl\Io\modules\menu\services
 * //@todo this needs caching
 */
final class MenuManager
{
    final public const string HOOK__ADD_TO_MENU__ROUTE_NAME = 'menu.addToMenu.routeName';
    final public const string HOOK__ADD_TO_MENU__CONFIG = 'menu.addToMenu.config';
    private const string DEFAULT_MENU = 'NAVIGATION';

    /**
     * @var MenuEntity[]
     */
    protected array $menus = [];

    public function __construct(private readonly HookManager $hookManager) {}

    public function addToMenu(
        string $routeName,
        array $config = [],
        string|UnitEnum $menu = self::DEFAULT_MENU,
    ): void {
        $menu = $this->resolveMenuName($menu);

        if (!isset($this->menus[$menu])) {
            $this->menus[$menu] = new menuEntity();
        }

        $routeName = $this->hookManager->processHook(self::HOOK__ADD_TO_MENU__ROUTE_NAME, $routeName, $menu, $config);
        $config = $this->hookManager->processHook(self::HOOK__ADD_TO_MENU__CONFIG, $config, $menu, $routeName);

        $this->menus[$menu]->addToMenu(
            $routeName,
            $config['title'] ?? '',
            $config['icon'] ?? '',
            $config['weight'] ?? 0,
            $config['parent'] ?? false,
            $config['replacements'] ?? []
        );
    }

    private function resolveMenuName(UnitEnum|string $menu): string
    {
        if (!is_string($menu)) {
            $menu = $menu->name;
        }

        return strtoupper($menu);
    }

    public function getMenuItem($routeName, string|UnitEnum $menu = self::DEFAULT_MENU): ?menuItem
    {
        if (isset($this->menus[$menu])) {
            return $this->menus[$menu]->getMenuItem($routeName);
        }

        return null;
    }

    public function generateBreadcrumbs(string $route, string|UnitEnum $menu = self::DEFAULT_MENU): array
    {
        return $this->menus[$menu]->generateBreadcrumbs($route);
    }

    /**
     * This method allows us to take all registered routes and build a menu with them. We register routes as their own dynamic entity
     */
    public function getAllItemsAsMenu(userEntity $user, string|UnitEnum $menu = self::DEFAULT_MENU, bool $filterByPermission = true): array
    {
        $menu = $this->resolveMenuName($menu);

        //We cache generated menu items so that the order can be controlled by admin users.
        return isset($this->menus[$menu]) ? $this->menus[$menu]->getAllItemsAsMenu(
            $user,
            $filterByPermission
        ) : [];
    }

    public function getMenu(string|UnitEnum $menu = self::DEFAULT_MENU): MenuEntity
    {
        $menu = $this->resolveMenuName($menu);

        return $this->menus[$menu] ?? container()->get(MenuEntity::class);
    }

    /**
     * Get the name of the Menu containing the current route.
     * Return first menu if no match found
     * @return $menu (object)
     */
    public function getActiveMenu(): ?Menu
    {
        foreach ($this->menus as $menu) {
            $firstMenu = $menu;
            if ($menu->isCurrentMenu()) {
                return $menu;
            }
        }

        return $firstMenu ?? null;
    }
}
