<?php

namespace FiloBlu\ExtBlackbirdMenuManager\Block;

use Blackbird\MenuManager\Api\MenuRepositoryInterface;
use Blackbird\MenuManager\Api\NodeRepositoryInterface;
use Blackbird\MenuManager\Model\NodeTypeProvider;
use Magento\Customer\Model\Context;
use Magento\Customer\Model\Session;
use Magento\Framework\Api\Search\FilterGroupBuilder;
use Magento\Framework\Api\Search\SearchCriteriaFactory;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\DataObject\IdentityInterface;
use Magento\Framework\Exception\NoSuchEntityException;

/**
 * Class Menu
 * @package FiloBlu\ExtBlackbirdMenuManager\Block
 */
class Menu extends \Blackbird\MenuManager\Block\Menu implements IdentityInterface
{

    /**
     * @var MenuRepositoryInterface
     */
    protected $menuRepository;
    /**
     * @var NodeRepositoryInterface
     */
    protected $nodeRepository;
    /**
     * @var NodeTypeProvider
     */
    protected $nodeTypeProvider;
    /**
     * @var
     */
    protected $nodes;
    /**
     * @var
     */
    protected $menu;
    /**
     * @var SearchCriteriaFactory
     */
    protected $searchCriteriaFactory;
    /**
     * @var FilterGroupBuilder
     */
    protected $filterGroupBuilder;
    /**
     * @var Session
     */
    protected $customerSession;
    /**
     * @var bool
     */
    protected $initialized = false;
    /**
     * @var \Magento\Framework\App\Http\Context
     */
    private $httpContext;

    /**
     * @param int $level
     * @param null $parent
     * @return string
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    public function getMenuHtml($level = 0, $parent = null)
    {
        $this->init();
        $nodes = $this->getNodes($level, $parent);

        $html = '';
        $i = 0;
        $counterColumn = 1;
        foreach ($nodes as $node) {

            $childrenHtml = $this->getMenuHtml($level + 1, $node);

            $classes = [
                'level' . $level,
                $node->getClasses() ?: '',
            ];

            $childrenArray = $this->getNodes($level + 1, $node);

            if ($i === 0) {
                $classes[] = 'first';
            }

            if ($i === (count($nodes) - 1)) {
                $classes[] = 'last';
            }

            if ($level === 0) {
                $classes[] = 'level-top';
            }

            if (count($childrenArray)) {
                $classes[] = 'with-children';
            }

            $getMaxItemColumnFromParent = '';
            if ($node->getParentId()) {
                $getMaxItemColumnFromParent = $this->nodeRepository->getById($node->getParentId())->getMaxItemColumn();
            }

            if ($level > 0 && $getMaxItemColumnFromParent && ($counterColumn === ($getMaxItemColumnFromParent + 1))) {
                $counterColumn = 1;
                $html .= '</ul><ul class="level' . ($level - 1) . ' submenu submenu-sibling">';
            }

            $html .= $this->renderNode($node, $level, $classes, $childrenHtml, $childrenArray);

            ++$i;
            $counterColumn++;
        }

        return $html;
    }

    /**
     *
     */
    public function init()
    {
        if ($this->initialized) {
            return;
        }

        $objectManager = ObjectManager::getInstance();
        $this->menuRepository = $this->menuRepository ?? $objectManager->create(MenuRepositoryInterface::class);
        $this->nodeRepository = $this->nodeRepository ?? $objectManager->create(NodeRepositoryInterface::class);
        $this->nodeTypeProvider = $this->nodeTypeProvider ?? $objectManager->create(NodeTypeProvider::class);
        $this->searchCriteriaFactory = $objectManager->create(SearchCriteriaFactory::class);
        $this->filterGroupBuilder = $objectManager->create(FilterGroupBuilder::class);
        $this->customerSession = $this->customerSession ?? $objectManager->get(Session::class);
        $this->httpContext = $this->httpContext ?? $objectManager->get(\Magento\Framework\App\Http\Context::class);

        $this->initialized = true;

    }

    /**
     * @param $level
     * @param $parent
     * @return array|mixed
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    protected function getNodes($level, $parent)
    {
        $this->init();

        if (empty($this->nodes)) {
            $this->fetchData();
        }

        if (!isset($this->nodes[$level])) {
            return [];
        }

        $parentId = $parent['node_id'] ?? 0;

        return $this->nodes[$level][$parentId] ?? [];
    }

    /**
     * @throws NoSuchEntityException
     */
    protected function fetchData()
    {
        $this->init();

        $storeId = $this->_storeManager->getStore()->getId();
        $this->menu = $this->menuRepository->get($this->getData('menu'), $storeId);
        $nodes = $this->nodeRepository->getByMenu($this->menu->getId());
        $result = [];
        $types = [];
        foreach ($nodes as $node) {
            $level = $node->getLevel();
            $parent = $node->getParentId() ?: 0;
            if (!isset($result[$level])) {
                $result[$level] = [];
            }
            if (!isset($result[$level][$parent])) {
                $result[$level][$parent] = [];
            }
            $result[$level][$parent][] = $node;
            $type = $node->getType();
            if (!isset($types[$type])) {
                $types[$type] = [];
            }
            $types[$type][] = $node;
        }
        $this->nodes = $result;

        foreach ($types as $type => $nodes) {
            $this->nodeTypeProvider->prepareFrontData($type, $nodes);
        }
    }

    /**
     * @param $node
     * @param $level
     * @param $classes
     * @param $childrenHtml
     * @param $childrenArray
     * @return mixed
     */
    protected function renderNode($node, $level, $classes, $childrenHtml, $childrenArray)
    {
        $this->init();

        $inlineCss = $node->getInlineCss();
        $type = $node->getType();
        $storeId = $this->menu->getStoreId();
        return $this->nodeTypeProvider->renderFront($this->menu->getIdentifier(), $type, $node->getId(), $level, $classes, $inlineCss, $childrenHtml, $childrenArray, $storeId);
    }

    /**
     * @return array
     * @throws NoSuchEntityException
     */
    public function getCacheKeyInfo()
    {
        $this->init();

        if (!$this->menu) {
            $this->fetchData();
        }

        $isLoggedIn = $this->httpContext->getValue(Context::CONTEXT_AUTH);

        $customerGroupId = -1;
        if ($isLoggedIn) {
            $customerGroupId = $this->customerSession->getCustomer()->getGroupId();
        }

        return [
            \Blackbird\MenuManager\Model\Menu::CACHE_TAG,
            'menu_' . $this->menu->getId(),
            'store_' . $this->_storeManager->getStore()->getId(),
            'customergroup_' . $customerGroupId,
        ];
    }

    /**
     * @return bool|int|null
     */
    protected function getCacheLifetime()
    {
        return 3600;
    }

}
