<?php
namespace Newland\Toubiz\Events\Neos\Filter\Items;

/*
 * This file is part of the "toubiz-evets-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\Query\Expr;
use Neos\Flow\Annotations as Flow;
use Neos\Flow\I18n\Translator;
use Neos\Flow\Mvc\View\ViewInterface;
use Newland\Contracts\Neos\Filter\Expression;
use Newland\Contracts\Neos\Filter\FilterItem;
use Newland\Contracts\Neos\Filter\QueryBoundFilterItem;
use Newland\Contracts\Neos\Filter\StatusIndicatingFilterItem;
use Newland\NeosFiltering\StatusIndicator\StatusIndicator;
use Newland\NeosFiltering\Traits\FilterItemCommon;
use Newland\NeosFiltering\Traits\HasInvisibleState;
use Newland\NeosFiltering\Traits\HasQueryString;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;

class Date implements
    FilterItem,
    QueryBoundFilterItem,
    StatusIndicatingFilterItem
{
    use FilterItemCommon,
        HasQueryString,
        HasInvisibleState;

    /** @var string */
    protected $databaseColumnFrom;

    /** @var string */
    protected $databaseColumnTo;

    /** @var string */
    protected $queryStringFrom;

    /** @var string */
    protected $queryStringTo;

    /**
     * @var Translator
     * @Flow\Inject()
     */
    protected $translator;

    /**
     * Returns a database expression that mirrors the item state.
     * This expression is applied to a database query in order to get the filtered results.
     *
     * Note: The entity that is being filtered for is always aliased as `entity`.
     *
     * @param Expr $expr
     * @return Expression An expression built by the given expression builder.
     */
    public function queryExpression(Expr $expr): Expression
    {
        $expressions = [];

        if (!empty($this->state['from'])) {
            $from = (new \DateTime($this->state['from']))->setTime(0, 0, 0);
            $expressions[] = $expr->orX(
                $expr->gte($this->databaseColumnFrom, $expr->literal($from->format('Y-m-d H:i:s'))),
                $expr->isNull($this->databaseColumnFrom)
            );
        }

        if (!empty($this->state['to'])) {
            $to = (new \DateTime($this->state['to']))->setTime(23, 59, 59);
            $expressions[] = $expr->orX(
                $expr->lte($this->databaseColumnTo, $expr->literal($to->format('Y-m-d H:i:s'))),
                $expr->isNull($this->databaseColumnTo)
            );
        }

        if (!empty($this->state['from']) || !empty($this->state['to'])) {
            $expressions[] = $expr->eq('entity.active', true);
        }

        if (\count($expressions) === 0) {
            return Expression::empty();
        }
        if (\count($expressions) === 1) {
            return Expression::where($expressions[0]);
        }
        return Expression::where($expr->andX(...$expressions));
    }

    public function render(RenderingContextInterface $renderingContext)
    {
        $view = $this->initializeView(
            [ 'resource://Newland.Toubiz.Events.Neos/Private/Templates/Filter/Items' ],
            [],
            [ 'resource://Newland.Toubiz.Events.Neos/Private/Partials/Filter/Items' ]
        );

        $view->assignMultiple(
            [
                'stateValues' => $this->state,
            ]
        );
        $this->assignDatePickerProperties($view);

        return $view->render('Date');
    }

    private function assignDatePickerProperties(ViewInterface $view): void
    {
        $today = (new \DateTime())->format('Y-m-d');
        $tomorrow = (new \DateTime())->modify('+1 day')->format('Y-m-d');
        $datePickerMinDate = (new \DateTime())->format('m/d/Y');
        $datePickerIsActive = false;
        if (!empty($this->state['from']) && !empty($this->state['to'])) {
            $datePickerIsActive = true;
        }

        $view->assignMultiple(
            [
                'today' => $today,
                'tomorrow' => $tomorrow,
                'datePickerMinDate' => $datePickerMinDate,
                'datePickerIsActive' => $datePickerIsActive,
                'initialDatepickerState' => json_encode(
                    [
                        'start' => $datePickerIsActive ? ($this->state['from'] ?? null) : null,
                        'end' => $datePickerIsActive ? ($this->state['to'] ?? null) : null,
                    ]
                ),
            ]
        );
    }

    public function setDatabaseColumns(array $databaseColumns): void
    {
        $this->databaseColumnFrom = $databaseColumns['from'];
        $this->databaseColumnTo = $databaseColumns['to'];
    }

    protected function throwIfNoDatabaseColumnDeclared(): void
    {
        if ($this->databaseColumnFrom === null) {
            throw new \Exception(
                'No databaseColumnFrom specified'
            );
        }
        if ($this->databaseColumnTo === null) {
            throw new \Exception(
                'No databaseColumnTo specified'
            );
        }
    }

    private function getStatusLabel(string $from, string $to): string
    {
        $today = (new \DateTime())->format('Y-m-d');
        if ($from === $today && $to === $today) {
            return $this->translator
                ->translateById('group.date.today', [], null, null, 'Views/Filter', 'Newland.Toubiz.Events.Neos');
        }

        $tomorrow = (new \DateTime())->modify('+1 day')->format('Y-m-d');
        if ($from === $tomorrow && $to === $tomorrow) {
            return $this->translator
                ->translateById('group.date.tomorrow', [], null, null, 'Views/Filter', 'Newland.Toubiz.Events.Neos');
        }

        $fromDate = new \DateTime($from);
        $toDate = new \DateTime($to);

        return sprintf(
            '%s - %s',
            $fromDate->format('d.m.Y'),
            $toDate->format('d.m.Y')
        );
    }


    /** @return StatusIndicator[] */
    public function getStatusIndicators(): array
    {
        // Do not show StatusIndicator for showTodaySeparately filter
        $showTodaySeparately = $this->root->getPluginNode()->getNodeData()
                ->getProperties()['showTodaySeparately'] ?? null;
        $tomorrow = (new \DateTime())->modify('+1 day')->format('Y-m-d');
        if ($showTodaySeparately && $this->state['from'] === $tomorrow && empty($this->state['to'])) {
            return [];
        }

        if (empty($this->state['from']) && empty($this->state['to'])) {
            return [];
        }

        $title = $this->getStatusLabel($this->state['from'] ?? '', $this->state['to'] ?? '');
        $indicator = new StatusIndicator();
        $indicator->setId($this->getId());
        $indicator->setTitle($title);

        return [ $indicator ];
    }
}
