<?php
namespace Newland\Toubiz\Sync\Neos\Domain\Repository;

/*
 * This file is part of the "toubiz-sync-neos" package.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 */

use Doctrine\ORM\QueryBuilder;
use Neos\Flow\Annotations as Flow;
use Newland\Toubiz\Api\ObjectAdapter\Concern\SlopeConstants;
use Newland\Toubiz\Sync\Neos\Command\OrphanFinder;
use Newland\Toubiz\Sync\Neos\Domain\Filter\FilterInterface;
use Newland\Toubiz\Sync\Neos\Domain\Filter\SlopeFilter;
use Newland\Toubiz\Sync\Neos\Domain\Model\Region;
use Newland\Toubiz\Sync\Neos\Domain\Model\Slope;

/**
 * Slope repository.
 *
 * @Flow\Scope("singleton")
 *
 * @method Slope|null findOneByOriginalId(string $originalId)
 */
class SlopeRepository extends AbstractRepository implements OrphanFinder
{
    /**
     * Calculates statistics.
     *
     * @param Region[] $regions
     * @return array
     */
    public function getStatistics(array $regions = [])
    {
        $query = $this->createQueryBuilder('slope');
        $query->leftJoin('slope.regions', 'region');

        $constraint = '';
        if (!empty($regions)) {
            $regionIds = [];
            foreach ($regions as $region) {
                $regionIds[] = $region->getPersistenceObjectIdentifier();
            }
            $query->setParameter('regionIds', $regionIds);
            $constraint = 'AND region IN(:regionIds)';
        }

        $query->select('
            SUM (
                CASE WHEN
                    slope.status = ' . SlopeConstants::STATUS_OPEN . '
                    AND slope.type = ' . SlopeConstants::TYPE_SKI . '
                    ' . $constraint . '
                THEN 1 ELSE 0 END
            ) AS ski_open,
            SUM (
                CASE WHEN
                    slope.type = ' . SlopeConstants::TYPE_SKI . '
                    ' . $constraint . '
                THEN 1 ELSE 0 END
            ) AS ski_total,

            SUM (
                CASE WHEN
                    slope.status = ' . SlopeConstants::STATUS_OPEN . '
                    AND slope.type = ' . SlopeConstants::TYPE_HIKING_TRAIL . '
                    ' . $constraint . '
                THEN 1 ELSE 0 END
            ) AS hike_open,
            SUM (
                CASE WHEN
                    slope.type = ' . SlopeConstants::TYPE_HIKING_TRAIL . '
                    ' . $constraint . '
                THEN 1 ELSE 0 END
            ) AS hike_total,

            SUM (
                CASE WHEN
                    slope.type IN(
                        ' . SlopeConstants::TYPE_CROSS_COUNTRY_SKIING . ',
                        ' . SlopeConstants::TYPE_CROSS_COUNTRY_SKIING_SKATING . '
                    )
                    AND slope.status = ' . SlopeConstants::STATUS_OPEN . '
                    ' . $constraint . '
                THEN 1 ELSE 0 END
            ) AS cross_country_skiing_open,
            SUM (
                CASE WHEN
                    slope.type IN(
                        ' . SlopeConstants::TYPE_CROSS_COUNTRY_SKIING . ',
                        ' . SlopeConstants::TYPE_CROSS_COUNTRY_SKIING_SKATING . '
                    )
                    ' . $constraint . '
                THEN 1 ELSE 0 END
            ) AS cross_country_skiing_total
        ');
        return $query->getQuery()->execute()[0];
    }

    /**
     * @return iterable
     */
    public function findOrphans()
    {
        $query = $this->createQueryBuilder('slope');

        return $query->join('slope.regions', 'regions')
            ->where($query->expr()->isNull('regions.Persistence_Object_Identifier'))
            ->getQuery()
            ->execute();
    }

    /**
     * @param SlopeFilter $filter
     * @param QueryBuilder $query
     * @return QueryBuilder
     */
    protected function applyFilter(FilterInterface $filter, QueryBuilder $query): QueryBuilder
    {
        $this->applyBasicFilter($filter, $query);

        $regions = $filter->getRegions();
        if (!empty($regions)) {
            $query->leftJoin('slope.regions', 'region');
            $query->andWhere($query->expr()->in('region', $regions));
        }

        $types = $filter->getTypes();
        if (!empty($types)) {
            $query->andWhere($query->expr()->in('slope.type', $types));
        }

        return $query;
    }
}
