<?php declare(strict_types=1);

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

use Neos\ContentRepository\Domain\Model\Node;
use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\ContentRepository\Domain\Projection\Content\TraversableNodeInterface;
use Neos\Flow\Configuration\ConfigurationManager;
use Newland\NeosCommon\Service\NodeService;
use Newland\NeosIcons\IconUrlService;
use Newland\Toubiz\Api\ObjectAdapter\Attributes\TourAttributes;
use Newland\Toubiz\Map\Neos\Provider\Contract\Marker;
use Newland\Toubiz\Poi\Neos\Service\ArticleUrlService;
use Newland\Toubiz\Sync\Neos\Domain\Model\Article;

trait ArticleFormatting
{
    /** @var NodeService */
    protected $nodeService;

    public function injectNodeService(NodeService $nodeService): void
    {
        $this->nodeService = $nodeService;
    }

    /** @var ArticleUrlService */
    protected $articleUrlService;

    public function injectArticleUrlService(ArticleUrlService $articleUrlService): void
    {
        $this->articleUrlService = $articleUrlService;
    }

    /** @var IconUrlService */
    protected $iconUrlService;

    public function injectArticleIconService(IconUrlService $iconUrlService): void
    {
        $this->iconUrlService = $iconUrlService;
    }

    /** @var array */
    protected $defaultIconSettings;

    public function injectDefaultIconSettings(ConfigurationManager $configurationManager): void
    {
        $this->defaultIconSettings = (array) $configurationManager->getConfiguration(
            ConfigurationManager::CONFIGURATION_TYPE_SETTINGS,
            'Newland.Toubiz.Map.Neos.markers.defaultIcons'
        );
    }

    protected function articleToMarker(
        Article $article,
        Node $articleNode,
        bool $asyncTourGeometry = true
    ): ?Marker {
        if (!$article->getHasGeocoordinates()) {
            return null;
        }

        $marker = new Marker(
            $article->getPersistenceObjectIdentifier(),
            [ sprintf(
                '%s/%s',
                $articleNode->findNodePath(),
                $article->getPersistenceObjectIdentifier()
            ) ],
            (float) $article->getLongitude(),
            (float) $article->getLatitude(),
            $article->getName()
        );

        $marker->categoryTitle = $this->getCategoryTitle($article, $articleNode);
        $marker->url = $this->articleUrlService->generateUrlByCurrentNode($article, $articleNode);
        $marker->outdoorActiveTrackingId = $article->getOutdoorActiveId();

        $medium = $article->getMainMedium();
        if ($medium !== null) {
            $marker->imageUrl = $medium->getPreviewUri();
            $marker->imageAlt = $medium->getTitle();
        }

        $marker->defaultStyle = $this->defaultIconSettings['mainType'][$article->getMainType()] ?? [];
        if ($articleNode instanceof NodeInterface) {
            $marker->defaultStyle['iconUrl'] = $this->iconUrlService->buildMarkerIconUrlFromNode(
                $articleNode,
                $marker->defaultStyle
            );
        }

        $detailEndpoints = [];
        if ($article->getIsTour()) {
            $marker->tour = [
                'difficultyRating' => $article->getFirstAttribute(TourAttributes::DIFFICULTY_RATING),
            ];

            if ($asyncTourGeometry) {
                $detailEndpoints['tour.polygon'] = $this->articleUrlService->tourGeometryApiUrl($article, $articleNode);
            } else {
                $marker->tour['polygon'] = $article->getFirstAttribute(TourAttributes::GEOMETRY) ?: [];
            }
        }

        if ($article->getOpeningTimes() !== null) {
            $detailEndpoints['openingTimes'] = $this->articleUrlService->openingTimesApiUrl($article, $articleNode);
        }

        $marker->additionalProperties = [ 'detailApiEndpoints' => (object) $detailEndpoints ];
        return $marker;
    }

    private function getCategoryTitle(Article $article, NodeInterface $articleNode): string
    {
        $category = $article->getMainCategory();
        if ($category !== null) {
            return $category->getTitle();
        }

        $parent = $this->nodeService->getClosestParentOfType(
            $articleNode,
            'Newland.Toubiz.Map.Neos:Map.FilterItem'
        );
        if ($parent !== null) {
            return (string) $parent->getProperty('title');
        }

        return '';
    }
}
