<?php
namespace Newland\Toubiz\Poi\Neos\ViewHelpers\EntityList\Controller;

/*
 * This file is part of the "toubiz-poi-neos" package.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 */

use Neos\Flow\Annotations as Flow;
use Neos\Flow\Configuration\Exception\InvalidConfigurationException;
use Neos\Flow\Log\Utility\LogEnvironment;
use Neos\FluidAdaptor\Core\Widget\AbstractWidgetController;
use Newland\NeosCommon\LinkHandler\LinkingService;
use Newland\NeosCommon\Service\NodeService;
use Newland\Toubiz\Api\Constants\EntityListType;
use Newland\Toubiz\Poi\Neos\Service\EntityListService;
use Newland\Toubiz\Poi\Neos\Service\LinkListService;
use Newland\Toubiz\Sync\Neos\Domain\Filter\ArticleFilter;
use Newland\Toubiz\Sync\Neos\Domain\Model\Article;
use Newland\Toubiz\Sync\Neos\Domain\Model\RelatedLists\EntityList;
use Newland\Toubiz\Sync\Neos\Domain\Model\ZipCode;
use Newland\Toubiz\Sync\Neos\Domain\Repository\ArticleRepository;

class ArticlesController extends AbstractWidgetController
{
    /**
     * @var array
     * @Flow\InjectConfiguration(path="cityDetails.links.data.attractions")
     */
    protected $poiListLinkData;

    /**
     * @var EntityListService
     * @Flow\Inject()
     */
    protected $entityListService;

    /**
     * @var EntityList
     */
    private $entityList;

    /**
     * @var Article
     */
    private $article;

    /**
     * @var ArticleRepository
     * @Flow\Inject()
     */
    protected $articleRepository;

    /**
     * @var LinkingService
     * @Flow\Inject()
     */
    protected $linkingService;

    /**
     * @var LinkListService
     * @Flow\Inject()
     */
    protected $linkListService;

    /**
     * @var NodeService
     * @Flow\Inject()
     */
    protected $nodeService;

    public function initializeAction(): void
    {
        $this->entityList = $this->widgetConfiguration['entityList'] ?? null;
        $this->article = $this->widgetConfiguration['article'] ?? null;
    }

    public function indexAction(): void
    {
        $articles = [];
        $totalCount = 0;

        $identifiers = $this->getIdentifiers();

        if (!empty($identifiers)) {
            $filter = $this->getFilter($identifiers);
            $articles = $this->articleRepository->findByFilter($filter);
            $totalCount = $this->getTotalCount($filter);
        }

        $this->view->assignMultiple(
            [
                'contentArguments' => [
                    'listLink' => $this->generateListLink(),
                    'articles' => $articles,
                    'totalCount' => $totalCount,
                ],
            ]
        );
    }

    private function getIdentifiers(): array
    {
        $identifiers = [];

        if ($this->entityList !== null) {
            foreach ($this->entityList->getIdentifiers() as $identifier) {
                $identifiers[$identifier] = $identifier;
            }
        }

        return $identifiers;
    }

    private function getZipCodes(): array
    {
        if ($this->article !== null && $this->article->getCityData() !== null) {
            $zipCodes = array_map(
                function (ZipCode $zipCode) {
                    return $zipCode->getZipCode();
                },
                $this->article->getCityData()->getZipCodes()->toArray()
            );

            return $zipCodes;
        }

        return [];
    }

    private function generateListLink(): string
    {
        $node = $this->widgetConfiguration['node'];

        $siteName = $this->nodeService->getCurrentSiteNodeName($node);

        $configuration = $this->linkListService->getCityDetailConfigurationByClient($siteName);
        $this->poiListLinkData = $configuration['data']['attractions'];

        if (empty($this->poiListLinkData)) {
            throw new InvalidConfigurationException(
                'No POI list page configuration set.' .
                ' Please configure in "Newland.Toubiz.Poi.Neos.cityDetails.links.{siteName}.data.attractions".'
            );
        }

        $baseNode = $this->widgetConfiguration['node'];
        $target = $this->poiListLinkData['target'];

        $node = $this->linkingService->convertUriToObject($target, $baseNode);
        $arguments = $this->entityListService->getQuery(
            $this->entityList,
            $this->article,
            $this->poiListLinkData['queryParameters']
        );

        try {
            $uri = $this->linkingService->createNodeUri(
                $this->getControllerContext(),
                $node,
                $baseNode,
                null,
                false,
                $arguments
            );
        } catch (\Exception $exception) {
            $this->logger->error($exception->getMessage(), LogEnvironment::fromMethodName(__METHOD__));
            $uri = '';
        }

        return $uri;
    }

    private function getFilter(array $identifiers): ArticleFilter
    {
        $filter = new ArticleFilter();
        $filter->setLimit($this->widgetConfiguration['limit'] ?? 11);

        if ($this->entityList->getType() === EntityListType::ARTICLES) {
            $filter->setIdentifiers($identifiers);
        } else {
            $filter->setCategories($identifiers);
            $filter->setZips($this->getZipCodes());
        }
        return $filter;
    }

    private function getTotalCount(ArticleFilter $filter): int
    {
        $count = $this->articleRepository->countByFilter($filter, $this->widgetConfiguration['limit'] ?? 11);
        return $count['items'];
    }
}
