<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CmsBundle\Controller\ContentElement;

use Contao\BackendTemplate;
use Contao\ContentModel;
use Contao\CoreBundle\Controller\ContentElement\AbstractContentElementController;
use Contao\CoreBundle\DependencyInjection\Attribute\AsContentElement;
use Contao\CoreBundle\Twig\FragmentTemplate;
use Contao\StringUtil;
use Doctrine\ORM\QueryBuilder;
use Ferienpass\CmsBundle\Controller\Fragment\OfferListController;
use Ferienpass\CoreBundle\Entity\Offer\OfferInterface;
use Ferienpass\CoreBundle\HttpCache\CacheTag;
use Ferienpass\CoreBundle\Repository\OfferRepositoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\Translation\TranslatorInterface;

/**
 * Renders a small, teaser-style grid of published offers ("Beliebte Angebote")
 * for landing pages. Unlike the full {@see Offers} list, it shows only a handful
 * of cards (configurable via "numberOfItems", default 3) in a compact preview
 * layout and links through to the complete offer list.
 */
#[AsContentElement(type: 'highlighted_offers', category: 'includes', priority: 9)]
class HighlightedOffers extends AbstractContentElementController
{
    public function __construct(private readonly OfferRepositoryInterface $offers)
    {
    }

    public static function getSubscribedServices(): array
    {
        $services = parent::getSubscribedServices();

        $services['translator'] = TranslatorInterface::class;

        return $services;
    }

    protected function getResponse(FragmentTemplate $template, ContentModel $model, Request $request): Response
    {
        if ($this->container->get('contao.routing.scope_matcher')->isBackendRequest($request)) {
            $template = new BackendTemplate('be_wildcard');

            $template->title = $this->container->get('translator')->trans('CTE.'.$this->getType().'.0', [], 'contao_modules');
            $template->wildcard = $this->container->get('translator')->trans('CTE.'.$this->getType().'.1', [], 'contao_modules');

            return new Response($template->parse());
        }

        /** @var QueryBuilder $qb */
        $qb = $this->offers->createQueryBuilder('o');

        OfferListController::prepareQueryBuilder($qb);

        $items = $qb->getQuery()->getResult();

        $limit = (int) ($model->numberOfItems ?: 3);
        if ($limit > 0) {
            $items = \array_slice($items, 0, $limit);
        }

        // Per-offer tags + the collection tag of every edition represented in
        // the rendered teaser, so a status/publish change on an offer in any
        // shown edition purges this preview (the per-offer xkey can't, as the
        // newly-eligible offer wasn't on the page when it was cached). See the
        // fuller note in {@see Offers}.
        $tags = array_map(static fn (OfferInterface $offer) => CacheTag::offer($offer), $items);
        foreach ($items as $offer) {
            $tags[] = CacheTag::offerCollection($offer->getEdition());
        }
        $this->tagResponse(array_values(array_unique($tags)));

        $headline = StringUtil::deserialize($model->headline, true);

        return $this->render('@Contao/content_element/highlighted_offers.html.twig', [
            'items' => $items,
            'text' => $model->text,
            'headline' => \is_array($headline) ? $headline['value'] : $headline,
        ]);
    }
}
