<?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 Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\QueryBuilder;
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\Model\Article;
use Newland\Toubiz\Sync\Neos\Domain\Model\RelatedLists\EntityList;
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)) {
            $query = $this->query($identifiers);
            $totalCount = (clone $query)
                    ->select('COUNT(article) as count')
                    ->getQuery()
                    ->execute([], AbstractQuery::HYDRATE_ARRAY)[0]['count'] ?? 0;
            $articles = $query
                ->setMaxResults($this->widgetConfiguration['limit'] ?? 11)
                ->getQuery()
                ->execute();
        }

        $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 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 query(array $identifiers): QueryBuilder
    {
        $query = $this->articleRepository->createQueryBuilder('article');
        $query->leftJoin('article.categories', 'category');

        if ($this->entityList->getType() === EntityListType::ARTICLES) {
            $query->andWhere($query->expr()->in('article.Persistence_Object_Identifier', $identifiers));
        } else {
            $query->andWhere($query->expr()->in('category.Persistence_Object_Identifier', $identifiers));
            if ($this->article->getIsCity()) {
                $query
                    ->leftJoin('article.cities', 'city')
                    ->andWhere(
                        $query->expr()->eq(
                            'city',
                            $query->expr()->literal($this->article->getPersistenceObjectIdentifier())
                        )
                    );
            }
        }
        return $query;
    }
}
