<?php

namespace App\Controller;

use App\Controller\Trait\AccountEventOwnershipTrait;
use App\Entity\Billet;
use App\Entity\BilletBuyer;
use App\Entity\BilletDesign;
use App\Entity\BilletOrder;
use App\Entity\Category;
use App\Entity\Event;
use App\Entity\Payout;
use App\Entity\User;
use App\Service\AuditService;
use App\Service\EventIndexService;
use App\Service\MailerService;
use App\Service\OrderIndexService;
use App\Service\StripeService;
use Doctrine\ORM\EntityManagerInterface;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;

#[IsGranted('ROLE_USER')]
class AccountController extends AbstractController
{
    use AccountEventOwnershipTrait;

    private const BREADCRUMB_HOME = ['name' => 'Accueil', 'url' => '/'];
    private const BREADCRUMB_ACCOUNT = ['name' => 'Mon compte', 'url' => '/mon-compte'];
    private const EVENT_BASE_URL = '/mon-compte/evenement/';
    private const DQL_EXCLUDE_INVITATIONS = 'o.isInvitation = false OR o.isInvitation IS NULL';
    private const DQL_BB_EXCLUDE_INVITATIONS = 'bb.isInvitation = false OR bb.isInvitation IS NULL';

    #[Route('/mon-compte', name: 'app_account')]
    public function index(Request $request, StripeService $stripeService, EntityManagerInterface $em, PaginatorInterface $paginator, EventIndexService $eventIndex): Response
    {
        /** @var User $user */
        $user = $this->getUser();
        $isOrganizer = $this->isGranted('ROLE_ORGANIZER');
        if ($isOrganizer && $user->getStripeAccountId() && (!$user->isStripeChargesEnabled() || !$user->isStripePayoutsEnabled())) {
            try { // @codeCoverageIgnoreStart
                $account = $stripeService->getClient()->accounts->retrieve($user->getStripeAccountId());
                $user->setStripeChargesEnabled((bool) $account->charges_enabled);
                $user->setStripePayoutsEnabled((bool) $account->payouts_enabled);
                $em->flush();
            } catch (\Throwable) {
                // Stripe API unavailable, keep current status
            } // @codeCoverageIgnoreEnd
        }

        $stripeReady = $user->isStripeChargesEnabled() && $user->isStripePayoutsEnabled();
        $organizerTabs = ['events', 'subaccounts', 'payouts'];
        $defaultTab = ($isOrganizer && $stripeReady) ? 'events' : 'tickets';
        $tab = $request->query->getString('tab', $defaultTab);

        if (\in_array($tab, $organizerTabs, true) && !$stripeReady) {
            $tab = $defaultTab;
        }

        $payouts = [];
        $subAccounts = [];
        $events = [];
        if ($isOrganizer) {
            $payouts = $em->getRepository(Payout::class)->findBy(
                ['organizer' => $user],
                ['createdAt' => 'DESC'],
            );
            $subAccounts = $em->getRepository(User::class)->findBy(
                ['parentOrganizer' => $user],
                ['createdAt' => 'DESC'],
            );
            $searchQuery = $request->query->getString('q', '');
            $eventsQuery = $eventIndex->searchEvents('event_'.$user->getId(), $searchQuery, ['account' => $user]);
            $events = $paginator->paginate($eventsQuery, $request->query->getInt('page', 1), 10);
        }

        $financeStats = $isOrganizer
            ? $this->computeFinanceStats($user, $em)
            : ['paid' => 0, 'pending' => 0, 'refunded' => 0, 'cancelled' => 0, 'commissionEticket' => 0, 'commissionStripe' => 0, 'net' => 0];

        $orders = $em->getRepository(BilletBuyer::class)->findBy(
            ['user' => $user],
            ['createdAt' => 'DESC'],
        );

        $userTickets = [];
        foreach ($orders as $order) {
            $tickets = $em->getRepository(BilletOrder::class)->findBy(['billetBuyer' => $order]);
            foreach ($tickets as $ticket) {
                $userTickets[] = $ticket;
            }
        }

        return $this->render('account/index.html.twig', [
            'tab' => $tab,
            'isOrganizer' => $isOrganizer,
            'payouts' => $payouts,
            'subAccounts' => $subAccounts,
            'events' => $events,
            'orders' => $orders,
            'userTickets' => $userTickets,
            'financeStats' => $financeStats,
            'breadcrumbs' => [
                self::BREADCRUMB_HOME,
                self::BREADCRUMB_ACCOUNT,
            ],
        ]);
    }

