<?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\Menu;

use Ferienpass\CoreBundle\Dto\ParticipantDuplicateDto;
use Ferienpass\CoreBundle\Entity\AccessCodeStrategy;
use Ferienpass\CoreBundle\Entity\Attendance;
use Ferienpass\CoreBundle\Entity\Consent;
use Ferienpass\CoreBundle\Entity\Debtor;
use Ferienpass\CoreBundle\Entity\Edition;
use Ferienpass\CoreBundle\Entity\Host;
use Ferienpass\CoreBundle\Entity\Offer\OfferInterface;
use Ferienpass\CoreBundle\Entity\Participant\ParticipantInterface;
use Ferienpass\CoreBundle\Entity\Payment;
use Ferienpass\CoreBundle\Entity\User;
use Knp\Menu\FactoryInterface;
use Knp\Menu\ItemInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Workflow\WorkflowInterface;

class ActionsBuilder
{
    public function __construct(
        private readonly FactoryInterface $factory,
        private readonly AuthorizationCheckerInterface $authorizationChecker,
        private readonly WorkflowInterface $offerWorkflow,
        private readonly RequestStack $requestStack,
    ) {
    }

    public function actions(array $options = []): ItemInterface
    {
        $item = $options['item'] ?? null;
        if (null === $item) {
            throw new \InvalidArgumentException('The list item is not available');
        }

        $route = $this->requestStack->getMainRequest()?->attributes->get('_route');
        $view = $options['view'] ?? $route;

        $menu = $this->factory->createItem('root');

        if ($item instanceof OfferInterface) {
            $this->offers($menu, $item, $view);

            return $menu;
        }

        if ($item instanceof ParticipantInterface) {
            $this->participants($menu, $item, $view);

            return $menu;
        }

        if ($item instanceof ParticipantDuplicateDto) {
            $this->duplicates($menu, $item, $view);

            return $menu;
        }
        if ($item instanceof Debtor) {
            $this->debtors($menu, $item, $view);

            return $menu;
        }

        if ($item instanceof Host) {
            $this->hosts($menu, $item, $view);

            return $menu;
        }
        if ($item instanceof Consent) {
            $this->consents($menu, $item, $view);

            return $menu;
        }

        if ($item instanceof Edition) {
            $this->editions($menu, $item, $view);

            return $menu;
        }
        if ($item instanceof AccessCodeStrategy) {
            $this->accessCodes($menu, $item, $view);

            return $menu;
        }

        if ($item instanceof Attendance) {
            $this->attendances($menu, $item, $view, $options);

            return $menu;
        }

        if ($item instanceof Payment) {
            $this->payments($menu, $item, $view);

            return $menu;
        }

        if ($item instanceof User) {
            $this->accounts($menu, $item, $view);

            return $menu;
        }

        return $menu;
    }

    public function offerTertiary(OfferInterface $item): ItemInterface
    {
        $request = $this->requestStack->getMainRequest();
        $route = $request?->attributes->get('_route');

        $menu = $this->factory->createItem('root');

        if (!$item->getId()) {
            return $menu;
        }

        $menu->addChild('show', [
            'label' => 'offers.action.show',
            'route' => 'admin_offers_show',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'current' => 'admin_offers_show' === $route,
        ]);

        $menu->addChild('edit', [
            'label' => 'offers.action.edit',
            'route' => 'admin_offers_edit',
            'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
            'display' => $this->isGranted('edit', $item),
            'current' => 'admin_offers_edit' === $route,
        ]);

        $menu->addChild('proof', [
            'label' => 'offers.action.proof',
            'route' => 'admin_offers_proof',
            'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
            'display' => $this->isGranted('view', $item),
            'current' => 'admin_offers_proof' === $route,
        ]);

        if ($item->isOnlineApplication()) {
            $menu->addChild('participantList', [
                'label' => 'offers.action.participants',
                'route' => 'admin_offers_participants',
                'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
                'display' => $this->isGranted('participants.view', $item),
                'current' => 'admin_offers_participants' === $route,
            ]);

            $menu->addChild('participantAssigning', [
                'label' => 'offers.action.assign',
                'route' => 'admin_offer_assign',
                'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
                'display' => $this->isGranted('participants.view', $item) && ($item->getEdition()->hostsCanAssign() || $this->isGranted('ROLE_ADMIN')),
                'current' => 'admin_offer_assign' === $route,
            ]);
        }

        return $menu;
    }

