<?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\Sync\Neos\Domain\Filter\EventDateFilter;
use Newland\Toubiz\Sync\Neos\Domain\Filter\FilterInterface;
use Newland\Toubiz\Sync\Neos\Domain\Model\EventDate;
use Newland\Toubiz\Sync\Neos\Translation\TranslatableRepository;

/**
 * Event date repository.
 *
 * @Flow\Scope("singleton")
 *
 * @method EventDate|null findOneByOriginalId(string $originalId)
 */
class EventDateRepository extends AbstractRepository
{
    use TranslatableRepository {
        createQueryBuilder as private createTranslatableQueryBuilder;
    }

    /** @var string */
    protected $alias = 'eventDate';


    public function createQueryBuilder($alias, $indexBy = null, bool $withHidden = false): QueryBuilder
    {
        $query = $this->createTranslatableQueryBuilder($alias, $indexBy);

        if (!$withHidden) {
            $query->addFixedExpression(
                $query->expr()->eq(sprintf('%s.hidden', $alias), 'false')
            );
        }

        return $query;
    }


    /**
     * Deletes records from the past.
     *
     * @param \DateTime $olderThan
     * @return void
     */
    public function deletePastRecords(\DateTime $olderThan)
    {
        $query = $this->createQueryBuilder($this->getTableAlias(), null, true);
        $query->delete()
            ->andWhere('eventDate.endsAt < :ends_at')
            ->setParameter('ends_at', $olderThan);

        $query->getQuery()->execute();
    }

    /**
     * Applies filter functions (from the event date filter) onto
     * the given query builder.
     *
     * @param EventDateFilter $filter
     * @param QueryBuilder $query
     * @return QueryBuilder
     */
    protected function applyFilter(FilterInterface $filter, QueryBuilder $query): QueryBuilder
    {
        $this->applyBasicFilter($filter, $query);
        $query->innerJoin('eventDate.event', 'event');
        $eventTags = $filter->getEventTags();
        $categories = $filter->getCategories();
        $highlight = $filter->getHighlight();

        if (!empty($categories) || $highlight !== null) {
            $query->innerJoin('event.categories', 'categories');
        }

        if (!empty($eventTags)) {
            $query->innerJoin('event.eventTags', 'tags');
        }

        if (!empty($categories)) {
            $query->andWhere('categories.Persistence_Object_Identifier IN (:categories)')
                ->setParameter('categories', $categories);
        }

        if (!empty($eventTags)) {
            $query->andWhere('tags.Persistence_Object_Identifier IN (:tags)')
                ->setParameter('tags', $eventTags);
        }

        $fromDate = $filter->getFromDate();
        if ($fromDate !== null) {
            $query->andWhere('(eventDate.beginsAt >= :fromDate OR eventDate.beginsAt IS NULL)')
                ->setParameter('fromDate', $fromDate->format('Y-m-d H:i:s'));
        }

        $fromMaxDate = $filter->getFromMaxDate();
        if ($fromMaxDate !== null) {
            $query->andWhere('(DATE(eventDate.beginsAt) <= :fromMaxDate OR eventDate.beginsAt IS NULL)')
                ->setParameter('fromMaxDate', $fromMaxDate);
        }

        $toDate = $filter->getToDate();
        if ($toDate !== null) {
            $toDate->setTime(23, 59, 59);
            $query->andWhere('(eventDate.endsAt <= :date OR eventDate.endsAt IS NULL)')
                ->setParameter('date', $toDate->format('Y-m-d H:i:s'));
        }

        if ($highlight !== null) {
            $query->andWhere('event.isHighlight = :flag')
                ->setParameter('flag', $highlight);
        }

        $locationZips = $filter->getLocationZips();
        if (!empty($locationZips)) {
            $query->innerJoin('event.location', 'location');
            $query->andWhere($query->expr()->in('location.zip', $locationZips));
        }

        $scope = $filter->getScope();
        if (!empty($scope)) {
            $query->andWhere($query->expr()->in('event.scope', $scope));
        }

        return $query;
    }
}
