<?php declare(strict_types=1);

namespace Newland\Toubiz\Map\Neos\Provider\DefaultProviders;

use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\ContentRepository\Domain\NodeType\NodeTypeConstraints;
use Neos\ContentRepository\Domain\NodeType\NodeTypeName;
use Neos\ContentRepository\Domain\Projection\Content\TraversableNodeInterface;
use Newland\NeosIcons\IconUrlService;
use Newland\Toubiz\Map\Neos\Provider\Contract\FilterItem;
use Newland\Toubiz\Map\Neos\Provider\Contract\FilterItemProvider;
use Newland\Toubiz\Map\Neos\Provider\Contract\ProviderContext;
use Neos\Flow\Annotations as Flow;
use Newland\Toubiz\Map\Neos\Provider\MapDataProvider;

/**
 * @MapDataProvider()
 */
class NodeBasedFilterItems implements FilterItemProvider
{
    public const FILTER_ITEM = 'Newland.Toubiz.Map.Neos:Map.FilterItem';

    /**
     * @var IconUrlService
     * @Flow\Inject()
     */
    protected $iconUrlService;

    public function getFilterItems(ProviderContext $context): array
    {
        return $this->serializeFilterItems($context->mapNode());
    }

    protected function serializeFilterItems(TraversableNodeInterface $node, array $style = []): array
    {
        $filterItems = [];

        foreach ($this->childrenOfContentCollections($node, [ static::FILTER_ITEM ]) as $child) {
            $style['icon'] = $child->getProperty('icon') ?? $style['icon'] ?? null;
            $style['backgroundColor'] = $child->getProperty('backgroundColor') ?? $style['backgroundColor'] ?? null;
            $style['color'] = $child->getProperty('color') ?? $style['color'] ?? null;

            if ($node instanceof NodeInterface) {
                $style['iconUrl'] = $this->iconUrlService->buildMarkerIconUrlFromNode($node, $style);
            }

            $item = new FilterItem(
                $child->getIdentifier(),
                (string) $child->findNodePath(),
                (string) $child->getProperty('title')
            );
            $item->style = $style;
            $item->overwriteMarkerStyles = !$child->getProperty('useDefaultStyles');
            $item->openByDefault = (bool) $child->getProperty('openByDefault');
            $item->children = $this->serializeFilterItems($child, $style);

            $filterItems[$item->id] = $item;
        }
        return $filterItems;
    }



    public function filterItemCacheKey(ProviderContext $context): ?string
    {
        return md5(static::class . $context->mapNode()->getContextPath());
    }


    /**
     * @param string[] $nodeTypes
     */
    private function childrenOfContentCollections(TraversableNodeInterface $node, array $nodeTypes): \Generator
    {
        $constraints = new NodeTypeConstraints(
            false,
            [ NodeTypeName::fromString('Neos.Neos:ContentCollection') ]
        );
        $types = array_map(
            function (string $type) {
                return NodeTypeName::fromString($type);
            },
            $nodeTypes
        );

        foreach ($node->findChildNodes($constraints) as $contentCollection) {
            foreach ($contentCollection->findChildNodes(new NodeTypeConstraints(true, $types)) as $childNode) {
                if (!$childNode->isHidden()) {
                    yield $childNode;
                }
            }
        }
    }
}
