<?php

namespace Webapp\Core\ApiProvider;

use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\ContextAwareQueryResultCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGenerator;
use ApiPlatform\Core\DataProvider\ContextAwareCollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
use Webapp\Core\Entity\Block;
use Webapp\Core\Entity\DataView\DataViewItem;
use Webapp\Core\Entity\Experiment;
use Webapp\Core\Entity\Individual;
use Webapp\Core\Entity\SubBlock;
use Webapp\Core\Entity\SurfacicUnitPlot;
use Webapp\Core\Entity\UnitPlot;

/**
 * Class DataViewItemProvider.
 */
class DataViewItemProvider implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface
{

    /**
     * @var ManagerRegistry
     */
    private $managerRegistry;

    /**
     * @var iterable
     */
    private $collectionExtensions;

    private IriConverterInterface $converter;

    public function __construct(ManagerRegistry $managerRegistry, IriConverterInterface $converter, iterable $collectionExtensions)
    {
        $this->managerRegistry = $managerRegistry;
        $this->collectionExtensions = $collectionExtensions;
        $this->converter = $converter;
    }

    public function getCollection(string $resourceClass, string $operationName = null, array $context = []): iterable
    {
        $manager = $this->managerRegistry->getManagerForClass(DataViewItem::class);
        $repository = $manager->getRepository(DataViewItem::class);
        /** @var QueryBuilder $queryBuilder */
        $queryBuilder = $repository->createQueryBuilder('dvi');
        $queryNameGenerator = new QueryNameGenerator();
        $individualTargets = [];
        $surfacicUnitPlotTargets = [];
        $unitPlotTargets = [];
        $subBlockTargets = [];
        $blockTargets = [];
        $experimentTargets = [];
        $context['filters']['target'] = $context['filters']['target'] ?? [];
        foreach ($context['filters']['target'] as $targetUri) {
            $target = $this->converter->getItemFromIri($targetUri);
            if ($target instanceof Individual) {
                $individualTargets[] = $target;
            } elseif ($target instanceof SurfacicUnitPlot) {
                $surfacicUnitPlotTargets[] = $target;
            } elseif ($target instanceof UnitPlot) {
                $unitPlotTargets[] = $target;
            } elseif ($target instanceof SubBlock) {
                $subBlockTargets[] = $target;
            } elseif ($target instanceof Block) {
                $blockTargets[] = $target;
            } elseif ($target instanceof Experiment) {
                $experimentTargets[] = $target;
            }
        }
        $queryBuilder->andWhere($queryBuilder->expr()->orX(
            $queryBuilder->expr()->in('dvi.individualTarget', ':individualTargets'),
            $queryBuilder->expr()->in('dvi.surfacicUnitPlotTarget', ':surfacicUnitPlotTargets'),
            $queryBuilder->expr()->in('dvi.unitPlotTarget', ':unitPlotTargets'),
            $queryBuilder->expr()->in('dvi.subBlockTarget', ':subBlockTargets'),
            $queryBuilder->expr()->in('dvi.blockTarget', ':blockTargets'),
            $queryBuilder->expr()->in('dvi.experimentTarget', ':experimentTargets'),
        ));
        $queryBuilder->orderBy('dvi.session', 'DESC');
        $queryBuilder
            ->setParameter('individualTargets', $individualTargets)
            ->setParameter('surfacicUnitPlotTargets', $surfacicUnitPlotTargets)
            ->setParameter('unitPlotTargets', $unitPlotTargets)
            ->setParameter('subBlockTargets', $subBlockTargets)
            ->setParameter('blockTargets', $blockTargets)
            ->setParameter('experimentTargets', $experimentTargets);

        foreach ($this->collectionExtensions as $extension) {
            $extension->applyToCollection($queryBuilder, $queryNameGenerator, $resourceClass, $operationName, $context);
            if ($extension instanceof ContextAwareQueryResultCollectionExtensionInterface && $extension->supportsResult($resourceClass, $operationName, $context)) {
                return $extension->getResult($queryBuilder, $resourceClass, $operationName, $context);
            }
        }

        return $queryBuilder->getQuery()->execute();
    }

    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
    {
        return DataViewItem::class === $resourceClass && $operationName === "get";
    }
}
