<?php

declare(strict_types=1);

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Controller\Site;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Filesystem\Filesystem;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Site\Account\AccountType;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Site\Account\Model\AccountData;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Messenger\Messaging\CommandBusInterface;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Notification\Command\NotificationCommand;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Notification\Enum\PushLevel;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Utils\Pdf;
use CpCreation\VitiCore\Cart\Model\Cart;
use CpCreation\VitiCore\Cart\Model\PaymentMethod;
use CpCreation\VitiCore\Cart\Repository\CartRepository;
use CpCreation\VitiCore\Contact\Repository\ContactRepository;
use CpCreation\VitiCore\Shop\Repository\ShopConfigRepository;
use CpCreation\VitiCore\User\Model\User;
use CpCreation\VitiCore\User\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\Translation\TranslatorInterface;

final class AccountController extends AbstractController
{
    public function __construct(
        private readonly CartRepository $cartRepository,
        private readonly UserRepository $userRepository,
        private readonly EntityManagerInterface $entityManager,
        private readonly TranslatorInterface $translator,
        private readonly CommandBusInterface $commandSimpleBus,
        private readonly ShopConfigRepository $shopConfigRepository,
        private readonly ContactRepository $contactRepository,
        private readonly Filesystem $filesystem,
        private readonly Pdf $pdf,
    ) {
    }

    #[Route(path: [
        'fr' => '/mon-compte',
        'en' => '/en/my-account',
    ], name: 'app_account')]
    public function index(Request $request): Response
    {
        $this->denyAccessUnlessGranted('ROLE_USER');

        $user = $this->getUser();
        if (!$user instanceof User) {
            return $this->redirectToRoute('app_login');
        }

        $data = AccountData::fromUser($user);
        $form = $this->createForm(AccountType::class, $data);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $normalizedEmail = $this->normalizeEmail((string) $data->email);
            $existingUser = $this->userRepository->findOneBy(['email' => $normalizedEmail]);

            if (null !== $existingUser && $existingUser->getId()->toString() !== $user->getId()->toString()) {
                $form->get('email')->addError(new FormError(
                    $this->translator->trans('account_page.form.email_taken')
                ));
            }

            if (0 === $form->getErrors(true)->count()) {
                $data->email = $normalizedEmail;
                $data->applyToUser($user);

                $this->entityManager->persist($user);
                $this->entityManager->flush();

                $this->commandSimpleBus->dispatch(new NotificationCommand(
                    message: $this->translator->trans('account_page.flash.updated'),
                    level: PushLevel::SUCCESS,
                ));

                $data = AccountData::fromUser($user);
                $form = $this->createForm(AccountType::class, $data);
            }
        }

        $orders = array_map(
            fn (Cart $cart): array => [
                'cart' => $cart,
                'payment_method_label' => $this->resolvePaymentMethodLabel($cart->getPaymentMethod()),
            ],
            $this->cartRepository->findLastAccountOrdersByUser($user, 5),
        );

        return $this->render('account/index.html.twig', [
            'form' => $form->createView(),
            'orders' => $orders,
        ]);
    }

    #[Route(path: [
        'fr' => '/mon-compte/commande/{cartId}',
        'en' => '/en/my-account/order/{cartId}',
    ], name: 'app_account_order', requirements: ['cartId' => '[0-9a-fA-F-]{36}'])]
    public function order(string $cartId): Response
    {
        $this->denyAccessUnlessGranted('ROLE_USER');

        $user = $this->getUser();
        $cart = $this->cartRepository->find($cartId);

        if (!$user instanceof User || !$cart instanceof Cart || !$this->canAccessAccountOrder($cart, $user)) {
            return $this->redirectToRoute('app_account');
        }

        $documentLabel = $cart->getDocumentLabelKey();

        return $this->render('account/order.html.twig', [
            'cart' => $cart,
            'payment_method_label' => $this->resolvePaymentMethodLabel($cart->getPaymentMethod()),
            'document_label' => $documentLabel,
            'download_document_label' => $cart->getDownloadDocumentLabelKey(),
        ]);
    }

    #[Route(path: [
        'fr' => '/mon-compte/commande/{cartId}/telecharger',
        'en' => '/en/my-account/order/{cartId}/download',
    ], name: 'app_account_order_download', requirements: ['cartId' => '[0-9a-fA-F-]{36}'])]
    public function orderDownload(string $cartId): Response
    {
        $this->denyAccessUnlessGranted('ROLE_USER');

        $user = $this->getUser();
        $cart = $this->cartRepository->find($cartId);

        if (!$user instanceof User || !$cart instanceof Cart || !$this->canAccessAccountOrder($cart, $user)) {
            return $this->redirectToRoute('app_account');
        }

        $contact = $this->contactRepository->findOne();
        if (null === $contact) {
            throw $this->createNotFoundException('Aucun contact boutique configuré.');
        }

        $filename = $this->pdf->createPdfCartDocument($contact, $cart, $cart->getLocale());
        $filePath = $this->filesystem->absolutePath('order', $filename);

        return $this->file($filePath, $filename, ResponseHeaderBag::DISPOSITION_ATTACHMENT);
    }

    private function normalizeEmail(string $email): string
    {
        return mb_strtolower(mb_trim($email));
    }

    private function resolvePaymentMethodLabel(?PaymentMethod $paymentMethod): ?string
    {
        if (null === $paymentMethod) {
            return null;
        }

        $configuration = method_exists($paymentMethod, 'getConfiguration')
            ? $paymentMethod->getConfiguration()
            : [];

        $configuredName = $configuration['name'] ?? null;
        if (\is_string($configuredName) && '' !== $configuredName) {
            return $configuredName;
        }

        $method = $paymentMethod->getMethod();

        return match ($method) {
            'check' => $this->translator->trans('checkout_design.payment_check'),
            'bankTransfert', 'banktransfert' => $this->translator->trans('checkout_design.payment_banktransfert'),
            default => $paymentMethod->isPaymentOnline()
                ? $this->translator->trans('checkout_design.payment_card')
                : $method,
        };
    }

    private function canAccessAccountOrder(Cart $cart, User $user): bool
    {
        if (!$cart->getUser() instanceof User || $cart->getUser()->getId()->toString() !== $user->getId()->toString()) {
            return false;
        }

        if ($cart->isCheckoutPayed()) {
            return true;
        }

        return $cart->getCartCheckout()?->getOrderedAt() instanceof \DateTimeImmutable
            && false === ($cart->getPaymentMethod()?->isPaymentOnline() ?? true);
    }
}
