<?php declare(strict_types=1);

namespace Newland\Toubiz\Events\Neos;

use Doctrine\ORM\QueryBuilder;
use Neos\ContentRepository\Domain\Model\NodeInterface;
use Neos\Fusion\Core\Cache\ContentCache;
use Newland\Contracts\Neos\Filter\FilterRoot;
use Newland\Toubiz\Events\Neos\Filter\EventDateFilterFactory;
use Newland\Toubiz\Events\Neos\Filter\Items\EventDateRoot;
use Newland\Toubiz\Sync\Neos\Configuration\ConfigurationAction;
use Newland\Toubiz\Sync\Neos\Configuration\ConfigurationProvider as ConfigurationProviderInterface;
use Newland\Toubiz\Sync\Neos\Domain\Model\Event;
use Newland\Toubiz\Sync\Neos\Domain\Model\EventDate;
use Neos\Flow\Annotations as Flow;
use Newland\Toubiz\Sync\Neos\Domain\Repository\EventRepository;

class ConfigurationProvider implements ConfigurationProviderInterface
{

    /** @var string */
    private $type;

    /**
     * @var array
     * @Flow\InjectConfiguration(path="filter")
     */
    protected $filterSettings;

    /**
     * @var EventRepository
     * @Flow\Inject()
     */
    protected $eventRepository;

    /**
     * @var ContentCache
     * @Flow\Inject()
     */
    protected $contentCache;

    /** @return string[] */
    public function types(): array
    {
        return [ 'event' ];
    }

    public function setType(string $type): void
    {
        $this->type = $type;
    }

    public function filter(NodeInterface $node): FilterRoot
    {
        return (new EventDateFilterFactory($node))->createEventFilter($this->filterSettings);
    }

    /** @param EventDateRoot $filter */
    public function count(FilterRoot $filter): int
    {
        return (int) $this->eventQuery($filter, false)
            ->select('COUNT(wrappingEvent.Persistence_Object_Identifier) AS count')
            ->getQuery()
            ->execute()[0]['count'];
    }

    /** @param EventDateRoot $filter */
    public function fetch(FilterRoot $filter): array
    {
        return $this->eventQuery($filter, true)->getQuery()->execute();
    }

    protected function getFormattedDateRange(Event $event): string
    {
        if ($event->getBeginsAt() === null || $event->getEndsAt() === null) {
            return '';
        }

        return sprintf(
            '%s - %s',
            $event->getBeginsAt()->format('Y-m-d H:i'),
            $event->getEndsAt()->format('Y-m-d H:i')
        );
    }

    private function eventQuery(EventDateRoot $filter, bool $withPagination): QueryBuilder
    {
        $subQuery = $filter->getEventQuery([], true)
            ->select('entity.Persistence_Object_Identifier');

        $query = $this->eventRepository->createQueryBuilder('wrappingEvent', null, true);
        $query->join('wrappingEvent.eventDates', 'eventDate');
        $query->where(
            $query->expr()->in(
                'eventDate.Persistence_Object_Identifier',
                $subQuery->getDQL()
            )
        );
        $query->setParameters($subQuery->getParameters());
        $query->distinct(true);
        $query->orderBy('wrappingEvent.beginsAt', 'ASC');

        $pagination = $filter->getPagination();
        if ($withPagination && $pagination) {
            $pagination->modifyDatabaseQuery($query);
        }

        return $query;
    }

    /**
     * Converts the given fetched item to table items: An array of primitive values displayed in the table.
     *
     * @param Event $item
     */
    public function tableItems($item): array
    {
        $dates = $item->getEventDates()->map(
            function (EventDate $date) {
                if ($date->getBeginsAt() === null || $date->getEndsAt() === null) {
                    return '';
                }

                return sprintf(
                    '%s - %s',
                    $date->getBeginsAt()->format('Y-m-d H:i'),
                    $date->getEndsAt()->format('Y-m-d H:i')
                );
            }
        )->toArray();

        $titleAttribute = implode("\n", $dates);

        $datesHtml = sprintf(
            '<span title="%s">%s</span>',
            $titleAttribute,
            $this->getFormattedDateRange($item)
        );

        return [
            $item->getOriginalId(),
            $item->getUrlIdentifier(),
            $item->getTitle(),
            $datesHtml,
        ];
    }

    /**
     * @param Event $item
     * @return ConfigurationAction[]
     */
    public function actions($item): array
    {
        return [
            'hide' => new ConfigurationAction(
                $item->isHidden() ? 'anzeigen' : 'verbergen',
                $item->isHidden() ? 'fas fa-eye-slash' : 'fas fa-eye',
                $item->isHidden() ? 'red' : 'green',
                function (array $configuration) {
                    $configuration['hidden'] = !($configuration['hidden'] ?? false);
                    $this->contentCache->flushByTag('event');
                    return $configuration;
                }
            ),
        ];
    }
}