    public function editionTertiary(Edition $item): ItemInterface
    {
        $request = $this->requestStack->getMainRequest();
        $route = $request?->attributes->get('_route');

        $menu = $this->factory->createItem('root');

        if (null === $item->getAlias() || '' === $item->getAlias()) {
            return $menu;
        }

        $menu->addChild('show', [
            'label' => 'editions.action.show',
            'route' => 'admin_editions_show',
            'routeParameters' => ['alias' => $item->getAlias()],
            'current' => 'admin_editions_show' === $route,
        ]);

        $menu->addChild('edit', [
            'label' => 'editions.action.edit',
            'route' => 'admin_editions_edit',
            'routeParameters' => ['alias' => $item->getAlias()],
            'display' => $this->isGranted('edit', $item),
            'current' => 'admin_editions_edit' === $route,
        ]);

        $menu->addChild('proofs', [
            'label' => 'editions.action.proofs',
            'route' => 'admin_offers_review',
            'routeParameters' => ['alias' => $item->getAlias()],
            'display' => $this->isGranted('stats', $item),
            'current' => 'admin_offers_review' === $route,
        ]);

        $menu->addChild('assign', [
            'label' => 'editions.action.assign',
            'route' => 'admin_editions_assign',
            'routeParameters' => ['alias' => $item->getAlias()],
            'display' => $this->isGranted('assign', $item),
            'current' => \in_array($route, ['admin_editions_assign', 'admin_editions_lotting'], true),
        ]);

        $menu->addChild('notifications', [
            'label' => 'editions.action.notifications',
            'route' => 'admin_editions_notifications',
            'routeParameters' => ['alias' => $item->getAlias()],
            'display' => $this->isGranted('ROLE_ADMIN', $item),
            'current' => 'admin_editions_notifications' === $route,
        ]);

        $menu->addChild('mailing', [
            'label' => 'editions.action.mailing',
            'route' => 'admin_editions_mailing',
            'routeParameters' => ['alias' => $item->getAlias()],
            'display' => $this->isGranted('mailing', $item),
            'current' => 'admin_editions_mailing' === $route,
        ]);

        $menu->addChild('export', [
            'label' => 'editions.action.export',
            'route' => 'admin_editions_export',
            'routeParameters' => ['alias' => $item->getAlias()],
            'display' => $this->isGranted('export', $item),
            'current' => 'admin_editions_export' === $route,
        ]);

        $menu->addChild('stats', [
            'label' => 'editions.action.stats',
            'route' => 'admin_editions_stats',
            'routeParameters' => ['alias' => $item->getAlias()],
            'display' => $this->isGranted('stats', $item),
            'current' => 'admin_editions_stats' === $route,
        ]);

        return $menu;
    }

    public function hostTertiary(Host $item): ItemInterface
    {
        $request = $this->requestStack->getMainRequest();
        $route = $request?->attributes->get('_route');

        $menu = $this->factory->createItem('root');

        $menu->addChild('show', [
            'label' => 'hosts.action.show',
            'route' => 'admin_hosts_show',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'current' => 'admin_hosts_show' === $route,
        ]);

        $menu->addChild('edit', [
            'label' => 'hosts.action.edit',
            'route' => 'admin_hosts_edit',
            'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
            'display' => $this->isGranted('edit', $item),
            'current' => 'admin_hosts_edit' === $route,
        ]);

        return $menu;
    }

    public function accountTertiary(User $item): ItemInterface
    {
        $request = $this->requestStack->getMainRequest();
        $route = $request?->attributes->get('_route');

        $menu = $this->factory->createItem('root');

        $menu->addChild('show', [
            'label' => 'accounts.action.show',
            'route' => 'admin_accounts_show',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'current' => 'admin_accounts_show' === $route,
        ]);

        $menu->addChild('edit', [
            'label' => 'accounts.action.edit',
            'route' => 'admin_accounts_edit',
            'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
            'display' => $this->isGranted('edit', $item),
            'current' => 'admin_accounts_edit' === $route,
        ]);

        return $menu;
    }

    public function participantTertiary(ParticipantInterface $item): ItemInterface
    {
        $request = $this->requestStack->getMainRequest();
        $route = $request?->attributes->get('_route');

        $menu = $this->factory->createItem('root');

        $menu->addChild('show', [
            'label' => 'participants.action.show',
            'route' => 'admin_participants_show',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'current' => 'admin_participants_show' === $route,
        ]);

        $menu->addChild('edit', [
            'label' => 'participants.action.edit',
            'route' => 'admin_participants_edit',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'display' => $this->isGranted('edit', $item),
            'current' => 'admin_participants_edit' === $route,
        ]);

        $menu->addChild('attendances', [
            'label' => 'participants.action.attendances',
            'route' => 'admin_participants_attendances',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'display' => $this->isGranted('view', $item),
            'current' => 'admin_participants_attendances' === $route,
        ]);

        return $menu;
    }

