<?php

declare(strict_types=1);

namespace FiloBlu\ExtBlackbirdMenuManager\Model\Menu;


use Blackbird\MenuManager\Api\Data\MenuInterface;
use Blackbird\MenuManager\Api\MenuRepositoryInterface;
use Blackbird\MenuManager\Api\NodeRepositoryInterface;
use Magento\Framework\Api\SearchCriteriaBuilderFactory;
use Magento\Framework\Serialize\SerializerInterface;

/**
 *
 */
class Exporter implements ExporterInterface
{
    /**
     * @var \Magento\Framework\Api\SearchCriteriaBuilderFactory
     */
    private $searchCriteriaBuilderFactory;
    /**
     * @var \Blackbird\MenuManager\Api\MenuRepositoryInterface
     */
    private $menuRepository;
    /**
     * @var \Blackbird\MenuManager\Api\NodeRepositoryInterface
     */
    private $nodeRepository;
    /**
     * @var \Magento\Framework\Serialize\SerializerInterface
     */
    private $serializer;


    /**
     * @param \Magento\Framework\Api\SearchCriteriaBuilderFactory $searchCriteriaBuilderFactory
     * @param \Blackbird\MenuManager\Api\MenuRepositoryInterface $menuRepository
     * @param \Blackbird\MenuManager\Api\NodeRepositoryInterface $nodeRepository
     * @param \Magento\Framework\Serialize\SerializerInterface $serializer
     */
    public function __construct(
        SearchCriteriaBuilderFactory $searchCriteriaBuilderFactory,
        MenuRepositoryInterface $menuRepository,
        NodeRepositoryInterface $nodeRepository,
        SerializerInterface $serializer
    ) {
        $this->menuRepository = $menuRepository;
        $this->searchCriteriaBuilderFactory = $searchCriteriaBuilderFactory;
        $this->nodeRepository = $nodeRepository;
        $this->serializer = $serializer;
    }

    /**
     * @param array $ids
     * @return bool|string
     */
    public function export(array $ids): string
    {
        $output = [];
        $builder = $this->searchCriteriaBuilderFactory->create();

        if (!empty($ids))
        {
            $builder->addFilter('menu_id', $ids, 'in');
        }

        /** @var \Magento\Framework\Api\SearchResultsInterface $result */
        $result = $this->menuRepository->getList($builder->create());

        /** @var \Blackbird\MenuManager\Model\Menu|\Blackbird\MenuManager\Api\Data\MenuInterface $menu */
        foreach ($result->getItems() as $menu)
        {
            $output[] = $this->createMenuEntry($menu);
        }

        return $this->serializer->serialize($output) ?: '{}';
    }

    /**
     * @param \Blackbird\MenuManager\Api\Data\MenuInterface $menu
     * @return array
     */
    public function createMenuEntry(MenuInterface $menu)
    {
        $stores = $menu->getResource()
                       ->lookupStoreIds($menu->getId())
        ;


        $menuData = $menu->getData();
        unset($menuData['menu_id']);

        return [
            'data'   => $menuData,
            'stores' => $stores,
            'nodes'  => $this->getNodeTree($menu)
        ];
    }

    /**
     * @param $menu
     * @return array
     */
    public function getNodeTree($menu)
    {
        $nodeTree = [];

        $result = $this->nodeRepository->getByMenu($menu->getId());


        foreach ($result as $key => $node)
        {
            if ($node->getParentId() !== null)
            {
                continue;
            }

            $currentId = (int)$node->getId();
            $nodeData = $node->toArray();

            unset($result[$key], $nodeData['node_id'], $nodeData['menu_id'], $nodeData['parent_id']);
            $nodeData['nodes'] = $this->getChildren($result, $currentId);
            $nodeTree[] = $nodeData;
        }


        return $nodeTree;
    }

    /**
     * @param $result
     * @param $nodeId
     * @return array
     */
    public function getChildren(&$result, $nodeId): array
    {
        $children = [];
        foreach ($result as $key => $node)
        {
            $parentId = (int)$node->getParentId();
            $currentNodeId = (int)$node->getId();


            if ($parentId !== $nodeId)
            {
                continue;
            }
            $nodeData = $node->toArray();

            unset($result[$key], $nodeData['node_id'], $nodeData['menu_id'], $nodeData['parent_id']);

            $nodeData['nodes'] = $this->getChildren($result, $currentNodeId);
            $children[] = $nodeData;
        }

        return $children;
    }

}