    #[Route('/mon-compte/parametres', name: 'app_account_settings', methods: ['POST'])]
    public function settings(Request $request, EntityManagerInterface $em): Response
    {
        /** @var User $user */
        $user = $this->getUser();
        $isOrganizer = $this->isGranted('ROLE_ORGANIZER');

        if (!$isOrganizer) {
            $user->setFirstName(trim($request->request->getString('first_name')));
            $user->setLastName(trim($request->request->getString('last_name')));
        }

        $user->setEmail(trim($request->request->getString('email')));
        $user->setPhone(trim($request->request->getString('phone')));

        if (!$isOrganizer) {
            $user->setAddress(trim($request->request->getString('address')));
            $user->setPostalCode(trim($request->request->getString('postal_code')));
            $user->setCity(trim($request->request->getString('city')));
        }

        if ($isOrganizer) {
            $user->setWebsite(trim($request->request->getString('website')));
            $user->setFacebook(trim($request->request->getString('facebook')));
            $user->setInstagram(trim($request->request->getString('instagram')));
            $user->setTwitter(trim($request->request->getString('twitter')));
            $user->setTiktok(trim($request->request->getString('tiktok')));

            $logoFile = $request->files->get('logo');
            if ($logoFile) {
                $user->setLogoFile($logoFile);
            }
        }

        $em->flush();

        $this->addFlash('success', 'Parametres mis a jour.');

        return $this->redirectToRoute('app_account', ['tab' => 'settings']);
    }

