<?php declare(strict_types=1);

namespace Newland\Toubiz\Poi\Neos\ViewHelpers;

use Neos\Flow\Annotations as Flow;
use Neos\FluidAdaptor\Core\ViewHelper\AbstractTagBasedViewHelper;
use Newland\Toubiz\Api\ObjectAdapter\Attributes\TourAttributes;
use Newland\Toubiz\Poi\Neos\Service\MapCompatibility\ApiKeyService;
use Newland\Toubiz\Sync\Neos\Domain\Model\Article;
use function Safe\json_encode;

class MapViewHelper extends AbstractTagBasedViewHelper
{

    /**
     * @var array
     * @Flow\InjectConfiguration(package="Newland.Toubiz.Poi.Neos", path="map")
     */
    protected $configuration;

    /**
     * @var array
     * @Flow\InjectConfiguration(package="Newland.Toubiz.Map.Neos", path="geolocation")
     */
    protected $geolocationSettings;

    /**
     * @var ApiKeyService
     * @Flow\Inject()
     */
    protected $apiKeyService;

    public function render(Article $article): string
    {
        if (!$article->getHasGeocoordinates()) {
            return sprintf(
                '<!-- Article %s does not have geocoordinates -->',
                $article->getPersistenceObjectIdentifier()
            );
        }

        $configuration = (array) array_replace_recursive(
            $this->configuration['default'],
            $this->configuration['mainType'][$article->getMainType()] ?? []
        );

        $geolocationEnabled = $this->geolocationSettings['enabled'] ?? false;

        $mapType = $configuration['mapType'] ?? null;
        $zoom = $configuration['zoom'] ?? 75;

        if ($mapType === null) {
            return '<!-- Static map not rendered: No map type defined. -->';
        }

        $this->addApiKeysToTags();
        $this->tag->addAttributes(
            [
                'class' => 'tb-map tb-map--article-' . $mapType,
                'data-toubiz-standalone-map' => '',
                'data-toubiz-standalone-map.map-type' => $mapType,
                'data-toubiz-standalone-map.map.zoom' => $zoom,
                'data-toubiz-standalone-map.map.geolocation.enabled' => '(bool) ' . $geolocationEnabled,
                'data-toubiz-standalone-map.map.geolocation.wait-for-user-intent' => '(bool) true',
                'data-toubiz-standalone-map.markers.0.latitude' => $article->getLatitude(),
                'data-toubiz-standalone-map.markers.0.longitude' => $article->getLongitude(),
            ]
        );

        $geometry = $article->getFirstAttribute(TourAttributes::GEOMETRY);
        if ($geometry) {
            $this->tag->addAttribute('data-toubiz-standalone-map.markers.0.tour', json_encode($geometry));
        }

        if (array_key_exists('staticMapType', $configuration)) {
            $this->tag->addAttribute('data-toubiz-standalone-map.map.static-map-type', $configuration['staticMapType']);
        }

        if (array_key_exists('dynamicMapType', $configuration)) {
            $this->tag->addAttribute(
                'data-toubiz-standalone-map.map.dynamic-map-type',
                $configuration['dynamicMapType']
            );
        }

        $this->addIconAttributes($configuration);
        $this->addSourceSetAttributes($configuration);
        $this->tag->forceClosingTag(true);
        return $this->tag->render();
    }

    private function addApiKeysToTags(): void
    {
        $apiKeys = $this->apiKeyService->getApiKeys($this->controllerContext->getRequest());

        if (array_key_exists('googleMaps', $apiKeys)) {
            $this->tag->addAttribute(
                'data-toubiz-standalone-map.map.google-maps-api-key',
                $apiKeys['googleMaps']
            );
        }

        if (array_key_exists('toursprung', $apiKeys)) {
            $this->tag->addAttribute(
                'data-toubiz-standalone-map.map.toursprung-api-key',
                $apiKeys['toursprung']
            );
        }
    }

    private function addIconAttributes(array $configuration): void
    {
        if (!array_key_exists('markerIcon', $configuration)) {
            return;
        }

        // backwards compatibility with pre-1.18.1 configuration
        if (\is_string($configuration['markerIcon'])) {
            $this->tag->addAttributes(
                [
                    'data-toubiz-standalone-map.map.static-marker-icon-url' => $configuration['markerIcon'],
                    'data-toubiz-standalone-map.markers.0.icon-url' => $configuration['markerIcon'],
                ]
            );
            return;
        }

        $icon = $configuration['markerIcon'];
        $this->tag->addAttributes(
            [
                'data-toubiz-standalone-map.map.static-marker-icon-url' => $icon['url'],
                'data-toubiz-standalone-map.markers.0.icon-url' => $icon['url'],
                'data-toubiz-standalone-map.markers.0.icon-width' => sprintf('(int)%d', $icon['width'] ?? 64),
                'data-toubiz-standalone-map.markers.0.icon-height' => sprintf('(int)%d', $icon['height'] ?? 51),
            ]
        );
    }

    private function addSourceSetAttributes(array $configuration): void
    {
        foreach ($configuration['srcSet'] ?? [] as $index => $set) {
            $this->tag->addAttribute(
                sprintf('data-toubiz-standalone-map.map.src-set.%d.width', $index),
                '(int)' . $set['width']
            );
            $this->tag->addAttribute(
                sprintf('data-toubiz-standalone-map.map.src-set.%d.height', $index),
                '(int)' . $set['height']
            );

            if (array_key_exists('query', $set) && $set['query']) {
                $this->tag->addAttribute(
                    sprintf('data-toubiz-standalone-map.map.src-set.%d.query', $index),
                    '(string)' . $set['query']
                );
            }
        }
    }
}
