<?php

declare(strict_types=1);

namespace App\Plates;

use App\Entity\Awardee;
use Doctrine\ORM\EntityManager;
use Knp\Menu\ItemInterface;
use Knp\Menu\Matcher\Matcher;
use Knp\Menu\Matcher\Voter\UriVoter;
use Knp\Menu\MenuFactory;
use Knp\Menu\MenuItem;
use Knp\Menu\Renderer\ListRenderer;
use League\Plates\Engine;
use League\Plates\Extension\ExtensionInterface;
use Zend\Expressive\Router\RouterInterface;

class NavigationExtension implements ExtensionInterface
{
    /** @var RouterInterface */
    private $router;

    /** @var EntityManager */
    private $entityManager;

    /** @var MenuItem */
    private $menu;

    public function __construct(
        RouterInterface $router,
        EntityManager $entityManager
    )
    {
        $this->router = $router;
        $this->entityManager = $entityManager;
    }

    /**
     * Register functions with the Plates engine.
     *
     * Registers:
     *
     * - url($route = null, array $params = []) : string
     * - serverurl($path = null) : string
     *
     * @param Engine $engine
     */
    public function register(Engine $engine): void
    {
        $engine->registerFunction('navigation', [$this, 'generateNavigation']);
    }

    public function generateNavigation(): string
    {
        $this->initMainMenu();
        $matcher = new Matcher([
            new UriVoter($_SERVER['REQUEST_URI'])
        ]);
        $renderer = new ListRenderer($matcher, [
            'depth' => 2,
        ]);
        return $renderer->render($this->menu);
    }

    private function initMainMenu()
    {
        $factory = new MenuFactory();
        $this->menu = $factory->createItem("Main-menu");

        $prizeMenu = $this->menu->addChild(strtoupper("The Prize"), [
            'uri' => $this->getUriFromRouter('the-prize')
        ]);
        $prizeMenu->addChild("Background and Purpose", [
            'uri' => $this->getUriFromRouter('the-prize.article', ['article' => 'background-and-purpose'])
        ]);
        $prizeMenu->addChild("Description and Values", [
            'uri' => $this->getUriFromRouter('the-prize.article', ['article' => 'description-and-values'])
        ]);
        $prizeMenu->addChild("Aspects for Selection", [
            'uri' => $this->getUriFromRouter('the-prize.article', ['article' => 'aspects-for-selection'])
        ]);
        $prizeMenu->addChild("Gran Prize Award and Events", [
            'uri' => $this->getUriFromRouter('the-prize.article', ['article' => 'gran-prize-award-events'])
        ]);

        $this->menu->addChild(strtoupper("Judges"), [
            'uri' => $this->getUriFromRouter('judges')
        ]);

        $awardeesMenu = $this->menu->addChild(strtoupper("Awardees"), [
            'uri' => $this->getUriFromRouter('awardees')
        ]);
        $this->populateAwardeesSubmenu($awardeesMenu);
    }

    private function getUriFromRouter(string $name, $param = []): string
    {
        return $this->router->generateUri($name, $param);
    }

    private function populateAwardeesSubmenu(ItemInterface $awardeesMenu)
    {
        $qb = $this->entityManager->createQueryBuilder();
        $result = $qb->select('a.year')
            ->from(Awardee::class, 'a')
            ->orderBy('a.year', 'DESC')
            ->getQuery()
            ->getScalarResult();

        $years = array_unique(array_map(function ($item) {
            return $item['year'];
        }, $result));

        foreach ($years as $year) {
            $yearItem = $awardeesMenu->addChild($year, [
                'uri' => $this->getUriFromRouter('awardees-by-year', ['year' => $year])
            ]);
            $this->populateYearSubmenuArticleDummy($yearItem, (int)$year);
        }
    }

    private function populateYearSubmenuArticleDummy(ItemInterface $yearMenu, int $year)
    {
        /** @var Awardee[] $yearAwardees */
        $yearAwardees = $this->entityManager->getRepository(Awardee::class)->findBy([
           'year' => $year,
        ]);

        foreach($yearAwardees as $awardee) {
            $yearMenu->addChild($awardee->getName(), [
                'uri' => $this->getUriFromRouter('awardee', ['slug' => $awardee->getSlug()])
            ]);
        }
    }
}