    private function offers(ItemInterface $root, OfferInterface $item, ?string $view = null)
    {
        if ('admin_editions_assign' === $view || 'admin_offers_assign' === $view || 'admin_editions_lotting' === $view) {
            $root->addChild('show', [
                'label' => 'offers.action.show',
                'route' => 'admin_offers_show',
                'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
                'display' => $this->isGranted('participants.view', $item),
                'extras' => ['icon' => 'info', 'section' => 'base', 'attr' => ['data-turbo-frame' => 'slideover']],
            ]);
            if ($item->isOnlineApplication()) {
                $root->addChild('participantList', [
                    'label' => 'offers.action.participants',
                    'route' => 'admin_offers_participants',
                    'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
                    'display' => $this->isGranted('participants.view', $item),
                    'extras' => ['icon' => 'user-list', 'section' => 'participants'],
                ]);
            }

            $root->addChild('increaseSeats', [
                'label' => 'offers.action.increaseSeats',
                'route' => 'admin_offers_increase_seats',
                'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
                'display' => $this->isGranted('edit', $item),
                'extras' => ['icon' => 'rows-plus-bottom', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'participants'],
            ]);

            $root->addChild('mailing', [
                'label' => 'offers.action.mailing',
                'route' => 'admin_tools_mailing',
                'routeParameters' => ['gruppe' => 'teilnehmende', 'angebote' => [$item->getId()]],
                'display' => $this->isGranted('participants.view', $item),
                'extras' => ['icon' => 'envelope', 'section' => 'participants'],
            ]);

            return;
        }

        $root->addChild('edit', [
            'label' => 'offers.action.edit',
            'route' => 'admin_offers_edit',
            'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
            // 'display' => $this->isGranted('edit', $item),
            'extras' => ['icon' => 'pencil-simple', 'section' => 'primary'],
        ]);

        foreach ($this->offerWorkflow->getEnabledTransitions($item) as $transition) {
            $this->addWorkflowTransition($root, $item, $transition->getName(), $view);
        }

        $root->addChild('copy', [
            'label' => 'offers.action.duplicate',
            'route' => 'admin_offers_duplicate',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'display' => $this->isGranted('view', $item),
            'extras' => ['icon' => 'copy-simple', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'edit'],
        ]);

        $root->addChild('proof', [
            'label' => 'offers.action.proof',
            'route' => 'admin_offers_proof',
            'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
            'display' => $this->isGranted('view', $item),
            'extras' => ['icon' => 'crosshair', 'section' => 'edit'],
        ]);

        if (!$item->getDates()->isEmpty()) {
            $root->addChild('variants', [
                'label' => 'offers.action.variants',
                'route' => 'admin_offers_variants',
                'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
                'display' => $this->isGranted('edit', $item),
                'extras' => ['icon' => 'calendar-plus', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'dates'],
            ]);
        }

        if ($item->isOnlineApplication() && $item->isPublished()) {
            $root->addChild('participantList', [
                'label' => 'offers.action.participants',
                'route' => 'admin_offers_participants',
                'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
                'display' => $this->isGranted('participants.view', $item),
                'extras' => ['icon' => 'user-list', 'section' => 'participants'],
            ]);
        }

        if ($item->isOnlineApplication() && !$item->isPublished()) {
            $root->addChild('participantList', [
                'label' => 'offers.action.participants',
                'route' => 'admin_offers_participants',
                'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
                'display' => $this->isGranted('participants.view', $item),
                'extras' => ['icon' => 'users', 'section' => 'participants'],
            ]);
        }

        if ($item->isOnlineApplication()) {
            $root->addChild('participantAssigning', [
                'label' => 'offers.action.assign',
                'route' => 'admin_offer_assign',
                'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
                'display' => $this->isGranted('participants.view', $item) && ($item->getEdition()->hostsCanAssign() || $this->isGranted('ROLE_ADMIN')),
                'extras' => ['icon' => 'arrows-clockwise', 'section' => 'participants'],
            ]);
        }

        $root->addChild('increaseSeats', [
            'label' => 'offers.action.increaseSeats',
            'route' => 'admin_offers_increase_seats',
            'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
            'display' => $this->isGranted('edit', $item),
            'extras' => ['icon' => 'rows-plus-bottom', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'participants'],
        ]);

        $root->addChild('transferParticipants', [
            'label' => 'offers.action.transfer_participants',
            'route' => 'admin_offers_transfer_participants',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'display' => $this->isGranted('participants.view', $item),
            'extras' => ['icon' => 'arrows-left-right', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'participants'],
        ]);

        $root->addChild('mailing', [
            'label' => 'offers.action.mailing',
            'route' => 'admin_tools_mailing',
            'routeParameters' => ['gruppe' => 'teilnehmende', 'angebote' => [$item->getId()]],
            'display' => $this->isGranted('participants.view', $item),
            'extras' => ['icon' => 'envelope', 'section' => 'participants'],
        ]);

        $root->addChild('delete', [
            'label' => 'accounts.action.delete',
            'route' => 'admin_offers_delete',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'display' => $this->isGranted('delete', $item),
            'extras' => ['icon' => 'trash', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'delete'],
        ]);
    }

