<?php declare(strict_types=1);

namespace Newland\Toubiz\Events\Neos\Tests\Unit\Filter\Items;

use Neos\Flow\Tests\FunctionalTestCase;
use Newland\Toubiz\Events\Neos\Filter\Items\Date;
use Newland\Toubiz\Sync\Neos\Domain\Model\Event;
use Newland\Toubiz\Sync\Neos\Domain\Model\EventDate;
use Newland\Toubiz\Sync\Neos\Domain\Repository\EventDateRepository;
use Newland\Toubiz\Sync\Neos\Domain\Repository\EventRepository;
use Newland\Toubiz\Sync\Neos\Tests\Factory\EventDateFactory;
use Newland\Toubiz\Sync\Neos\Tests\Factory\EventFactory;

class DateTest extends FunctionalTestCase
{
    protected static $testablePersistenceEnabled = true;

    /** @var Date */
    protected $subject;

    /** @var EventDateFactory */
    protected $eventDateFactory;

    /** @var EventFactory */
    protected $eventFactory;

    public function setUp(): void
    {
        parent::setUp();
        $this->eventDateFactory = new EventDateFactory($this->objectManager);
        $this->eventFactory = new EventFactory($this->objectManager);
        $this->subject = new Date();
        $this->subject->setDatabaseColumns([ 'from' => 'entity.beginsAt', 'to' => 'entity.endsAt' ]);
    }

    public function testFindsResultsOfSingleDay(): void
    {
        $events = $this->createEvents(new \DateTime('2019-12-12'));
        $idsBefore = array_map(
            function (EventDate $date) {
                return $date->getPersistenceObjectIdentifier();
            },
            $events
        );

        $this->subject->setState([ 'from' => '2019-12-12', 'to' => '2019-12-12' ]);
        $fromDb = $this->findEventDatesForCurrentSubject();
        $idsFromDb = array_map(
            function (EventDate $date) {
                return $date->getPersistenceObjectIdentifier();
            },
            $fromDb
        );

        $this->assertContains($idsBefore['today'], $idsFromDb);
        $this->assertNotContains($idsBefore['tomorrow'], $idsFromDb);
        $this->assertNotContains($idsBefore['yesterday'], $idsFromDb);
        $this->assertNotContains($idsBefore['dayAfterTomorrow'], $idsFromDb);
    }

    public function testFindsEventsInGivenRange(): void
    {
        $events = $this->createEvents(new \DateTime('2019-12-12'));
        $idsBefore = array_map(
            function (EventDate $date) {
                return $date->getPersistenceObjectIdentifier();
            },
            $events
        );

        $this->subject->setState([ 'from' => '2019-12-11', 'to' => '2019-12-13' ]);
        $fromDb = $this->findEventDatesForCurrentSubject();
        $idsFromDb = array_map(
            function (EventDate $date) {
                return $date->getPersistenceObjectIdentifier();
            },
            $fromDb
        );

        $this->assertContains($idsBefore['today'], $idsFromDb);
        $this->assertContains($idsBefore['tomorrow'], $idsFromDb);
        $this->assertContains($idsBefore['yesterday'], $idsFromDb);
        $this->assertNotContains($idsBefore['dayAfterTomorrow'], $idsFromDb);
    }

    private function findEventDatesForCurrentSubject()
    {
        $repo = $this->objectManager->get(EventDateRepository::class);
        $repo->setLanguage(null);
        $query = $repo->createQueryBuilder('entity');

        $expression = $this->subject->queryExpression($query->expr());
        if ($expression->where) {
            $query->andWhere($expression->where);
        }
        if ($expression->having) {
            $query->andHaving($expression->having);
        }

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

    /** @return EventDate[] */
    private function createEvents(\DateTime $today = null): array
    {
        $today = $today ?? new \DateTime();
        $events = [];

        $eventToday = $this->eventFactory->create([ 'title' => 'DATE_TOMORROW' ]);
        $events['today'] = $this->eventDateFactory->create(
            [ 'beginsAt' => $today, 'endsAt' => (clone $today)->add(new \DateInterval('PT1H')), 'event' => $eventToday ]
        );

        $tomorrow = (clone $today)->add(new \DateInterval('P1D'));
        $eventTomorrow = $this->eventFactory->create([ 'title' => 'DATE_TOMORROW' ]);
        $events['tomorrow'] = $this->eventDateFactory->create(
            [
                'beginsAt' => $tomorrow,
                'endsAt' => (clone $tomorrow)->add(new \DateInterval('PT1H')),
                'event' => $eventTomorrow,
            ]
        );

        $yesterday = (clone $today)->sub(new \DateInterval('P1D'));
        $eventYesterday = $this->eventFactory->create([ 'title' => 'DATE_YESTERDAY' ]);
        $events['yesterday'] = $this->eventDateFactory->create(
            [
                'beginsAt' => $yesterday,
                'endsAt' => (clone $yesterday)->add(new \DateInterval('PT1H')),
                'event' => $eventYesterday,
            ]
        );

        $dayAfterTomorrow = (clone $today)->add(new \DateInterval('P2D'));
        $eventDayAfterTomorrow = $this->eventFactory->create([ 'title' => 'DATE_DAY_AFTER_TOMORROW' ]);
        $events['dayAfterTomorrow'] = $this->eventDateFactory->create(
            [
                'beginsAt' => $dayAfterTomorrow,
                'endsAt' => (clone $dayAfterTomorrow)->add(new \DateInterval('PT1H')),
                'event' => $eventDayAfterTomorrow,
            ]
        );

        return $events;
    }

}
