<?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\Entity\Host;
use Ferienpass\CoreBundle\Entity\Offer\OfferInterface;
use Ferienpass\CoreBundle\Entity\User;
use Ferienpass\CoreBundle\Payments\PaymentSystem;
use Ferienpass\CoreBundle\Repository\EditionRepository;
use Ferienpass\CoreBundle\Repository\HostRepository;
use Ferienpass\CoreBundle\Repository\OfferRepositoryInterface;
use Knp\Menu\FactoryInterface;
use Knp\Menu\ItemInterface;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Http\Logout\LogoutUrlGenerator;
use Symfony\Component\Translation\TranslatableMessage;

class MenuBuilder
{
    public function __construct(private readonly FactoryInterface $factory, private readonly LogoutUrlGenerator $logoutUrlGenerator, private readonly AuthorizationCheckerInterface $authorizationChecker, private readonly RequestStack $requestStack, private readonly EditionRepository $editions, private readonly Security $security, private readonly HostRepository $hosts, private readonly OfferRepositoryInterface $offers, private readonly PaymentSystem $paymentSystem, #[Autowire(param: 'ferienpass_admin.plausible_shared_link')] private readonly string $plausibleSharedLink = '')
    {
    }

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

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

        $menu->addChild('offers.title', [
            'route' => 'admin_offers_index',
            'current' => $route && (str_starts_with($route, 'admin_offers') || str_starts_with($route, 'admin_editions_assign')),
        ]);

        if (!$this->isGranted('ROLE_ADMIN')) {
            $menu->addChild('profile.title', [
                'route' => 'admin_profile_index',
                'current' => $route && str_starts_with($route, 'admin_profile'),
            ]);
        }

        if ($this->isGranted('ROLE_PARTICIPANTS_ADMIN')) {
            $menu->addChild('participants.title', [
                'route' => 'admin_participants_index',
                'current' => $route && str_starts_with($route, 'admin_participant'),
            ]);
        }

        if ($this->isGranted('ROLE_ADMIN')) {
            $menu->addChild('hosts.title', [
                'route' => 'admin_hosts_index',
                'current' => $route && str_starts_with($route, 'admin_hosts'),
            ]);
        }
        if ($this->isGranted('ROLE_PAYMENTS_ADMIN') && $this->paymentSystem->isEnabled()) {
            $menu->addChild('payments.title', [
                'route' => 'admin_payments_debtors',
                'current' => $route && str_starts_with($route, 'admin_payments'),
            ]);
        }
        // Files should be available to non-admins as well
        $menu->addChild('files.title', [
            'route' => 'admin_files',
            'current' => $route && str_starts_with($route, 'admin_files'),
        ]);
        if ($this->isGranted('ROLE_ADMIN')) {
            $menu->addChild('accounts.title', [
                'route' => 'admin_accounts_index',
                'current' => $route && str_starts_with($route, 'admin_accounts'),
            ]);

            $isToolRoute = $route && (
                str_starts_with($route, 'admin_tools')
                || str_starts_with($route, 'admin_accessCodes')
                || str_starts_with($route, 'admin_notifications')
                || str_starts_with($route, 'admin_editions')
                || \in_array($route, ['admin_outbox', 'admin_export_index', 'admin_webstats', 'admin_consents_index', 'admin_erase_data', 'email_delivery_errors', 'blocked_contacts'], true)
            );

            $tools = $menu->addChild('tools.title', [
                'uri' => '#',
                'current' => $isToolRoute,
                'extras' => ['mega_menu' => true],
            ]);

            // Group: Daten
            $daten = $tools->addChild('mega.daten', [
                'label' => 'Daten',
                'uri' => '#',
                'extras' => ['mega_group' => true],
            ]);
            $daten->addChild('editions.title', [
                'route' => 'admin_editions_index',
                'extras' => ['icon' => 'ph:calendar', 'desc' => 'Ferienpass-Programme und Zeiträume verwalten'],
            ]);
            $daten->addChild('export.title', [
                'route' => 'admin_export_index',
                'extras' => ['icon' => 'ph:file-arrow-down', 'desc' => 'Word, PDF, Excel'],
            ]);
            if ('' !== $this->plausibleSharedLink) {
                $daten->addChild('webstats.title', [
                    'label' => 'Webstatistik',
                    'route' => 'admin_webstats',
                    'extras' => ['icon' => 'ph:chart-line', 'desc' => 'Besucher und Seitenaufrufe'],
                ]);
            }

            // Group: Kommunikation
            $communication = $tools->addChild('mega.communication', [
                'label' => 'Kommunikation',
                'uri' => '#',
                'extras' => ['mega_group' => true],
            ]);
            $communication->addChild('notifications.title', [
                'route' => 'admin_notifications',
                'extras' => ['icon' => 'ph:bell', 'desc' => 'System-Mails an Eltern, Kinder und Veranstaltende'],
            ]);
            $communication->addChild('mailing.title', [
                'route' => 'admin_tools_mailing',
                'extras' => ['icon' => 'ph:megaphone', 'desc' => 'Massenmail versenden'],
            ]);
            if ($this->isGranted('ROLE_SUPER_ADMIN')) {
                $communication->addChild('outbox.title', [
                    'route' => 'admin_outbox',
                    'extras' => ['icon' => 'ph:paper-plane-tilt', 'desc' => 'Vom System gesendete Nachrichten'],
                ]);
            }

            // Group: Datenschutz (super-admin only)
            if ($this->isGranted('ROLE_SUPER_ADMIN')) {
                $privacy = $tools->addChild('mega.privacy', [
                    'label' => 'Datenschutz',
                    'uri' => '#',
                    'extras' => ['mega_group' => true],
                ]);
                $privacy->addChild('consents.title', [
                    'route' => 'admin_consents_index',
                    'extras' => ['icon' => 'ph:identification-card', 'desc' => 'DSE und Einverständniserklärungen'],
                ]);
                $privacy->addChild('eraseData.title', [
                    'label' => 'Betroffenenrechte',
                    'route' => 'admin_erase_data',
                    'extras' => ['icon' => 'ph:user-check', 'desc' => 'Auskunft und Löschung'],
                ]);

                // Group: System
                $system = $tools->addChild('mega.system', [
                    'label' => 'System',
                    'uri' => '#',
                    'extras' => ['mega_group' => true],
                ]);
                $system->addChild('settings.title', [
                    'label' => 'Systemkonfiguration',
                    'route' => 'admin_tools_settings',
                    'extras' => ['icon' => 'ph:wrench', 'desc' => 'Allgemein, Integrationen, Kategorien'],
                ]);
            }
        }

        return $menu;
    }

