<?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\AdminBundle\Controller\Page;

use Doctrine\ORM\EntityManagerInterface;
use Ferienpass\AdminBundle\Breadcrumb\Breadcrumb;
use Ferienpass\CoreBundle\Entity\AttendanceStash;
use Ferienpass\CoreBundle\Message\CommitAttendances as CommitAttendancesMessage;
use Ferienpass\CoreBundle\Messenger\UuidStamp;
use Ferienpass\CoreBundle\Repository\AttendanceStashRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\MapQueryParameter;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use Symfony\Component\Uid\Uuid;
use Symfony\UX\Turbo\TurboBundle;

#[IsGranted('ROLE_ADMIN')]
final class CommitAttendancesController extends AbstractController
{
    #[Route('/anmeldungen-festschreiben', name: 'admin_commit_attendances')]
    public function index(Breadcrumb $breadcrumb): Response
    {
        return $this->render('@FerienpassAdmin/page/attendances/commit.html.twig', [
            'breadcrumb' => $breadcrumb->generate('tools.title', 'commitAttendances.title'),
        ]);
    }

    #[Route('/anmeldungen-festschreiben/verschieben', name: 'admin_stash_move')]
    public function moveToStash(#[MapQueryParameter('ids')] array $ids): Response
    {
        return $this->render('@FerienpassAdmin/page/attendances/move_to_stash.html.twig', [
            'ids' => $ids,
        ]);
    }

    // NB: cache invalidation is NOT done here via #[InvalidatePath]. The commit
    // is asynchronous (CommitAttendancesMessage) and mutates attendances with
    // bulk DQL UPDATEs that bypass Doctrine events — so neither this controller
    // (which fires before the worker runs) nor the CacheInvalidationListener
    // (which never sees the bulk update) can invalidate the affected pages.
    // The worker invalidates instead, scoped to the host captured below.
    #[Route('/anmeldungen-festschreiben/bestaetigen', name: 'admin_commit_attendances_confirm')]
    public function confirm(#[MapQueryParameter] int $stash, #[MapQueryParameter] bool $notify, EntityManagerInterface $entityManager, MessageBusInterface $commandBus, AttendanceStashRepository $stashRepository, Request $request): Response
    {
        $stashEntity = $stashRepository->find($stash);
        if (!$stashEntity instanceof AttendanceStash) {
            throw $this->createNotFoundException('Stapel nicht gefunden');
        }

        if ($request->isMethod('POST')) {
            $uuid = Uuid::v7();

            // Captured here (request context) so the worker can BAN this
            // tenant's cached pages — the CLI worker has no request host.
            $host = $request->getHttpHost();

            $byEdition = [];
            foreach ($stashEntity->getAttendances() as $attendance) {
                $byEdition[(string) $attendance->getOffer()->getEdition()->getUuid()][] = (string) $attendance->getUuid();
            }

            foreach ($byEdition as $editionId => $ids) {
                $commandBus->dispatch(
                    new Envelope(new CommitAttendancesMessage($editionId, $ids, $notify, $host))->with(new UuidStamp($uuid))
                );
            }

            $entityManager->remove($stashEntity);
            $entityManager->flush();

            if (TurboBundle::STREAM_FORMAT === $request->getPreferredFormat()) {
                $request->setRequestFormat(TurboBundle::STREAM_FORMAT);

                return $this->renderBlock('@FerienpassAdmin/page/attendances/confirm_commit.html.twig', 'success_stream', [
                    'uuid' => $uuid->toBase58(),
                    'notify' => $notify,
                ]);
            }

            return $this->redirectToRoute('admin_commit_attendances');
        }

        return $this->render('@FerienpassAdmin/page/attendances/confirm_commit.html.twig', [
            'stash' => $stashEntity,
            'notify' => $notify,
        ]);
    }
}
