<?php declare(strict_types=1);

namespace App\Engine\UpcomingEvent;

final readonly class UpcomingEventProvider
{

    public const CACHE_TTL = 3600;
    public const HOMEPAGE_CACHE_KEY = "UpcomingEventsForHomepage";
    public const LIST_CACHE_KEY = "UpcomingEventsForList";
    public const TRAINING_LIST_CACHE_KEY = "UpcomingEventsForTrainingList";
    public const ARCHIVE_CACHE_KEY = "UpcomingEventsForArchive";

    public function __construct(
        private \App\Engine\UpcomingEvent\UpcomingEventRepository $upcomingEventRepository,
        private \Symfony\Contracts\Cache\CacheInterface           $fileAdapterCache,
    ) {
    }

    /**
     * @return array<\App\Engine\Inertia\Frontend\ViewModels\UpcomingEventTileViewModel>
     */
    public function provideForHomepageCached(): array
    {
        return $this->fileAdapterCache->get(self::HOMEPAGE_CACHE_KEY, function (\Symfony\Component\Cache\CacheItem $item) {
            $item->expiresAfter(self::CACHE_TTL);
            return $this->provideForHomepage();
        });
    }

    /**
     * @return array<\App\Engine\Inertia\Frontend\ViewModels\UpcomingEventTileViewModel>
     */
    public function provideForHomepage(): array
    {
        $cb = $this->upcomingEventRepository->createQueryBuilder($alias = "ue");
        $loadedResults = $cb->where(VisibleRecordsFilters::create($cb->expr(), $alias)->visibleForHomepage())
            ->setParameter("dateTime", $this->createDatetime())
            ->getQuery()
            ->getResult();

        $results = [];
        foreach ($loadedResults as $loadedResult) {
            $results[] = $this->createTileViewModel(upcomingEvent: $loadedResult);
        }

        return $results;
    }

    /**
     * @return array<\App\Engine\Inertia\Frontend\ViewModels\UpcomingEventRowViewModel>
     */
    public function provideForEventsListCached(): array
    {
        return $this->fileAdapterCache->get(self::LIST_CACHE_KEY, function (\Symfony\Component\Cache\CacheItem $item) {
            $item->expiresAfter(self::CACHE_TTL);
            return $this->provideForEventsList();
        });
    }

    /**
     * @return array<\App\Engine\Inertia\Frontend\ViewModels\UpcomingEventRowViewModel>
     */
    public function provideForEventsList(): array
    {
        $cb = $this->upcomingEventRepository->createQueryBuilder($alias = "ue");
        $loadedResults = $cb->where(VisibleRecordsFilters::create($cb->expr(), $alias)->visibleForList())
            ->setParameter("dateTime", $this->createDatetime())
            ->getQuery()
            ->getResult();

        $results = [];
        foreach ($loadedResults as $loadedResult) {
            $results[] = $this->createRowViewModel(upcomingEvent: $loadedResult);
        }

        return $results;
    }

    /**
     * @return array<\App\Engine\Inertia\Frontend\ViewModels\UpcomingEventTileViewModel>
     */
    public function provideForEventsTrainingList(): array
    {
        $cb = $this->upcomingEventRepository->createQueryBuilder($alias = "ue");
        $loadedResults = $cb->where(VisibleRecordsFilters::create($cb->expr(), $alias)->visibleForTrainingList())
            ->setParameter("dateTime", $this->createDatetime())
            ->getQuery()
            ->getResult();

        $results = [];
        foreach ($loadedResults as $loadedResult) {
            $results[] = $this->createTileViewModel(upcomingEvent: $loadedResult);
        }

        return $results;
    }

    /**
     * @return array<\App\Engine\Inertia\Frontend\ViewModels\UpcomingEventTileViewModel>
     */
    public function provideForEventsTrainingListCached(): array
    {
        return $this->fileAdapterCache->get(self::TRAINING_LIST_CACHE_KEY, function (\Symfony\Component\Cache\CacheItem $item) {
            $item->expiresAfter(self::CACHE_TTL);
            return $this->provideForEventsTrainingList();
        });
    }

    /**
     * @return array<\App\Engine\Inertia\Frontend\ViewModels\UpcomingEventRowViewModel>
     */
    public function provideForEventsArchiveCached(): array
    {
        return $this->fileAdapterCache->get(self::ARCHIVE_CACHE_KEY, function (\Symfony\Component\Cache\CacheItem $item) {
            $item->expiresAfter(self::CACHE_TTL);
            return $this->provideForEventsArchive();
        });
    }

    /**
     * @return array<\App\Engine\Inertia\Frontend\ViewModels\UpcomingEventRowViewModel>
     */
    public function provideForEventsArchive(): array
    {
        $cb = $this->upcomingEventRepository->createQueryBuilder($alias = "ue");
        $loadedResults = $cb->where(VisibleRecordsFilters::create($cb->expr(), $alias)->visibleForArchive())
            ->setParameter("dateTime", $this->createDatetime())
            ->getQuery()
            ->getResult();

        $results = [];
        foreach ($loadedResults as $loadedResult) {
            $results[] = $this->createRowViewModel(upcomingEvent: $loadedResult);
        }

        return $results;
    }

    private function createDatetime(): \DateTimeImmutable
    {
        return new \DateTimeImmutable();
    }

    private function createTileViewModel(\App\Engine\UpcomingEvent\UpcomingEvent $upcomingEvent): \App\Engine\Inertia\Frontend\ViewModels\UpcomingEventTileViewModel
    {
        return new \App\Engine\Inertia\Frontend\ViewModels\UpcomingEventTileViewModel(
            title: $upcomingEvent->getTitle(),
            coverImagePictureTag: \App\Engine\Thumbnail\Thumbnail::create()
                ->fromRelativePath($upcomingEvent->getCoverImage())
                ->alt($upcomingEvent->getTitle())
                ->sizeOperation(\App\Engine\Thumbnail\SizeOperation::COVER)
                ->width(1185)
                ->height(660)
                ->getPictureHtmlTag(),
            summary: htmlspecialchars($upcomingEvent->getSummary()),
            link: $upcomingEvent->getUrl(),
        );
    }

    private function createRowViewModel(\App\Engine\UpcomingEvent\UpcomingEvent $upcomingEvent): \App\Engine\Inertia\Frontend\ViewModels\UpcomingEventRowViewModel
    {
        return new \App\Engine\Inertia\Frontend\ViewModels\UpcomingEventRowViewModel(
            title: $upcomingEvent->getTitle(),
            rowSummary: htmlspecialchars($upcomingEvent->getRowSummary()),
            link: $upcomingEvent->isWithDetail() ? $upcomingEvent->getUrl() : null,
        );
    }

}