<?php declare(strict_types=1);
namespace Newland\Toubiz\Events\Neos\Search\Indexer;

/*
 * This file is part of the "toubiz-events-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 Newland\Contracts\Neos\Search\IndexerInterface;
use Newland\Contracts\Neos\Search\SearchBackend;
use Newland\Contracts\Neos\Search\IndexRecordModification;
use Newland\Contracts\Neos\Search\ProgressHandler;
use Newland\Toubiz\Sync\Neos\Domain\Filter\EventFilter;
use Newland\Toubiz\Sync\Neos\Domain\Model\Event;
use Newland\Toubiz\Sync\Neos\Domain\Repository\EventRepository;

/**
 * Event indexer.
 *
 * Indexes events for the search.
 *
 * @Flow\Scope("singleton")
 */
class EventIndexer implements IndexerInterface
{
    public const TYPE = 'event';

    /**
     * @var EventRepository
     * @Flow\Inject()
     */
    protected $eventRepository;

    /** @var int|null */
    private $total = null;

    /** @var string[] */
    protected $indexed = [];

    /** @var array */
    protected $configuration;

    public function index(array $scopesToIndex, SearchBackend $backend, ProgressHandler $progressHandler): void
    {
        $this->eventRepository->withoutLanguageHandling(
            function () use ($progressHandler, $backend, $scopesToIndex) {
                $filter = $this->filter();
                $this->total = $this->eventRepository->countByFilter($filter, 1)['items'] ?? null;

                $this->eventRepository->forEachFilter(
                    $filter,
                    function (Event $event) use ($progressHandler, $backend, $scopesToIndex) {
                        $modification = $this->eventToModification($event, $scopesToIndex);
                        $backend->createOrUpdateIndexEntry($modification);
                        $this->indexed[] = $modification->getIdentifier();
                        $progressHandler->informProgress(static::TYPE, \count($this->indexed), $this->total);
                    }
                );
            }
        );
    }

    public function postIndex(SearchBackend $backend): void
    {
        $backend->deleteObsoleteIndexEntries($this->indexed);
    }

    public function setConfiguration(array $configuration = []): void
    {
        $this->configuration = $configuration;
    }

    private function eventToModification(Event $event, array $scopes): IndexRecordModification
    {
        $content = [
            $event->getTitle(),
            $event->getDescription(),
            $event->getAdditionalSearchString(),
        ];

        return new IndexRecordModification(
            (string) $event->getPersistenceObjectIdentifier(),
            static::TYPE,
            $event->getTitle(),
            (string) $event->getDescription(),
            trim(implode(' ', $content)),
            $scopes,
            $event->getLanguage()
        );
    }

    private function filter(): EventFilter
    {
        $today = new \DateTime();
        $today->setTime(0, 0, 0);

        return (new EventFilter())
            ->setFromDate($today);
    }
}