    private function participants(ItemInterface $root, ParticipantInterface $item, ?string $view = null)
    {
        $root->addChild('show', [
            'label' => 'participants.action.show',
            'route' => 'admin_participants_show',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'display' => $this->isGranted('edit', $item),
            'extras' => ['icon' => 'info', 'section' => 'basic'],
        ]);

        $root->addChild('edit', [
            'label' => 'participants.action.edit',
            'route' => 'admin_participants_edit',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'display' => $this->isGranted('edit', $item),
            'extras' => ['icon' => 'pencil-simple', 'section' => 'basic'],
        ]);

        $root->addChild('attendances', [
            'label' => 'participants.action.attendances',
            'route' => 'admin_participants_attendances',
            'routeParameters' => array_merge(
                ['uuid' => $item->getUuid()->toBase58()],
                $this->attendancesQueryParamsFromCurrentRoute(),
            ),
            'display' => $this->isGranted('view', $item),
            'extras' => ['icon' => 'user-list', 'section' => 'attendances'],
        ]);

        $root->addChild('delete', [
            'label' => 'participants.action.delete',
            'route' => 'admin_participants_delete',
            'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
            'display' => $this->isGranted('delete', $item),
            'extras' => ['icon' => 'trash', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'delete'],
        ]);
    }

    private function duplicates(ItemInterface $root, ParticipantDuplicateDto $item, ?string $view = null)
    {
        if ('unconfirmed' !== $item->statusGroup) {
            return;
        }

        $root->addChild('ignore', [
            'label' => 'participant.duplicates.action.ignore',
            'route' => 'admin_participant_duplicates_ignore_modal',
            'routeParameters' => [
                'uuid1' => $item->participant1->uuid,
                'uuid2' => $item->participant2->uuid,
            ],
            'extras' => [
                'icon' => 'x',
                'color' => 'text-gray-400',
                'attr' => ['data-turbo-frame' => 'modal'],
            ],
        ]);

        $root->addChild('tolerate', [
            'label' => 'participant.duplicates.action.tolerate',
            'route' => 'admin_participant_duplicates_tolerate_modal',
            'routeParameters' => [
                'uuid1' => $item->participant1->uuid,
                'uuid2' => $item->participant2->uuid,
            ],
            'extras' => [
                'icon' => 'check',
                'color' => 'text-yellow-600',
                'attr' => ['data-turbo-frame' => 'modal'],
            ],
        ]);

        $root->addChild('merge', [
            'label' => 'participant.duplicates.action.merge',
            'route' => 'admin_participant_duplicates_merge_modal',
            'routeParameters' => [
                'uuid1' => $item->participant1->uuid,
                'uuid2' => $item->participant2->uuid,
            ],
            'extras' => [
                'icon' => 'arrows-clockwise',
                'color' => 'text-primary-600',
                'attr' => ['data-turbo-frame' => 'modal'],
            ],
        ]);
    }

    private function debtors(ItemInterface $root, Debtor $item, ?string $view = null)
    {
        $root->addChild('show', [
            'label' => 'debtors.action.show',
            'route' => 'admin_payments_debtor',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            // 'display' => $this->isGranted('edit', $item),
            'extras' => ['icon' => 'info', 'section' => 'basic'],
        ]);

        if ($item->getAttendancesDue()) {
            $root->addChild('settle', [
                'label' => 'debtors.action.settle',
                'route' => 'admin_attendances_settle',
                'routeParameters' => ['ids' => array_map(static fn (Attendance $attendance) => $attendance->getId(), $item->getAttendancesDue())],
                // 'display' => $this->isGranted('edit', $item),
                'extras' => ['icon' => 'receipt', 'section' => 'balance', 'attr' => ['data-turbo-frame' => 'slideover']],
            ]);
        }

        $root->addChild('createBooking', [
            'label' => 'debtors.action.createBooking',
            'route' => 'admin_payments_create_booking',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            // 'display' => $this->isGranted('edit', $item),
            'extras' => ['icon' => 'wallet', 'section' => 'balance', 'attr' => ['data-turbo-frame' => 'modal']],
        ]);
    }

