<?php

declare(strict_types=1);

namespace KupShop\FeedsBundle\Feed;

use Doctrine\Common\Collections\ArrayCollection;
use KupShop\CatalogBundle\Util\ReviewsUtil;
use KupShop\FeedGeneratorBundle\Feed\ConfigurableFeedTrait;
use KupShop\FeedGeneratorBundle\Feed\IConfigurableFeed;
use KupShop\FeedsBundle\Wrapper\ReviewWrapper;
use KupShop\I18nBundle\Translations\ReviewsTranslation;
use KupShop\KupShopBundle\Context\LanguageContext;
use Query\Operator;
use Query\QueryBuilder;
use Query\Translation;

class ReviewConfigurableFeed implements IFeed, IConfigurableFeed
{
    use ConfigurableFeedTrait;

    public static string $type = 'reviewConfigurable';

    public static string $alias = 'Hodnocení';

    public static string $objectType = 'review';

    /** @var \Query\QueryBuilder */
    protected $query;

    public function __construct(
        protected ReviewWrapper $_objectWrapper,
        protected LanguageContext $languageContext,
        protected ReviewsUtil $reviewsUtil,
    ) {
        $this->objectWrapper = $this->_objectWrapper;
    }

    public static function isAllowed(): bool
    {
        return (bool) findModule(\Modules::REVIEWS);
    }

    public function getQuery(array $feedRow): QueryBuilder
    {
        $settings = json_decode($feedRow['settings'] ?? '', true) ?? [];

        $qb = $this->reviewsUtil
               ->getQueryBuilder()
               ->addSelect(' u.name AS username, brand.name AS brand_name')
               ->leftJoin('r', 'products', 'prod', 'r.id_product=prod.id')
               ->leftJoin('prod', 'producers', 'brand', 'brand.id=prod.producer');

        if (findModule(\Modules::TRANSLATIONS)) {
            if ($settings['filter']['allowTranslations'] ?? false) {
                $langID = mb_strtolower($this->languageContext->getActiveId());
                $qb->andWhere(Translation::coalesceTranslatedFields(ReviewsTranslation::class))
                    ->addSelect('r_'.$langID.'.id AS translation_id')
                    ->andWhere('r.id_language=:id_language OR r_'.$langID.'.id IS NOT NULL')
                    ->setParameter('id_language', $this->languageContext->getActiveId());
            } else {
                $qb->andWhere(Operator::equals(['r.id_language' => $this->languageContext->getActiveId()]));
            }
        }

        foreach ($this->specs as $spec) {
            $qb->andWhere($spec);
        }

        $this->query = $qb;

        return $qb;
    }

    public function getData(array $feedRow, ?int $limit = null): \Generator
    {
        $baseQb = $this->getQuery($feedRow);

        $queryIDs = clone $baseQb;
        $queryIDs->select('r.id AS id')
            ->groupBy('r.id');
        if (isset($limit)) {
            $queryIDs->setMaxResults($limit);
        }

        foreach (array_chunk($queryIDs->execute()->fetchFirstColumn(), static::$batchSize) as $ids) {
            $qb = clone $baseQb;
            $qb->andWhere(function (QueryBuilder $qb) use ($ids) {
                $qb->andWhere(Operator::inIntArray($ids, 'r.id'));
            });

            $collection = new ArrayCollection();
            foreach ($qb->execute() as $row) {
                $collection->set($row['id'], (object) $row); // cast to (object) to force reference
            }
            $this->objectWrapper->setObjects($collection);
            foreach ($collection as $item) {
                yield $this->prepareSingleObject($item);
            }
        }
    }

    public function filterByObjectID($objectID): void
    {
        $this->specs[] = function (QueryBuilder $qb) use ($objectID) {
            $qb->andWhere(Operator::equals(['r.id' => $objectID]));
        };
    }
}