    public function secondaryNavigation(): ItemInterface
    {
        $request = $this->requestStack->getMainRequest();
        $menu = $this->factory->createItem('root');

        if (!$request) {
            return $menu;
        }

        $route = (string) $request->attributes->get('_route');

        if (str_starts_with($route, 'admin_profile_index')) {
            $currentHost = $request->attributes->get('host');
            if ($currentHost instanceof Host) {
                $currentHostAlias = $currentHost->getAlias();
            } else {
                $currentHostAlias = $currentHost;
            }
            $user = $this->security->getUser();
            if ($user instanceof User) {
                $hosts = $this->hosts->findByUser($user);
                foreach ($hosts as $h) {
                    $menu->addChild($h->getName(), [
                        'route' => 'admin_profile_index',
                        'routeParameters' => ['host' => $h->getAlias()],
                        'current' => $currentHostAlias === $h->getAlias(),
                    ]);
                }
            }
        } elseif (str_starts_with($route, 'admin_participant')) {
            $menu->addChild('participants.all', [
                'route' => 'admin_participants_index',
                'current' => \in_array($route, ['admin_participants_index', 'admin_participants_create', 'admin_participants_edit', 'admin_participants_show', 'admin_participants_attendances'], true),
            ]);
            $menu->addChild('participants.duplicates', [
                'route' => 'admin_participant_duplicates',
                'current' => 'admin_participant_duplicates' === $route,
            ]);
        } elseif (str_starts_with($route, 'admin_payments')) {
            $menu->addChild('payments.debtors', [
                'route' => 'admin_payments_debtors',
                'current' => \in_array($route, ['admin_payments_debtors', 'admin_payments_debtor'], true),
            ]);
            $menu->addChild('payments.title', [
                'route' => 'admin_payments_receipts',
                'current' => \in_array($route, ['admin_payments_receipts', 'admin_payments_receipt'], true),
            ]);
            $menu->addChild('payments.unpaid', [
                'route' => 'admin_payments_unpaid',
                'current' => 'admin_payments_unpaid' === $route,
            ]);
            $menu->addChild('payments.overpaid', [
                'route' => 'admin_payments_overpaid',
                'current' => 'admin_payments_overpaid' === $route,
            ]);
        }

        // Tool-page routes (mailing, notifications, outbox, settings sub-pages, …)
        // intentionally emit no secondary strip — the mega-menu under "Werkzeuge
        // & Einstellungen" handles discovery, and System pages use an in-page TOC.

        return $menu;
    }