    private function hosts(ItemInterface $root, Host $item, ?string $view = null)
    {
        $root->addChild('edit', [
            'label' => 'hosts.action.edit',
            'route' => 'admin_hosts_edit',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'display' => $this->isGranted('edit', $item),
            'extras' => ['icon' => 'pencil-simple', 'section' => 'basic'],
        ]);

        $root->addChild('mailing', [
            'label' => 'hosts.action.mailing',
            'route' => 'admin_tools_mailing',
            'routeParameters' => ['gruppe' => 'veranstaltende', 'veranstaltende' => [$item->getId()]],
            'extras' => ['icon' => 'envelope', 'section' => 'basic'],
        ]);

        $root->addChild('delete', [
            'label' => 'hosts.action.delete',
            'route' => 'admin_hosts_delete',
            'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
            'display' => $this->isGranted('delete', $item),
            'extras' => ['icon' => 'trash', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'delete'],
        ]);
    }

    private function consents(ItemInterface $root, Consent $item, ?string $view = null)
    {
        if (null !== $item->getConsentForm()) {
            $root->addChild('show', [
                'label' => 'signatures.action.show',
                'route' => 'admin_consents_show',
                'routeParameters' => [
                    'uuid' => $item->getUuid()->toBase58(),
                ],
                'extras' => ['icon' => 'magnifying-glass', 'attr' => ['data-turbo-frame' => 'slideover'], 'section' => 'primary'],
            ]);
        }

        if (!$item->isRevoked()) {
            $root->addChild('revoke', [
                'label' => 'signatures.action.revoke',
                'route' => 'admin_consents_revoke',
                'routeParameters' => ['id' => $item->getId()],
                'display' => $this->isGranted('revoke', $item),
                'extras' => ['icon' => 'trash', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'delete'],
            ]);
        }

        $root->addChild('sheet', [
            'label' => 'signatures.action.sheet',
            'route' => 'admin_consents_sheet',
            'routeParameters' => ['id' => $item->getId()],
            'display' => $this->isGranted('view', $item),
            'extras' => ['icon' => 'file-arrow-down', 'section' => 'basic'],
        ]);

        $root->addChild('delete', [
            'label' => 'signatures.action.delete',
            'route' => 'admin_consents_delete',
            'routeParameters' => ['id' => $item->getId()],
            'display' => $this->isGranted('delete', $item),
            'extras' => ['icon' => 'trash', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'delete'],
        ]);
    }

    private function editions(ItemInterface $root, Edition $item, ?string $view = null)
    {
        // Order mirrors the tertiary nav on edition pages
        // (show, edit, proofs, assign, notifications, mailing, export, stats).

        $root->addChild('show', [
            'label' => 'editions.action.show',
            'route' => 'admin_editions_show',
            'routeParameters' => ['alias' => $item->getAlias()],
            'extras' => ['icon' => 'magnifying-glass', 'section' => 'basic'],
        ]);

        $root->addChild('edit', [
            'label' => 'editions.action.edit',
            'route' => 'admin_editions_edit',
            'routeParameters' => ['alias' => $item->getAlias()],
            'display' => $this->isGranted('edit', $item),
            'extras' => ['icon' => 'pencil-simple', 'section' => 'basic'],
        ]);

        // Direct shortcut to the `tasks` section of the edit screen — that
        // section is its own LiveComponent (Admin:Edition:Tasks) and shows
        // the Gantt timeline + 7 phase sections.
        $root->addChild('tasks', [
            'label' => 'editions.action.tasks',
            'route' => 'admin_editions_edit',
            'routeParameters' => ['alias' => $item->getAlias(), 'section' => 'tasks'],
            'display' => $this->isGranted('edit', $item),
            'extras' => ['icon' => 'calendar', 'section' => 'basic'],
        ]);

        $root->addChild('proofs', [
            'label' => 'editions.action.proofs',
            'route' => 'admin_offers_review',
            'routeParameters' => ['alias' => $item->getAlias()],
            'display' => $this->isGranted('stats', $item),
            'extras' => ['icon' => 'check-square', 'section' => 'basic'],
        ]);

        $root->addChild('assign', [
            'label' => 'editions.action.assign',
            'route' => 'admin_editions_assign',
            'routeParameters' => ['alias' => $item->getAlias()],
            'display' => $this->isGranted('assign', $item),
            'extras' => ['icon' => 'arrows-clockwise', 'section' => 'basic'],
        ]);

        $root->addChild('notifications', [
            'label' => 'editions.action.notifications',
            'route' => 'admin_editions_notifications',
            'routeParameters' => ['alias' => $item->getAlias()],
            'display' => $this->isGranted('ROLE_ADMIN', $item),
            'extras' => ['icon' => 'bell', 'section' => 'basic'],
        ]);

        $root->addChild('export', [
            'label' => 'editions.action.export',
            'route' => 'admin_editions_export',
            'routeParameters' => ['alias' => $item->getAlias()],
            'display' => $this->isGranted('export', $item),
            'extras' => ['icon' => 'file-arrow-down', 'section' => 'basic'],
        ]);

        $root->addChild('stats', [
            'label' => 'editions.action.stats',
            'route' => 'admin_editions_stats',
            'routeParameters' => ['alias' => $item->getAlias()],
            'display' => $this->isGranted('stats', $item),
            'extras' => ['icon' => 'chart-pie', 'section' => 'basic'],
        ]);

        $root->addChild('delete', [
            'label' => 'editions.action.delete',
            'route' => 'admin_editions_delete',
            'routeParameters' => array_filter(['alias' => $item->getAlias()]),
            'display' => $this->isGranted('delete', $item),
            'extras' => ['icon' => 'trash', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'delete'],
        ]);
    }

