<?php declare(strict_types=1);

namespace App\Engine\Navigation;

/**
 * @template TNavigationItem of \App\Engine\Navigation\Menu\NavigationItem
 */
readonly class NavigationProvider
{

    public const CACHE_TTL = 3600;

    public function __construct(
        private \App\Engine\Navigation\Menu\NavigationMenuFactory $navigationMenuFactory,
        private \Symfony\Contracts\Cache\CacheInterface           $fileAdapterCache,
        private \Symfony\Component\HttpFoundation\RequestStack    $requestStack,
    ) {
    }

    /**
     * @return array<int, TNavigationItem
     */
    public function provideCached(\App\Engine\Navigation\NavigationSection $section): array
    {
        $menu = $this->fileAdapterCache->get(self::getCacheKey($section), function (\Symfony\Component\Cache\CacheItem $item) use ($section) {
            $item->expiresAfter(self::CACHE_TTL);
            return $this->provide($section);
        });
        $this->activeRouteDecorator($menu);

        return $menu;
    }

    public static function getCacheKey(\App\Engine\Navigation\NavigationSection $section): string
    {
        return "CachedNavigation_$section->value";
    }

    /**
     * @return array<int, TNavigationItem>
     */
    public function provide(\App\Engine\Navigation\NavigationSection $section): array
    {
        $navigationMenu = $this->navigationMenuFactory->create($section);
        $menu = $navigationMenu->generateMenu();
        $this->activeRouteDecorator($menu);

        return $menu;
    }

    /**
     * @param array<TNavigationItem> $navigationItems
     */
    private function activeRouteDecorator(array &$navigationItems): void
    {
        foreach ($navigationItems as $navigationItem) {
            $this->handleIsActive($navigationItem);
        }
    }

    private function handleIsActive(\App\Engine\Navigation\Menu\NavigationItem $navigationItem): void
    {
        $request = $this->requestStack->getCurrentRequest();
        $navigationItem->setIsActive($navigationItem->getUrl() === $request->getPathInfo());

        foreach ($navigationItem->getChildren() as $item) {
            $this->handleIsActive($item);
        }
    }

}