    public function userNavigation(): ItemInterface
    {
        $request = $this->requestStack->getMainRequest();
        $menu = $this->factory->createItem('root');

        $menu->addChild('user.title', [
            'route' => 'admin_user_index',
            'current' => $request instanceof \Symfony\Component\HttpFoundation\Request && 'admin_user_index' === $request->attributes->get('_route'),
            'extras' => ['icon' => 'user'],
        ]);

        $menu->addChild('user.password.title', [
            'route' => 'admin_security',
            'current' => $request instanceof \Symfony\Component\HttpFoundation\Request && 'admin_security' === $request->attributes->get('_route'),
            'extras' => ['icon' => 'password'],
        ]);

        $token = $this->security->getToken();

        if ($token instanceof SwitchUserToken) {
            $impersonatorUser = $token->getOriginalToken()->getUser();
            $menu->addChild('user.impersonation_exit', [
                'label' => new TranslatableMessage('user.impersonation_exit', ['impersonator' => $impersonatorUser->getUserIdentifier()], 'admin'),
                'route' => 'admin_accounts_index',
                'routeParameters' => ['_switch_user' => '_exit'],
                'linkAttributes' => ['data-turbo' => 'false'],
                // State-changing action -> render as a POST <form> (DropdownItem).
                'extras' => ['icon' => 'sign-out', 'method' => 'post'],
            ]);
        }

        $menu->addChild('user.logout', [
            'uri' => $this->logoutUrlGenerator->getLogoutUrl('ferienpass_admin'),
            'linkAttributes' => ['data-turbo' => 'false'],
            'extras' => ['icon' => 'sign-out', 'method' => 'post'],
        ]);

        return $menu;
    }

    public function participantListActions(array $options = []): ItemInterface
    {
        $offer = $options['offer'] ?? null;
        if (!$offer instanceof OfferInterface) {
            throw new \InvalidArgumentException('Pass "offer" as option');
        }

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

        $menu->addChild('pdf', [
            'label' => 'offers.action.participantList',
            'route' => 'admin_offers_participants',
            'routeParameters' => ['uuid' => $offer->getUuid()->toBase58(), '_suffix' => '.pdf'],
            'extras' => [
                'icon' => 'file-arrow-down',
            ],
        ]);

        //        if (!$offer->isCancelled()
        //            && ((null === $edition = $offer->getEdition()) || !$edition->getActiveTasks('show_offers')->isEmpty())) {
        //            $menu->addChild('cancel', [
        //                'label' => 'offers.action.cancel',
        //                'route' => 'admin_offer_show',
        //                'routeParameters' => ['id' => $offer->getId(), 'act' => 'cancel'],
        //                'display' => $this->isGranted('cancel', $offer),
        //                'extras' => [
        //                    'method' => 'post',
        //                    'icon' => 'ban-solid',
        //                ],
        //            ]);
        //        }
        //
        //        if ($offer->isCancelled()) {
        //            $menu->addChild('reactivate', [
        //                'label' => 'offers.action.reactivate',
        //                'route' => 'admin_offer_show',
        //                'routeParameters' => ['id' => $offer->getId(), 'act' => 'relaunch', 'edition' => $offer->getEdition()->getAlias()],
        //                'display' => $this->isGranted('reactivate', $offer),
        //                'extras' => [
        //                    'method' => 'post',
        //                    'icon' => 'trash-solid',
        //                ],
        //            ]);
        //        }

        return $menu;
    }

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