    private function accessCodes(ItemInterface $root, AccessCodeStrategy $item, ?string $view = null)
    {
        $root->addChild('edit', [
            'label' => 'accessCodes.action.edit',
            'route' => 'admin_accessCodes_edit',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            // 'display' => $this->isGranted('edit', $item),
            'extras' => ['icon' => 'pencil-simple', 'section' => 'basic'],
        ]);

        $root->addChild('delete', [
            'label' => 'accessCodes.action.delete',
            'route' => 'admin_accessCodes_delete',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'display' => $this->isGranted('delete', $item),
            'extras' => ['icon' => 'trash', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'delete'],
        ]);
    }

    private function attendances(ItemInterface $root, Attendance $item, ?string $view = null, array $options = [])
    {
        if ('admin_payments_debtor' === $view) {
            if (!$item->isPaid()) {
                $root->addChild('settle', [
                    'label' => 'attendance.action.settle',
                    'route' => 'admin_attendances_settle',
                    'routeParameters' => ['ids' => [$item->getId()]],
                    'extras' => ['icon' => 'receipt', 'attr' => ['data-turbo-frame' => 'slideover'], 'section' => 'primary'],
                ]);
                $root->addChild('unsetPayable', [
                    'label' => 'attendance.action.unsetPayable',
                    'route' => 'admin_attendance_pay_status',
                    'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
                    'extras' => ['icon' => 'receipt-x', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'primary'],
                ]);
            }
            $root->addChild('status', [
                'label' => 'attendance.action.status',
                'route' => 'admin_participants_attendances_status',
                'routeParameters' => ['ids' => [$item->getId()]],
                'extras' => ['icon' => 'flag', 'attr' => ['data-turbo-frame' => 'slideover'], 'section' => 'attendance'],
            ]);

            return;
        }
        if ('admin_commit_attendances' === $view) {
            $root->addChild('status', [
                'label' => 'attendance.action.status',
                'route' => 'admin_participants_attendances_status',
                'routeParameters' => ['ids' => [$item->getId()]],
                'extras' => ['icon' => 'flag', 'attr' => ['data-turbo-frame' => 'slideover'], 'section' => 'primary'],
            ]);

            $root->addChild('participant', [
                'label' => 'attendance.action.participant',
                'route' => 'admin_participants_show',
                'routeParameters' => ['uuid' => $item->getParticipant()->getUuid()->toBase58()],
                'display' => $this->isGranted('view', $item->getParticipant()),
                'extras' => ['icon' => 'user-square', 'section' => 'participant', 'attr' => ['data-turbo-frame' => 'slideover']],
            ]);

            $root->addChild('offerParticipantList', [
                'label' => 'attendance.action.offerParticipantList',
                'route' => 'admin_offers_participants',
                'routeParameters' => ['uuid' => $item->getOffer()->getUuid()->toBase58()],
                'display' => $this->isGranted('view', $item->getOffer()),
                'extras' => ['icon' => 'user-list', 'section' => 'offer'],
            ]);

            $root->addChild('offerAssign', [
                'label' => 'attendance.action.offerAssign',
                'route' => 'admin_offer_assign',
                'routeParameters' => ['uuid' => $item->getOffer()->getUuid()->toBase58()],
                'display' => $this->isGranted('view', $item->getOffer()),
                'extras' => ['icon' => 'arrows-clockwise', 'section' => 'offer'],
            ]);

            return;
        }

        if ('admin_payments_unpaid' === $view) {
            $root->addChild('unsetPayable', [
                'label' => 'attendance.action.unsetPayable',
                'route' => 'admin_attendance_pay_status',
                'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
                'extras' => ['icon' => 'receipt-x', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'primary'],
            ]);

            $root->addChild('settle', [
                'label' => 'attendance.action.settle',
                'route' => 'admin_attendances_settle',
                'routeParameters' => ['ids' => [$item->getId()]],
                'extras' => ['icon' => 'receipt', 'attr' => ['data-turbo-frame' => 'slideover'], 'section' => 'secondary'],
            ]);
            $root->addChild('status', [
                'label' => 'attendance.action.status',
                'route' => 'admin_participants_attendances_status',
                'routeParameters' => ['ids' => [$item->getId()]],
                'extras' => ['icon' => 'flag', 'attr' => ['data-turbo-frame' => 'slideover'], 'section' => 'secondary'],
            ]);

            return;
        }

        if ('admin_payments_overpaid' === $view) {
            $root->addChild('payments', [
                'label' => 'attendance.action.payments',
                'route' => 'admin_participants_attendances_payments',
                'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
                'extras' => ['icon' => 'receipt', 'attr' => ['data-turbo-frame' => 'slideover'], 'section' => 'attendance'],
            ]);

            return;
        }

        $root->addChild('status', [
            'label' => 'attendance.action.status',
            'route' => 'admin_participants_attendances_status',
            'routeParameters' => ['ids' => [$item->getId()]],
            'extras' => ['icon' => 'flag', 'attr' => ['data-turbo-frame' => 'slideover'], 'section' => 'attendance'],
        ]);

        $root->addChild('payments', [
            'label' => 'attendance.action.payments',
            'route' => 'admin_participants_attendances_payments',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'extras' => ['icon' => 'receipt', 'attr' => ['data-turbo-frame' => 'slideover'], 'section' => 'attendance'],
        ]);

        $root->addChild('offerParticipantList', [
            'label' => 'attendance.action.offerParticipantList',
            'route' => 'admin_offers_participants',
            'routeParameters' => ['uuid' => $item->getOffer()->getUuid()->toBase58()],
            'display' => $this->isGranted('view', $item->getOffer()),
            'extras' => ['icon' => 'user-list', 'section' => 'offer'],
        ]);

        $root->addChild('offerAssign', [
            'label' => 'attendance.action.offerAssign',
            'route' => 'admin_offer_assign',
            'routeParameters' => ['uuid' => $item->getOffer()->getUuid()->toBase58()],
            'display' => $this->isGranted('view', $item->getOffer()),
            'extras' => ['icon' => 'arrows-clockwise', 'section' => 'offer'],
        ]);
    }

