<?php declare(strict_types=1);

namespace Newland\Toubiz\Poi\Neos\Controller;

use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\Flow\Annotations as Flow;
use Neos\Neos\Controller\Module\AbstractModuleController;
use Neos\Neos\Domain\Repository\SiteRepository;
use Newland\NeosCommon\Domain\Repository\NodeRepository;
use Newland\Toubiz\Api\ObjectAdapter\Concern\ArticleConstants;
use Newland\Toubiz\Poi\Neos\Filter\ArticleFilterFactory;
use Newland\Toubiz\Poi\Neos\Filter\Items\ArticleRoot;
use Newland\Toubiz\Sync\Neos\Domain\Model\Article;
use Newland\Toubiz\Sync\Neos\Domain\Repository\ArticleRepository;
use Newland\Toubiz\Sync\Neos\Domain\Repository\RecordConfigurationRepository;
use Newland\Toubiz\Sync\Neos\Enum\ArticleType;

class BackendController extends AbstractModuleController
{
    protected const PER_PAGE = 50;

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

    /**
     * @var SiteRepository
     * @Flow\Inject()
     */
    protected $siteRepository;

    /**
     * @var NodeRepository
     * @Flow\Inject()
     */
    protected $nodeRepository;

    /**
     * @var RecordConfigurationRepository
     * @Flow\Inject()
     */
    protected $recordConfiguration;

    private function argument(string $argumentName, $default)
    {
        if ($this->request->hasArgument($argumentName)) {
            return $this->request->getArgument($argumentName);
        }
        return $default;
    }

    public function indexAction(): void
    {
        $sites = $this->getSites();
        $page = (int) $this->argument('page', 1);
        $articleType = (int) $this->argument('articleType', ArticleConstants::TYPE_ATTRACTION);

        $filter = $this->initializeFilter($articleType, $page, $sites);
        $articles = $filter->getArticleQuery([], true)->getQuery()->execute();
        $count = $filter->countArticles([], true);

        $this->view->assignMultiple(
            [
                'articleTypes' => ArticleType::$map,
                'articleType' => $articleType,
                'page' => $page,
                'pageBounds' => [
                    ($page - 1) * static::PER_PAGE + 1,
                    min($count, $page * static::PER_PAGE),
                ],
                'filter' => $filter,
                'articles' => $articles,
                'total' => $count,
                'lastPage' => ceil($count / static::PER_PAGE),
            ]
        );
    }

    public function toggleHiddenAction(Article $article): void
    {
        $this->recordConfiguration->updateConfiguration(
            $article,
            function (array $config) {
                $config['hidden'] = !($config['hidden'] ?? false);
                return $config;
            },
            true
        );

        $this->redirectToRequest($this->request->getReferringRequest());
    }

    private function initializeFilter(int $articleType, int $page, array $sites): ArticleRoot
    {
        $node = $this->getCurrentNode($sites);
        $filter = (new ArticleFilterFactory($node))->createFilterForArticleType($articleType, []);
        $filter->fillStateFromRootRequestArguments($this->request);
        $filter->addTemplateRootPaths([ 'resource://Newland.Toubiz.Poi.Neos/Private/Templates/Backend/Filter' ]);
        $filter->setActionUri((string) $this->request->getHttpRequest()->getUri()->withQuery(''));
        $filter->setPageSize(static::PER_PAGE);
        $filter->setState([ 'page' => $page ]);
        $filter->addHiddenFields([ 'moduleArguments[articleType]' => $articleType ]);
        return $filter;
    }

    private function getSites(): array
    {
        $sites = $this->siteRepository->findAll();
        $result = [];
        foreach ($sites as $site) {
            $node = $this->nodeRepository->findOneByNodePath(
                sprintf('/sites/%s', $site->getNodeName()),
                true
            );
            if ($node) {
                $result[] = [ 'site' => $site, 'node' => $node ];
            }
        }
        return $result;
    }

    private function getCurrentNode(array $sites): NodeInterface
    {
        $node = null;
        if ($this->request->hasArgument('node')) {
            $node = $this->nodeRepository->findOneByNodePath($this->request->getArgument('node'));
        }
        return $node ?? $sites[0]['node'];
    }
}
