<?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\EntityManagerInterface;
use Webapp\Core\Entity\DataView\DataViewBusinessObject;
use Webapp\Core\Entity\FieldMeasure;
use Webapp\Core\Enumeration\PathLevelEnum;

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

    /**
     * @var EntityManagerInterface
     */
    private $entityManager;

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

    private IriConverterInterface $converter;

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

    public function getCollection(string $resourceClass, string $operationName = null, array $context = []): iterable
    {
        $repository = $this->entityManager->getRepository(DataViewBusinessObject::class);
        $fieldMeasureRepository = $this->entityManager->getRepository(FieldMeasure::class);

        $queryBuilder = $repository->createQueryBuilder('bo');
        $queryNameGenerator = new QueryNameGenerator();
        $sessions = [];
        foreach ($context['filters']['session'] as $sessionIri) {
            $sessions[] = $this->converter->getItemFromIri($sessionIri);

        }
        $fieldMeasureQueryBuilder = $fieldMeasureRepository->createQueryBuilder('fm');
        $fieldMeasureQueryBuilder->select('1')
            ->andWhere('COALESCE(IDENTITY(fm.experimentTarget), 0) = coalesce(IDENTITY(bo.experimentTarget), 0)')
            ->andWhere('COALESCE(IDENTITY(fm.blockTarget), 0) = coalesce(IDENTITY(bo.blockTarget), 0)')
            ->andWhere('COALESCE(IDENTITY(fm.subBlockTarget), 0) = coalesce(IDENTITY(bo.subBlockTarget), 0)')
            ->andWhere('COALESCE(IDENTITY(fm.surfacicUnitPlotTarget), 0) = coalesce(IDENTITY(bo.surfacicUnitPlotTarget), 0)')
            ->andWhere('COALESCE(IDENTITY(fm.unitPlotTarget), 0) = coalesce(IDENTITY(bo.unitPlotTarget), 0)')
            ->andWhere('COALESCE(IDENTITY(fm.individualTarget), 0) = coalesce(IDENTITY(bo.individualTarget), 0)')
            ->andWhere($fieldMeasureQueryBuilder->expr()->in('fm.session', ':sessions'));
        $queryBuilder->andWhere($queryBuilder->expr()->exists($fieldMeasureQueryBuilder));

        if ($context['filters']['filters']['x']) {
            $queryBuilder->andWhere('bo.x = :x');
            $queryBuilder->setParameter('x', $context['filters']['filters']['x']);
        }
        if ($context['filters']['filters']['y']) {
            $queryBuilder->andWhere('bo.y = :y');
            $queryBuilder->setParameter('y', $context['filters']['filters']['y']);
        }
        if ($context['filters']['filters']['experiment']) {
            $queryBuilder->andWhere('bo.experiment = :experiment');
            $queryBuilder->setParameter('experiment', $context['filters']['filters']['experiment']);
        }
        if ($context['filters']['filters']['block']) {
            $queryBuilder->andWhere('bo.block = :block');
            $queryBuilder->setParameter('block', $context['filters']['filters']['block']);
        }
        if ($context['filters']['filters']['treatment']) {
            $queryBuilder->innerJoin('bo.treatment', 'tr');
            $queryBuilder->andWhere('tr.name = :treatment');
            $queryBuilder->setParameter('treatment', $context['filters']['filters']['treatment']);
        }
        if ($context['filters']['filters']['unitPlot']) {
            $queryBuilder->andWhere($queryBuilder->expr()->orX(
                'bo.surfacicUnitPlot = :unitPlot',
                'bo.unitPlot = :unitPlot'
            ));
            $queryBuilder->setParameter('unitPlot', $context['filters']['filters']['unitPlot']);
        }
        if ($context['filters']['filters']['individual']) {
            $queryBuilder->andWhere('bo.individual = :individual');
            $queryBuilder->setParameter('individual', $context['filters']['filters']['individual']);
        }
        if ($context['filters']['filters']['pathLevel'] && $context['filters']['filters']['pathLevel'] !== 'none') {
            switch ($context['filters']['filters']['pathLevel']){
                case PathLevelEnum::EXPERIMENT:
                    $queryBuilder->andWhere($queryBuilder->expr()->isNotNull('bo.experimentTarget'));
                    break;
                case PathLevelEnum::BLOCK:
                    $queryBuilder->andWhere($queryBuilder->expr()->isNotNull('bo.blockTarget'));
                    break;
                case PathLevelEnum::SUB_BLOCK:
                    $queryBuilder->andWhere($queryBuilder->expr()->isNotNull('bo.subBlockTarget'));
                    break;
                case PathLevelEnum::UNIT_PLOT:
                    $queryBuilder->andWhere($queryBuilder->expr()->isNotNull('bo.unitPlotTarget'));
                    break;
                case PathLevelEnum::SURFACIC_UNIT_PLOT:
                    $queryBuilder->andWhere($queryBuilder->expr()->isNotNull('bo.surfacicUnitPlotTarget'));
                    break;
                case PathLevelEnum::INDIVIDUAL:
                    $queryBuilder->andWhere($queryBuilder->expr()->isNotNull('bo.individualTarget'));
                    break;
            }
        }

        /*
        filters = {
    experiment: '',
    block: '',
    treatment: '',
    unitPlot: '',
    individual: '',
    x: '',
    y: '',
    pathLevel: PathLevelEnum.NONE
  }
         */

        $queryBuilder->setParameter('sessions', $sessions);

        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 DataViewBusinessObject::class === $resourceClass && $operationName === "get";
    }
}