    private function payments(ItemInterface $root, Payment $item, ?string $view = null)
    {
        $root->addChild('receipt', [
            'label' => 'payments.action.receipt',
            'route' => 'admin_payments_receipt',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'extras' => ['icon' => 'receipt', 'section' => 'basic'],
        ]);

        if ($item->getDebtor()) {
            $root->addChild('debtor', [
                'label' => 'payments.action.debtor',
                'route' => 'admin_payments_debtor',
                'routeParameters' => ['uuid' => $item->getDebtor()->getUuid()->toBase58()],
                'extras' => ['icon' => 'identification-card', 'section' => 'basic', 'attr' => ['data-turbo-frame' => 'slideover']],
            ]);
        }

        if ($item->isPaid() && !$item->isReversal()) {
            $root->addChild('reverse', [
                'label' => 'payments.action.reverse',
                'route' => 'admin_payments_reverse',
                'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
                'extras' => ['icon' => 'arrow-u-up-left', 'section' => 'reverse', 'attr' => ['data-turbo-frame' => 'modal']],
            ]);
        }
    }

    private function accounts(ItemInterface $root, User $item, ?string $view = null)
    {
        $root->addChild('edit', [
            'label' => 'accounts.action.edit',
            'route' => 'admin_accounts_edit',
            'routeParameters' => ['uuid' => $item->getUuid()->toBase58()],
            'display' => $this->isGranted('edit', $item),
            'extras' => ['icon' => 'pencil-simple', 'section' => 'basic'],
        ]);

        if (\in_array('ROLE_MEMBER', $item->getRoles(), true)) {
            $root->addChild('impersonate', [
                'label' => 'accounts.action.impersonate',
                'route' => 'admin_frontend_preview',
                'routeParameters' => ['username' => $item->getUserIdentifier()],
                'display' => $this->isGranted('ROLE_ALLOWED_TO_SWITCH'),
                'linkAttributes' => ['data-turbo' => 'false'],
                'extras' => ['icon' => 'sign-out', 'method' => 'post', 'translation_params' => ['user' => $item->getUserIdentifier()], 'section' => 'security'],
            ]);
        } else {
            $root->addChild('impersonate', [
                'label' => 'accounts.action.impersonate',
                'route' => 'admin_index',
                'routeParameters' => ['_switch_user' => $item->getUserIdentifier()],
                'display' => $this->isGranted('ROLE_ALLOWED_TO_SWITCH'),
                'linkAttributes' => ['data-turbo' => 'false'],
                // State-changing action -> render as a POST <form> (DropdownItem).
                'extras' => ['icon' => 'sign-out', 'method' => 'post', 'translation_params' => ['user' => $item->getUserIdentifier()], 'section' => 'security'],
            ]);
        }

        if ($item->isBlockedEmail()) {
            $root->addChild('unblock', [
                'label' => 'accounts.action.unblock',
                'route' => 'admin_accounts_unblock',
                'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
                'display' => $this->isGranted('unblock', $item),
                'extras' => ['icon' => 'envelope', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'security'],
            ]);
        }

        $root->addChild('password', [
            'label' => 'accounts.action.password',
            'route' => 'admin_accounts_password',
            'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
            'display' => $this->isGranted('password', $item),
            'extras' => ['icon' => 'key', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'security'],
        ]);

        $root->addChild('delete', [
            'label' => 'accounts.action.delete',
            'route' => 'admin_accounts_delete',
            'routeParameters' => array_filter(['uuid' => $item->getUuid()->toBase58()]),
            'display' => $this->isGranted('delete', $item),
            'extras' => ['icon' => 'trash', 'attr' => ['data-turbo-frame' => 'modal'], 'section' => 'delete'],
        ]);
    }