    /** @codeCoverageIgnore Requires live Stripe API */
    #[Route('/mon-compte/abonnement', name: 'app_account_billing_subscribe')]
    public function billingSubscribe(StripeService $stripeService, EntityManagerInterface $em): Response
    {
        /** @var User $user */
        $user = $this->getUser();

        if (!$this->isGranted('ROLE_ORGANIZER') || !$user->isBilling() || 'poor' !== $user->getBillingState()) {
            return $this->redirectToRoute('app_account');
        }

        try {
            $url = $stripeService->createBillingCheckoutSession($user);

            return $this->redirect($url);
        } catch (\Throwable $e) {
            $this->addFlash('error', 'Erreur lors de la creation de l\'abonnement : '.$e->getMessage());

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

    /** @codeCoverageIgnore Stripe checkout callback */
    #[Route('/mon-compte/abonnement/succes', name: 'app_account_billing_success')]
    public function billingSuccess(): Response
    {
        $this->addFlash('success', 'Votre abonnement a ete active avec succes.');

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

    /** @codeCoverageIgnore Requires live Stripe API */
    #[Route('/mon-compte/stripe-connect', name: 'app_account_stripe_connect')]
    public function stripeConnect(StripeService $stripeService, EntityManagerInterface $em): Response
    {
        /** @var User $user */
        $user = $this->getUser();

        if (!$this->isGranted('ROLE_ORGANIZER') || ($user->isBilling() && 'good' !== $user->getBillingState())) {
            return $this->redirectToRoute('app_account');
        }

        try {
            if (!$user->getStripeAccountId()) {
                $accountId = $stripeService->createAccountConnect($user);
                $user->setStripeAccountId($accountId);
                $user->setStripeStatus('started');
                $em->flush();
            }

            $link = $stripeService->createAccountLink($user->getStripeAccountId());

            return $this->redirect($link);
        } catch (\Throwable $e) {
            $this->addFlash('error', 'Erreur lors de la connexion a Stripe : '.$e->getMessage());

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

    /** @codeCoverageIgnore Requires live Stripe API */
    #[Route('/mon-compte/stripe-cancel', name: 'app_account_stripe_cancel', methods: ['POST'])]
    public function stripeCancel(StripeService $stripeService, EntityManagerInterface $em): Response
    {
        /** @var User $user */
        $user = $this->getUser();

        if ($this->isGranted('ROLE_ORGANIZER') && $user->getStripeAccountId()) {
            try {
                $stripeService->deleteAccount($user->getStripeAccountId());
            } catch (\Throwable) {
                // Account may already be deleted on Stripe side
            }

            $user->setStripeAccountId(null);
            $user->setStripeChargesEnabled(false);
            $user->setStripePayoutsEnabled(false);
            $em->flush();

            $this->addFlash('success', 'Compte Stripe cloture.');
        }

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

    /** @codeCoverageIgnore Stripe redirect callback */
    #[Route('/stripe/connect/return', name: 'app_stripe_connect_return')]
    public function stripeConnectReturn(): Response
    {
        $this->addFlash('success', 'Configuration Stripe terminee.');

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

    /** @codeCoverageIgnore Stripe redirect callback */
    #[Route('/stripe/connect/refresh', name: 'app_stripe_connect_refresh')]
    public function stripeConnectRefresh(): Response
    {
        return $this->redirectToRoute('app_account_stripe_connect');
    }

    #[Route('/mon-compte/sous-compte/creer', name: 'app_account_create_subaccount', methods: ['POST'])]
    public function createSubAccount(Request $request, EntityManagerInterface $em, UserPasswordHasherInterface $passwordHasher, MailerService $mailerService): Response
    {
        /** @var User $user */
        $user = $this->getUser();

        if (!$this->isGranted('ROLE_ORGANIZER')) {
            return $this->redirectToRoute('app_account');
        }

        $plainPassword = bin2hex(random_bytes(8));

        $subAccount = new User();
        $subAccount->setFirstName(trim($request->request->getString('first_name')));
        $subAccount->setLastName(trim($request->request->getString('last_name')));
        $subAccount->setEmail(trim($request->request->getString('email')));
        $subAccount->setPassword($passwordHasher->hashPassword($subAccount, $plainPassword));
        $subAccount->setIsVerified(true);
        $subAccount->setEmailVerifiedAt(new \DateTimeImmutable());
        $subAccount->setParentOrganizer($user);

        $permissions = $request->request->all('permissions');
        $subAccount->setSubAccountPermissions($permissions);

        $em->persist($subAccount);
        $em->flush();

        $mailerService->sendEmail(
            to: $subAccount->getEmail(),
            subject: 'Votre sous-compte E-Ticket a ete cree',
            content: $this->renderView('email/subaccount_created.html.twig', [
                'firstName' => $subAccount->getFirstName(),
                'organizerName' => $user->getCompanyName() ?? $user->getFirstName().' '.$user->getLastName(),
                'email' => $subAccount->getEmail(),
                'password' => $plainPassword,
                'permissions' => $permissions,
            ]),
            withUnsubscribe: false,
        );

        $this->addFlash('success', sprintf('Sous-compte %s %s cree.', $subAccount->getFirstName(), $subAccount->getLastName()));

        return $this->redirectToRoute('app_account', ['tab' => 'subaccounts']);
    }

    #[Route('/mon-compte/sous-compte/{id}', name: 'app_account_edit_subaccount_page', methods: ['GET'])]
    public function editSubAccountPage(User $subAccount): Response
    {
        /** @var User $user */
        $user = $this->getUser();

        if ($subAccount->getParentOrganizer()?->getId() !== $user->getId()) {
            throw $this->createAccessDeniedException();
        }

        return $this->render('account/edit_subaccount.html.twig', [
            'subAccount' => $subAccount,
            'breadcrumbs' => [
                self::BREADCRUMB_HOME,
                self::BREADCRUMB_ACCOUNT,
                ['name' => 'Sous-compte', 'url' => self::BREADCRUMB_ACCOUNT['url'].'/sous-compte/'.$subAccount->getId()],
            ],
        ]);
    }

    #[Route('/mon-compte/sous-compte/{id}/modifier', name: 'app_account_edit_subaccount', methods: ['POST'])]
    public function editSubAccount(User $subAccount, Request $request, EntityManagerInterface $em): Response
    {
        /** @var User $user */
        $user = $this->getUser();

        if ($subAccount->getParentOrganizer()?->getId() !== $user->getId()) {
            throw $this->createAccessDeniedException();
        }

        $permissions = $request->request->all('permissions');
        $subAccount->setSubAccountPermissions($permissions);
        $subAccount->setFirstName(trim($request->request->getString('first_name')));
        $subAccount->setLastName(trim($request->request->getString('last_name')));
        $subAccount->setEmail(trim($request->request->getString('email')));
        $em->flush();

        $this->addFlash('success', sprintf('Sous-compte %s %s mis a jour.', $subAccount->getFirstName(), $subAccount->getLastName()));

        return $this->redirectToRoute('app_account', ['tab' => 'subaccounts']);
    }

    #[Route('/mon-compte/sous-compte/{id}/supprimer', name: 'app_account_delete_subaccount', methods: ['POST'])]
    public function deleteSubAccount(User $subAccount, EntityManagerInterface $em): Response
    {
        /** @var User $user */
        $user = $this->getUser();

        if ($subAccount->getParentOrganizer()?->getId() !== $user->getId()) {
            throw $this->createAccessDeniedException();
        }

        $name = sprintf('%s %s', $subAccount->getFirstName(), $subAccount->getLastName());
        $em->remove($subAccount);
        $em->flush();

        $this->addFlash('success', sprintf('Sous-compte %s supprime.', $name));

        return $this->redirectToRoute('app_account', ['tab' => 'subaccounts']);
    }

    #[Route('/mon-compte/evenement/creer', name: 'app_account_create_event', methods: ['GET', 'POST'])]
    public function createEvent(Request $request, EntityManagerInterface $em, EventIndexService $eventIndex, AuditService $audit): Response
    {
        $this->denyAccessUnlessGranted('ROLE_ORGANIZER');
        if ($redirect = $this->requireStripeReady()) { // @codeCoverageIgnoreStart
            return $redirect;
        } // @codeCoverageIgnoreEnd

        /** @var User $user */
        $user = $this->getUser();

        if ($request->isMethod('POST')) {
            $event = new Event();
            $event->setAccount($user);
            $this->hydrateEventFromRequest($event, $request);

            $em->persist($event);
            $em->flush();

            $eventIndex->indexEvent($event);

            $audit->log('event_created', 'Event', $event->getId(), ['title' => $event->getTitle()]);

            $this->addFlash('success', 'Evenement cree avec succes.');

            return $this->redirectToRoute('app_account', ['tab' => 'events']);
        }

        return $this->render('account/create_event.html.twig', [
            'breadcrumbs' => [
                self::BREADCRUMB_HOME,
                self::BREADCRUMB_ACCOUNT,
                ['name' => 'Creer un evenement', 'url' => '/mon-compte/evenement/creer'],
            ],
        ]);
    }

    #[Route('/mon-compte/evenement/{id}/modifier', name: 'app_account_edit_event', methods: ['GET', 'POST'])]
    public function editEvent(Event $event, Request $request, EntityManagerInterface $em, EventIndexService $eventIndex, PaginatorInterface $paginator, OrderIndexService $orderIndex, AuditService $audit): Response
    {
        $this->denyAccessUnlessGranted('ROLE_ORGANIZER');
        if ($redirect = $this->requireStripeReady()) { // @codeCoverageIgnoreStart
            return $redirect;
        } // @codeCoverageIgnoreEnd

        $user = $this->requireEventOwnership($event);

        if ($request->isMethod('POST')) {
            $this->hydrateEventFromRequest($event, $request);

            $em->flush();

            $eventIndex->indexEvent($event);

            $audit->log('event_updated', 'Event', $event->getId(), ['title' => $event->getTitle()]);

            $this->addFlash('success', 'Evenement modifie avec succes.');

            return $this->redirectToRoute('app_account_edit_event', ['id' => $event->getId()]);
        }

        $categories = $em->getRepository(Category::class)->findBy(
            ['event' => $event],
            ['position' => 'ASC'],
        );

        $allBillets = $em->getRepository(Billet::class)->findBy(['category' => $categories], ['position' => 'ASC']);

        $billets = [];
        $billetIds = [];
        foreach ($allBillets as $billet) {
            $catId = $billet->getCategory()->getId();
            $billets[$catId][] = $billet;
            $billetIds[] = $billet->getId();
        }

        $soldCounts = [];
        if ($billetIds) {
            $rows = $em->createQueryBuilder()
                ->select('IDENTITY(bo.billet) AS billetId, COUNT(bo.id) AS cnt')
                ->from(BilletOrder::class, 'bo')
                ->join('bo.billetBuyer', 'bb')
                ->where('bo.billet IN (:ids)')
                ->andWhere(self::DQL_BB_EXCLUDE_INVITATIONS)
                ->setParameter('ids', $billetIds)
                ->groupBy('bo.billet')
                ->getQuery()
                ->getArrayResult();

            foreach ($rows as $row) {
                $soldCounts[$row['billetId']] = (int) $row['cnt'];
            }
        }

        $searchQuery = $request->query->getString('q', '');
        $ordersQuery = '' !== $searchQuery
            ? $orderIndex->searchOrders($event->getId(), $searchQuery)
            : $em->getRepository(BilletBuyer::class)->findBy(['event' => $event], ['createdAt' => 'DESC']);
        $eventOrders = $paginator->paginate($ordersQuery, $request->query->getInt('page', 1), 20);

        $ticketsSearchQuery = $request->query->getString('tq', '');
        $ticketsQb = $em->createQueryBuilder()
            ->select('t', 'bb')
            ->from(BilletOrder::class, 't')
            ->join('t.billetBuyer', 'bb')
            ->where('bb.event = :ticketEvent')
            ->setParameter('ticketEvent', $event)
            ->orderBy('t.createdAt', 'DESC');

        if ('' !== $ticketsSearchQuery) {
            $ticketsQb->andWhere('t.reference LIKE :tq OR t.securityKey LIKE :tq OR t.billetName LIKE :tq OR bb.firstName LIKE :tq OR bb.lastName LIKE :tq OR bb.email LIKE :tq')
                ->setParameter('tq', '%'.$ticketsSearchQuery.'%');
        }

        $eventTickets = $paginator->paginate($ticketsQb->getQuery(), $request->query->getInt('tp', 1), 20);

        $paidEventOrders = $em->createQueryBuilder()
            ->select('o', 'i')
            ->from(BilletBuyer::class, 'o')
            ->leftJoin('o.items', 'i')
            ->where('o.event = :event')
            ->andWhere('o.status = :status')
            ->andWhere(self::DQL_EXCLUDE_INVITATIONS)
            ->setParameter('event', $event)
            ->setParameter('status', BilletBuyer::STATUS_PAID)
            ->getQuery()
            ->getResult();
        $eventStats = $this->computeEventStats($paidEventOrders);

        return $this->render('account/edit_event.html.twig', [
            'event' => $event,
            'owner' => $user,
            'categories' => $categories,
            'billets' => $billets,
            'sold_counts' => $soldCounts,
            'commission_rate' => $user->getCommissionRate() ?? 0,
            'stripe_fee_rate' => (float) $this->getParameter('stripe_fee_rate'),
            'stripe_fee_fixed' => (int) $this->getParameter('stripe_fee_fixed'),
            'billet_design' => $em->getRepository(BilletDesign::class)->findOneBy(['event' => $event]),
            'event_orders' => $eventOrders,
            'event_tickets' => $eventTickets,
            'tickets_search_query' => $ticketsSearchQuery,
            'invitations' => $em->getRepository(BilletBuyer::class)->findBy(['event' => $event, 'isInvitation' => true], ['createdAt' => 'DESC']),
            'event_total_ht' => $eventStats['totalHT'] / 100,
            'event_total_sold' => $eventStats['totalSold'],
            'event_total_orders' => \count($paidEventOrders),
            'billet_stats' => $eventStats['billetStats'],
            'search_query' => $searchQuery,
            'breadcrumbs' => [
                self::BREADCRUMB_HOME,
                self::BREADCRUMB_ACCOUNT,
                ['name' => $event->getTitle(), 'url' => self::EVENT_BASE_URL.$event->getId().'/modifier'],
            ],
        ]);
    }

    #[Route('/mon-compte/evenement/{id}/supprimer', name: 'app_account_delete_event', methods: ['POST'])]
    public function deleteEvent(Event $event, EntityManagerInterface $em, EventIndexService $eventIndex, AuditService $audit): Response
    {
        $this->denyAccessUnlessGranted('ROLE_ORGANIZER');
        if ($redirect = $this->requireStripeReady()) { // @codeCoverageIgnoreStart
            return $redirect;
        } // @codeCoverageIgnoreEnd

        $this->requireEventOwnership($event);

        $eventTitle = $event->getTitle();
        $eventDbId = $event->getId();
        $eventIndex->removeEvent($event);

        $em->remove($event);
        $em->flush();

        $audit->log('event_deleted', 'Event', $eventDbId, ['title' => $eventTitle]);

        $this->addFlash('success', 'Evenement supprime.');

        return $this->redirectToRoute('app_account', ['tab' => 'events']);
    }

    /** @codeCoverageIgnore Test helper, not used in production */
    #[Route('/mon-compte/test-payout', name: 'app_account_test_payout', methods: ['POST'])]
    public function testPayout(EntityManagerInterface $em): Response
    {
        /** @var User $user */
        $user = $this->getUser();

        if (!$this->isGranted('ROLE_ORGANIZER') || !$user->getStripeAccountId()) {
            return $this->redirectToRoute('app_account');
        }

        $payout = new Payout();
        $payout->setOrganizer($user);
        $payout->setStripePayoutId('po_test_'.bin2hex(random_bytes(8)));
        $payout->setStatus('paid');
        $payout->setAmount(random_int(1000, 50000));
        $payout->setCurrency('eur');
        $payout->setDestination('ba_test_bank');
        $payout->setStripeAccountId($user->getStripeAccountId());
        $payout->setArrivalDate(new \DateTimeImmutable('+2 days'));

        $em->persist($payout);
        $em->flush();

        $this->addFlash('success', sprintf('Payout test cree : %s (%.2f EUR)', $payout->getStripePayoutId(), $payout->getAmountDecimal()));

        return $this->redirectToRoute('app_account', ['tab' => 'payouts']);
    }

    /** @codeCoverageIgnore Requires live Stripe API */
    #[Route('/mon-compte/stripe-dashboard', name: 'app_account_stripe_dashboard')]
    public function stripeDashboard(StripeService $stripeService): Response
    {
        /** @var User $user */
        $user = $this->getUser();

        if (!$this->isGranted('ROLE_ORGANIZER') || !$user->getStripeAccountId()) {
            return $this->redirectToRoute('app_account');
        }

        try {
            $link = $stripeService->createLoginLink($user->getStripeAccountId());

            return $this->redirect($link);
        } catch (\Throwable $e) {
            $this->addFlash('error', 'Erreur Stripe : '.$e->getMessage());

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

    /**
     * @param list<BilletBuyer> $paidOrders
     *
     * @return array{totalHT: int, totalSold: int, billetStats: array<int, array{name: string, sold: int, revenue: int}>}
     */
    private function computeEventStats(array $paidOrders): array
    {
        $totalHT = 0;
        $totalSold = 0;
        $billetStats = [];

        foreach ($paidOrders as $order) {
            $totalHT += $order->getTotalHT();
            foreach ($order->getItems() as $item) {
                $totalSold += $item->getQuantity();
                $billetId = $item->getBillet()?->getId();
                if (!$billetId) { // @codeCoverageIgnore
                    continue; // @codeCoverageIgnore
                } // @codeCoverageIgnore
                if (!isset($billetStats[$billetId])) {
                    $billetStats[$billetId] = ['name' => $item->getBilletName(), 'sold' => 0, 'revenue' => 0];
                }
                $billetStats[$billetId]['sold'] += $item->getQuantity();
                $billetStats[$billetId]['revenue'] += $item->getLineTotalHT();
            }
        }

        return ['totalHT' => $totalHT, 'totalSold' => $totalSold, 'billetStats' => $billetStats];
    }

    private function hydrateEventFromRequest(Event $event, Request $request): void
    {
        $event->setTitle(trim($request->request->getString('title')));
        $event->setDescription(trim($request->request->getString('description')) ?: null);
        $event->setStartAt(new \DateTimeImmutable($request->request->getString('start_at')));
        $event->setEndAt(new \DateTimeImmutable($request->request->getString('end_at')));
        $event->setAddress(trim($request->request->getString('address')));
        $event->setZipcode(trim($request->request->getString('zipcode')));
        $event->setCity(trim($request->request->getString('city')));

        $pictureFile = $request->files->get('event_main_picture');
        if ($pictureFile) {
            $event->setEventMainPictureFile($pictureFile);
        }
    }

    /**
     * @return array{paid: float, pending: float, refunded: float, cancelled: float, commissionEticket: float, commissionStripe: float, net: float}
     */
    private function computeFinanceStats(User $user, EntityManagerInterface $em): array
    {
        $stats = ['paid' => 0, 'pending' => 0, 'refunded' => 0, 'cancelled' => 0, 'commissionEticket' => 0, 'commissionStripe' => 0, 'net' => 0];

        $orgaOrders = $em->createQueryBuilder()
            ->select('o')
            ->from(BilletBuyer::class, 'o')
            ->join('o.event', 'e')
            ->where('e.account = :user')
            ->andWhere(self::DQL_EXCLUDE_INVITATIONS)
            ->setParameter('user', $user)
            ->getQuery()
            ->getResult();

        $rate = $user->getCommissionRate() ?? 3;
        $stripeFeeRate = (float) $this->getParameter('stripe_fee_rate');
        $stripeFeeFixed = (int) $this->getParameter('stripe_fee_fixed');

        $statusMap = [
            BilletBuyer::STATUS_PENDING => 'pending',
            BilletBuyer::STATUS_REFUNDED => 'refunded',
            BilletBuyer::STATUS_CANCELLED => 'cancelled',
        ];

        foreach ($orgaOrders as $o) {
            $ht = $o->getTotalHT() / 100;
            $status = $o->getStatus();

            if (BilletBuyer::STATUS_PAID === $status) {
                $stats['paid'] += $ht;
                $stats['commissionEticket'] += $ht * ($rate / 100);
                $stats['commissionStripe'] += $ht * $stripeFeeRate + $stripeFeeFixed / 100;
            } elseif (isset($statusMap[$status])) {
                $stats[$statusMap[$status]] += $ht;
            }
        }

        $stats['net'] = $stats['paid'] - $stats['commissionEticket'] - $stats['commissionStripe'];

        return $stats;
    }
}
