<?php
namespace Newland\Toubiz\Poi\Neos\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\ContentRepository\Domain\Model\Node;
use Neos\Flow\Annotations as Flow;
use Newland\NeosCommon\LinkHandler\LinkingService;
use Newland\NeosCommon\Service\NodeService;
use Newland\Toubiz\Poi\Neos\Domain\Repository\TopicRepository;
use Newland\Toubiz\Poi\Neos\Encoder\TopicsToQueryEncoder;
use Newland\Toubiz\Poi\Neos\Filter\ArticleFilterFactory;
use Newland\Toubiz\Poi\Neos\Filter\Items\ArticleRoot;
use Newland\Toubiz\Poi\Neos\Service\CacheService;
use Newland\Toubiz\Sync\Neos\Domain\Filter\ArticleFilter;

class FilteredListsController extends AbstractActionController
{
    public const CACHE_NAME = 'Newland_Toubiz_Poi_Neos-FilteredLists';
    public const CACHE_KEY_TEMPLATE = 'SelectableFilterSections-%s';

    /**
     * @var TopicRepository
     * @Flow\Inject()
     */
    protected $topicRepository;

    /**
     * @var TopicsToQueryEncoder
     * @Flow\Inject()
     */
    protected $topicsToQueryEncoder;

    /**
     * @var CacheService
     * @Flow\Inject()
     */
    protected $cacheService;

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

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

    public function indexAction(): void
    {
        $articleType = $this->properties['articleType'];
        $filter = (new ArticleFilterFactory($this->node))
            ->createFilterForArticleType($articleType, $this->properties)
            ->initializeForFilteredLists($this->request);

        $topics = $this->topicRepository->findByIdentifiers($this->properties['topics'] ?? []);
        $lists = $this->topicRepository->findByIdentifiers($this->properties['lists'] ?? []);

        $this->view->assignMultiple(
            [
                'filter' => $filter,
                'topics' => $topics,
                'lists' => $lists,
                'properties' => $this->properties,
                'listLimit' => $this->properties['listLimit'] ?? 11,
                'documentNode' => $this->nodeService->getDocumentNode($this->node),
            ]
        );
    }

    public function showAction(Node $node = null): void
    {
        // For AJAX requests we need to set the node manually and re-parse the properties, etc.
        $this->initializeNode($node);

        $articleType = $this->properties['articleType'];
        $filter = (new ArticleFilterFactory($this->node))
            ->createFilterForArticleType($articleType, $this->properties)
            ->initializeForFilteredLists($this->request);

        $count = $filter->countArticles();
        $articles = $filter
            ->getArticleQuery()
            ->setMaxResults($this->settings['gridItemsPerPage'])
            ->getQuery()
            ->execute();

        $page = $this->getCurrentPageNumberFromRequest();
        $pages = ceil($count / $this->settings['gridItemsPerPage']);

        $this->view->assignMultiple(
            [
                'filter' => $filter,
                'articles' => $articles,
                'count' => $count,
                'format' => $node ? 'ajax' : 'html',
                'pagination' => [
                    'isFirst' => $page === 1,
                    'page' => $page,
                    'isLast' => $pages === $page,
                    'count' => [
                        'items' => $count,
                        'pages' => $pages,
                    ],
                ],
            ]
        );
    }

    public function showTeaserListAction(): void
    {
        $this->initializeNode();

        $articleType = $this->properties['articleType'];
        $filter = (new ArticleFilterFactory($this->node))
            ->createFilterForArticleType($articleType, $this->properties)
            ->initializeForFilteredLists($this->request);

        $count = $filter->countArticles();
        $articles = $filter
            ->getArticleQuery()
            ->setMaxResults($this->settings['listItemsPerPage'])
            ->getQuery()
            ->execute();

        $this->view->assignMultiple(
            [
                'title' => $this->properties['title'] ?? '',
                'articles' => $articles,
                'count' => $count,
                'listUri' => $this->getListUri($filter),
            ]
        );
    }

    protected function initializeNode(Node $node = null): void
    {
        parent::initializeNode($node);
        $this->cacheService->setCacheName(self::CACHE_NAME);
    }

    protected function removePlaceholders(string $url)
    {
        $uri = \Safe\preg_replace('/\{.*\}(\/)?/', '', $url);

        if (is_array($uri)) {
            $uri[0] = $uri[0] ?? '';
            $uri = $uri[0];
        }
        return $uri;
    }

    private function getCurrentPageNumberFromRequest(string $argument = 'page'): int
    {
        if (!$this->request->getMainRequest()->hasArgument($argument)) {
            return 1;
        }

        return max(1, (int) $this->request->getMainRequest()->getArgument($argument));
    }

    protected function getListUri(ArticleRoot $filter): string
    {
        $articleType = $this->properties['articleType'];

        $targetUri = $this->settings['linkTargets']['lists'][$articleType] ?? null;
        if ($targetUri === null) {
            return '';
        }

        if (strpos($targetUri, 'node://') === 0) {
            $node = $this->linkingService->convertUriToObject($targetUri, $this->node);
            $arguments = $filter->buildQueryStringFromOverrides($this->properties);

            return $this->linkingService->createNodeUri(
                $this->getControllerContext(),
                $node,
                $this->node,
                null,
                false,
                $arguments
            );
        }

        return $this->removePlaceholders($targetUri);
    }
}
