<?php
namespace Newland\Toubiz\Poi\Neos\Search\Indexer;

/*
 * 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 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\Api\ObjectAdapter\Attributes\GenericArticleAttributes;
use Newland\Toubiz\Api\ObjectAdapter\Concern\ArticleConstants;
use Newland\Toubiz\Sync\Neos\Domain\Model\Article;
use Newland\Toubiz\Sync\Neos\Domain\Repository\ArticleRepository;
use Newland\Toubiz\Sync\Neos\Enum\ArticleType;

/**
 * Article indexer.
 *
 * Indexes articles for the search.
 *
 * @Flow\Scope("singleton")
 */
class ArticleIndexer implements IndexerInterface
{
    protected const FALLBACK_SCOPE = 'article';

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

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

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

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

    public function index(SearchBackend $backend, ProgressHandler $progressHandler): void
    {
        $this->articleRepository->withoutLanguageHandling(function () use ($backend, $progressHandler) {
            $this->total = $this->articleRepository->countAll();

            foreach ($this->articleRepository->findAllIterator() as $articles) {
                foreach ($articles as $article) {
                    $modification = $this->articleToModification($article);
                    $backend->createOrUpdateIndexEntry($modification);
                    $this->indexed[] = $modification->getIdentifier();
                    $progressHandler->informProgress('Articles', \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 articleToModification(Article $article): IndexRecordModification
    {
        $content = [
            $article->getName(),
            $article->getAbstract(),
            $article->getDescription(),
        ];

        foreach ($article->getAttributes() as $attribute) {
            if ($attribute->getName() === GenericArticleAttributes::ADDITIONAL_SEARCH_STRING) {
                $content[] = $attribute->getData();
            }
        }

        return new IndexRecordModification(
            (string) $article->getPersistenceObjectIdentifier(),
            $article->getName(),
            (string) $article->getAbstract(),
            trim(implode(' ', $content)),
            ArticleType::$map[$article->getMainType()] ?? static::FALLBACK_SCOPE,
            $article->getLanguage()
        );
    }
}