    private function isGranted(string $attribute, ?object $item = null): bool
    {
        return $this->authorizationChecker->isGranted($attribute, $item);
    }

    private function attendancesQueryParamsFromCurrentRoute(): array
    {
        $request = $this->requestStack->getMainRequest();
        if (null === $request) {
            return [];
        }

        if ('admin_participants_index' !== $request->attributes->get('_route')) {
            return [];
        }

        $editionParam = (string) $request->attributes->get('edition', '');
        if ('' === $editionParam) {
            return [];
        }

        $aliases = array_values(array_filter(explode('+', $editionParam)));
        if (1 !== \count($aliases)) {
            return [];
        }

        return ['filter' => ['edition' => $aliases[0]]];
    }

    private function addWorkflowTransition(ItemInterface $root, OfferInterface $item, string $transitionName, ?string $view = null): void
    {
        $icons = [
            'draft' => 'plus-circle',
            'to_draft' => 'plus-circle',
            'to_draft_2' => 'plus-circle',
            'cancel' => 'x-circle-fill',
            'cancelled' => 'x-circle-fill',
            'finalize' => 'check-circle',
            'finalized' => 'check-circle',
            'approve' => 'shield-check',
            'reviewed' => 'shield-check',
            'publish' => 'check-circle-fill',
            'relaunch' => 'check-circle-fill',
            'published' => 'check-circle-fill',
            'unpublish' => 'x-circle',
            'complete' => 'check-circle-fill',
            'completed' => 'check-circle-fill',
        ];

        $colors = [
            'draft' => 'text-orange-600',
            'to_draft' => 'text-orange-600',
            'to_draft_2' => 'text-orange-600',
            'cancel' => 'text-red-600',
            'cancelled' => 'text-red-600',
            'finalize' => 'text-green-600',
            'finalized' => 'text-green-600',
            'approve' => 'text-green-600',
            'reviewed' => 'text-green-600',
            'publish' => 'text-green-600',
            'relaunch' => 'text-green-600',
            'published' => 'text-green-600',
            'unpublish' => 'text-gray-500',
            'complete' => 'text-blue-600',
            'completed' => 'text-blue-600',
        ];

        $options = [
            'label' => 'offers.workflow.'.$transitionName,
            'extras' => [
                'icon' => $icons[$transitionName] ?? 'circle',
                'color' => $colors[$transitionName] ?? 'text-gray-400',
                'section' => 'primary',
            ],
        ];

        // Should become a modal dialog
        if (\in_array($transitionName, ['cancel', 'relaunch', 'complete'], true)) {
            $options['route'] = 'admin_offers_'.$transitionName;
            $options['routeParameters'] = ['uuid' => $item->getUuid()->toBase58()];
            $options['extras']['attr']['data-turbo-frame'] = 'modal';
        } else {
            $options['route'] = 'admin_offers_apply';
            $options['routeParameters'] = ['uuid' => $item->getUuid()->toBase58(), 'transition' => $transitionName];
            $options['extras']['method'] = 'post';
        }

        $root->addChild('workflow_'.$transitionName, $options);
    }
}
