<?php

/*
 * This file is part of the VitiCore 2.
 *
 * (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\Behavior\HasPayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\AxeptaPayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\CawlPayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\EtransactionsPayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\MoneticoPayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\PayPlugPayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\Sherlock2Payment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\SogeCommercePayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\StripePayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\StripePaymentStateSynchronizer;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment\SystemPayPayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Tracking\MatomoEcommerceTracker;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Tracking\MetaConversionsApiTracker;
use CpCreation\VitiCore\Cart\Model\Cart;
use CpCreation\VitiCore\Cart\Repository\CartRepository;
use CpCreation\VitiCore\Payment\Model\Payment;
use OnlinePayments\Sdk\Domain\GetHostedCheckoutResponse;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Attribute\ValueResolver;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\Translation\LocaleAwareInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

final class MethodPaymentController extends AbstractController
{
    public function __construct(
        private readonly EtransactionsPayment $etransactionsPayment,
        private readonly array $sherlockDir,
        private readonly MoneticoPayment $moneticoPayment,
        private readonly SystemPayPayment $systempay,
        private readonly SogeCommercePayment $sogeCommercePayment,
        private readonly AxeptaPayment $axeptaPayment,
        private readonly Sherlock2Payment $sherlock2Payment,
        private readonly PayPlugPayment $payPlugPayment,
        private readonly StripePayment $stripePayment,
        private readonly StripePaymentStateSynchronizer $stripePaymentStateSynchronizer,
        private readonly TranslatorInterface $translator,
        private readonly RequestStack $requestStack,
        private readonly ParameterBagInterface $parameterBag,
        private readonly CawlPayment $cawlPayment,
        private readonly CartRepository $cartRepository,
        private readonly MatomoEcommerceTracker $matomoEcommerceTracker,
        private readonly MetaConversionsApiTracker $metaConversionsApiTracker,
    ) {
    }

    private function getSession(): ?SessionInterface
    {
        return $this->requestStack->getSession();
    }

    private function isStandalonePaymentFlow(): bool
    {
        return 'Payment' === $this->getSession()?->get('payment');
    }

    private function redirectCheckoutWithFlash(string $level, string $message): RedirectResponse
    {
        $this->addFlash($level, $message);

        $cartId = $this->resolveReturnCartId();

        if (null !== $cartId) {
            return $this->redirectToRoute('shop_checkout_cart', [
                '_locale' => $this->resolveReturnLocale(),
                'cartId' => $cartId,
            ]);
        }

        return $this->redirectToRoute('shop_checkout', $this->resolveReturnLocaleParameters());
    }

    private function redirectCheckoutSuccess(): RedirectResponse
    {
        $cartId = $this->resolveReturnCartId();

        if (null === $cartId) {
            return $this->redirectToRoute('shop_checkout', $this->resolveReturnLocaleParameters());
        }

        $cart = $this->resolveReturnCart();
        if (!$cart instanceof Cart || !$cart->isCheckoutPayed()) {
            $this->clearReturnCartSession((string) $cartId);

            return $this->redirectToRoute('shop_checkout_payment_pending', [
                '_locale' => $this->resolveReturnLocale(),
                'cartId' => (string) $cartId,
                'startedAt' => time(),
            ]);
        }

        $this->clearReturnCartSession((string) $cartId);

        return $this->redirectToRoute('shop_checkout_success', [
            '_locale' => $this->resolveReturnLocale(),
            'cartId' => (string) $cartId,
        ]);
    }

    private function clearReturnCartSession(string $cartId): void
    {
        $sessionCartId = $this->getSession()?->get('cart');

        if ((\is_scalar($sessionCartId) || $sessionCartId instanceof \Stringable) && (string) $sessionCartId === $cartId) {
            $this->getSession()?->remove('cart');
        }
    }

    private function resolveReturnCartId(): ?string
    {
        $request = $this->requestStack->getCurrentRequest() ?? $this->requestStack->getMainRequest();
        $cartId = $request?->get('cartId');

        if (\is_string($cartId) && '' !== $cartId) {
            return $cartId;
        }

        $sessionCartId = $this->getSession()?->get('cart');

        return \is_string($sessionCartId) && '' !== $sessionCartId ? $sessionCartId : null;
    }

    private function resolveReturnCart(): ?Cart
    {
        $cartId = $this->resolveReturnCartId();

        if (null === $cartId) {
            return null;
        }

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

        return $cart instanceof Cart ? $cart : null;
    }

    private function resolveReturnLocale(): string
    {
        $request = $this->requestStack->getCurrentRequest() ?? $this->requestStack->getMainRequest();
        $cart = $this->resolveReturnCart();
        if ($cart instanceof Cart && '' !== $cart->getLocale()) {
            return $this->applyLocale($cart->getLocale(), $request);
        }

        $locale = $request?->getLocale();

        if (\is_string($locale) && '' !== $locale) {
            return $this->applyLocale($locale, $request);
        }

        $sessionLocale = $this->getSession()?->get('_locale');

        if (\is_string($sessionLocale) && '' !== $sessionLocale) {
            return $this->applyLocale($sessionLocale, $request);
        }

        return $this->applyLocale('fr', $request);
    }

    /**
     * @return array{_locale: string}
     */
    private function resolveReturnLocaleParameters(): array
    {
        return [
            '_locale' => $this->resolveReturnLocale(),
        ];
    }

    private function renderLegacyPaymentReturn(string $message, ?string $error = null): Response
    {
        return $this->render('payment/payment_return.html.twig', [
            'msg' => $message,
            'error' => $error,
        ]);
    }

    private function respondToPendingPaymentReturn(Request $request): Response
    {
        if (!$this->isStandalonePaymentFlow()) {
            $locale = $this->resolveReturnLocale();
            $this->addFlash('warning', $this->translator->trans('checkout_design.payment_confirmation_pending'));

            $cartId = $this->resolveReturnCartId();
            $sessionId = $request->get('session_id');
            $parameters = [
                '_locale' => $locale,
            ];

            if (\is_string($sessionId) && str_starts_with($sessionId, 'cs_')) {
                $parameters['stripeSessionId'] = $sessionId;
            }

            if (null !== $cartId) {
                return $this->redirectToRoute('shop_checkout_payment_pending', [
                    'cartId' => $cartId,
                    'startedAt' => time(),
                    ...$parameters,
                ]);
            }

            $parameters['paymentPending'] = 1;

            return $this->redirectToRoute('shop_checkout', $parameters);
        }

        return $this->renderLegacyPaymentReturn(
            $this->translator->trans('checkout_design.payment_return'),
            $this->translator->trans('checkout_design.payment_confirmation_pending')
        );
    }

    private function buildCartReturnMessage(string $status, ?string $reason = null): string
    {
        if ('success' === $status) {
            return $this->translator->trans('shop.return.success');
        }

        $key = 'shop.return.'.$status;
        if (null !== $reason) {
            $key .= '_with_reason';

            return $this->translator->trans($key, ['%reason%' => $reason]);
        }

        return $this->translator->trans($key);
    }

    /**
     * @return array{msg: string, error: ?string}
     */
    private function buildLegacyPaymentReturnPayload(string $status, ?string $reason = null): array
    {
        return match ($status) {
            'success' => [
                'msg' => $this->translator->trans('payment.success'),
                'error' => null,
            ],
            'canceled' => [
                'msg' => $this->translator->trans('payment.canceled'),
                'error' => $reason,
            ],
            default => [
                'msg' => $this->translator->trans('payment.refused'),
                'error' => $reason ?? $this->translator->trans('payment.error'),
            ],
        };
    }

    private function respondToPaymentReturn(string $status, ?string $reason = null): Response
    {
        $this->resolveReturnLocale();

        $level = match ($status) {
            'success' => 'success',
            'canceled' => 'warning',
            default => 'error',
        };

        if ('success' !== $status) {
            $trackedCart = $this->recordCartPaymentReturn($status, $reason);
            if ($trackedCart instanceof Cart) {
                $this->trackPaymentReturn($trackedCart, $status);
            }
            $this->releaseCheckoutReservation();
        }

        if (!$this->isStandalonePaymentFlow()) {
            if ('success' === $status) {
                return $this->redirectCheckoutSuccess();
            }

            return $this->redirectCheckoutWithFlash($level, $this->buildCartReturnMessage($status, $reason));
        }

        $payload = $this->buildLegacyPaymentReturnPayload($status, $reason);

        return $this->renderLegacyPaymentReturn($payload['msg'], $payload['error']);
    }

    private function releaseCheckoutReservation(): void
    {
        if ($this->isStandalonePaymentFlow()) {
            return;
        }

        $cart = $this->resolveReturnCart();

        if (!$cart instanceof Cart) {
            return;
        }

        $checkout = $cart->getCartCheckout();

        if (null === $checkout || null !== $checkout->getPayedAt() || null === $checkout->getInitiatedAt()) {
            return;
        }

        $checkout->setInitiatedAt(null);
        $this->cartRepository->save($cart);
    }

    private function recordCartPaymentReturn(string $status, ?string $reason = null): ?Cart
    {
        if ($this->isStandalonePaymentFlow()) {
            return null;
        }

        $cart = $this->resolveReturnCart();

        if (!$cart instanceof Cart) {
            return null;
        }

        $checkout = $cart->getCartCheckout();

        if (null === $checkout || null !== $checkout->getPayedAt()) {
            return null;
        }

        $request = $this->requestStack->getCurrentRequest() ?? $this->requestStack->getMainRequest();
        $response = $checkout->getResponse() ?? [];
        $previousPaymentReturn = \is_array($response['payment_return'] ?? null) ? $response['payment_return'] : [];
        if (($previousPaymentReturn['status'] ?? null) === $status) {
            return null;
        }

        $checkout->setResponse(array_replace_recursive($response, [
            'payment_return' => array_filter([
                'status' => $status,
                'reason' => $reason,
                'captured_at' => (new \DateTimeImmutable())->format(\DateTimeInterface::ATOM),
                'query' => $request?->query->all() ?? [],
                'request' => $request?->request->all() ?? [],
            ], static fn (mixed $value): bool => null !== $value),
        ]));

        $this->cartRepository->save($cart);

        return $cart;
    }

    private function trackPaymentReturn(Cart $cart, string $status): void
    {
        $request = $this->requestStack->getCurrentRequest() ?? $this->requestStack->getMainRequest();

        if ('canceled' === $status) {
            $this->matomoEcommerceTracker->trackPaymentCanceled($cart, $request);
            $this->metaConversionsApiTracker->trackPaymentCanceled($cart, $request);

            return;
        }

        $this->matomoEcommerceTracker->trackPaymentFailed($cart, $request);
        $this->metaConversionsApiTracker->trackPaymentFailed($cart, $request);
    }

    private function synchronizeStripeSuccessReturn(Request $request): bool
    {
        return $this->isStandalonePaymentFlow()
            ? $this->stripePaymentStateSynchronizer->synchronizeStandaloneReturn($request)
            : $this->stripePaymentStateSynchronizer->synchronizeCartReturn($request);
    }

    /**
     * @param array<string, mixed> $context
     */
    private function extractReturnReason(Request $request, array $context = []): ?string
    {
        $this->resolveReturnLocale();

        $payload = array_replace($request->query->all(), $request->request->all(), $context);
        $keys = [
            'motifrefus',
            'reason',
            'error_description',
            'error_message',
            'vads_error_message',
            'vads_payment_error',
            'message',
            'error',
            'Status',
            'status',
            'Code',
            'Erreur',
            'vads_extra_result',
            'vads_result',
            'vads_auth_result',
            'responseCode',
            'acquirerResponseCode',
        ];

        foreach ($keys as $key) {
            if (!array_key_exists($key, $payload)) {
                continue;
            }

            $reason = $this->normalizeReturnReason($payload[$key]);
            if (null !== $reason) {
                return $reason;
            }
        }

        return null;
    }

    private function normalizeReturnReason(mixed $value): ?string
    {
        if (\is_array($value) || null === $value) {
            return null;
        }

        $reason = trim(strip_tags((string) $value));
        if ('' === $reason) {
            return null;
        }

        $normalized = mb_strtolower($reason);
        if (\in_array($normalized, [
            '00000',
            '00',
            '000',
            '001',
            'ok',
            'authorized',
            'authorised',
            'payment',
            'payetest',
            'success',
            'succeeded',
            'paid',
            'payment_created',
            'in_progress',
        ], true)) {
            return null;
        }

        if (\in_array($normalized, [
            'annulation',
            'annule',
            'annulé',
            'cancel',
            'cancelled',
            'canceled',
            'abandoned',
            'abandonne',
            'abandonné',
        ], true)) {
            return null;
        }

        $reason = preg_replace('/\s+/', ' ', $reason) ?? $reason;

        if (preg_match('/^[A-Z0-9_-]{2,}$/', $reason) || preg_match('/^\d{2,}$/', $reason)) {
            return $this->translator->trans('shop.return.reason_code', ['%code%' => $reason]);
        }

        return $reason;
    }

    /**
     * @param array<string, mixed> $context
     */
    private function isCanceledReturn(Request $request, array $context = []): bool
    {
        $payload = array_replace($request->query->all(), $request->request->all(), $context);
        $keys = [
            'code-retour',
            'reason',
            'status',
            'Status',
            'vads_trans_status',
            'vads_trans_state',
            'event',
            'error',
            'message',
        ];

        foreach ($keys as $key) {
            if (!array_key_exists($key, $payload)) {
                continue;
            }

            $value = (string) $payload[$key];
            if (preg_match('/annul|cancel|aband/i', $value)) {
                return true;
            }
        }

        return false;
    }

    #[Route('/paiement/{id}/check', name: 'payment_check')]
    public function paymentCheck(Request $request, Cart $cart): Response
    {
        $this->applyCartLocale($request, $cart);

        return $this->render('payment/check.html.twig', [
            'cart' => $cart,
        ]);
    }

    #[Route('/paiement/{id}/banktransfert', name: 'payment_banktransfert')]
    public function paymentBankTransfert(Request $request, Cart $cart): Response
    {
        $this->applyCartLocale($request, $cart);

        return $this->render('payment/banktransfert.html.twig', [
            'cart' => $cart,
        ]);
    }

    private function applyCartLocale(Request $request, Cart $cart): void
    {
        $this->applyLocale($cart->getLocale(), $request);
    }

    private function applyLocale(string $locale, ?Request $request = null): string
    {
        $locale = trim($locale);

        if ('' === $locale) {
            $locale = 'fr';
        }

        if (null !== $request) {
            $request->setLocale($locale);
            $request->attributes->set('_locale', $locale);
        }

        $this->getSession()?->set('_locale', $locale);

        if ($this->translator instanceof LocaleAwareInterface) {
            $this->translator->setLocale($locale);
        }

        return $locale;
    }

    #[Route('/paiement/{id}/etransactions', name: 'payment_cb_etransactions')]
    #[Route('/paiement/{id}/etransactions', name: 'payment_etransactions')]
    public function paymentEtransactions(
        Request $request,
        #[ValueResolver('haspayment_resolver')]
        HasPayment $payment,
    ): ?Response {
        $data = $this->etransactionsPayment->createData($payment);

        $view = 'cb.html.twig';
        $this->getSession()->set('payment', 'Cart');

        if ($payment instanceof Payment) {
            $view = 'payment.html.twig';
            $this->getSession()->set('payment', 'Payment');
        }

        return $this->render('payment/'.$view, [
            'cart' => $payment,
            'data' => $data,
        ]);
    }

    #[Route('/paiement/cb/retour', name: 'payment_cb_return')]
    public function paymentCbReturn(Request $request): Response
    {
        $code = $request->query->get('Erreur');

        if ('00000' === $code) {
            return $this->respondToPaymentReturn('success');
        }

        $reason = $this->extractReturnReason($request, ['Erreur' => $code]);
        $status = $this->isCanceledReturn($request) ? 'canceled' : 'refused';

        return $this->respondToPaymentReturn($status, $reason);
    }

    #[Route('/paiement/{id}/cb_monetico', name: 'payment_cb_monetico')]
    #[Route('/paiement/{id}/cb_monetico', name: 'payment_monetico')]
    public function paymentCbMonetico(
        Request $request,
        #[ValueResolver('haspayment_resolver')]
        HasPayment $payment,
    ): Response {
        $data = $this->moneticoPayment->createData($payment);

        $view = 'cb.html.twig';
        $this->getSession()->set('payment', 'Cart');

        if ($payment instanceof Payment) {
            $view = 'payment.html.twig';
            $this->getSession()->set('payment', 'Payment');
        }

        return $this->render('payment/'.$view, [
            'cart' => $payment,
            'data' => $data,
        ]);
    }

    #[Route('/paiement/cb/retour/erreur', name: 'payment_cb_return_error')]
    #[Route('/paiement/cb_monetico/retour/erreur', name: 'payment_cb_monetico_return_error')]
    #[Route('/paiement/cb_monetico/retour/erreur', name: 'payment_monetico_return_error')]
    #[Route('/paiement/sogecommerce/retour/erreur', name: 'payment_sogecommerce_return_error')]
    #[Route('/paiement/systempay/retour/erreur', name: 'payment_systempay_return_error')]
    #[Route('/paiement/axepta/retour/erreur', name: 'payment_axepta_return_error')]
    public function paymentCbReturnError(Request $request): Response
    {
        $reason = $this->extractReturnReason($request);
        $status = $this->isCanceledReturn($request) ? 'canceled' : 'refused';

        return $this->respondToPaymentReturn($status, $reason);
    }

    #[Route('/paiement/cb/retour/annule', name: 'payment_cb_return_canceled')]
    #[Route('/paiement/cb_monetico/retour/annule', name: 'payment_cb_monetico_return_canceled')]
    #[Route('/paiement/sogecommerce/retour/annule', name: 'payment_sogecommerce_return_canceled')]
    #[Route('/paiement/systempay/retour/annule', name: 'payment_systempay_return_canceled')]
    #[Route('/paiement/axepta/retour/annule', name: 'payment_axepta_return_canceled')]
    public function paymentCbReturnCanceled(Request $request): Response
    {
        $reason = $this->extractReturnReason($request);

        return $this->respondToPaymentReturn('canceled', $reason);
    }

    #[Route('/paiement/cb/retour/success', name: 'payment_cb_return_success')]
    #[Route('/paiement/cb_monetico/retour/success', name: 'payment_cb_monetico_return_success')]
    #[Route('/paiement/cb_monetico/retour/success', name: 'payment_monetico_return_success')]
    #[Route('/paiement/sogecommerce/retour/success', name: 'payment_sogecommerce_return_success')]
    #[Route('/paiement/systempay/retour/success', name: 'payment_systempay_return_success')]
    #[Route('/paiement/axepta/retour/success', name: 'payment_axepta_return_success')]
    public function paymentCbReturnSuccess(Request $request): Response
    {
        return $this->respondToPaymentReturn('success');
    }

    #[Route('/paiement/{id}/sherlock', name: 'payment_cb_sherlock')]
    #[Route('/paiement/{id}/sherlock', name: 'payment_sherlock')]
    public function paymentSherlock(
        Request $request,
        #[ValueResolver('haspayment_resolver')]
        HasPayment $payment,
    ): ?Response {
        $data = [];
        $params = $this->sherlockPayment->createData($payment);
        $pathBin = $this->sherlockDir['sherlock_request_path'];

        $result = exec("$pathBin $params");

        $doc = new \DOMDocument();
        $doc->loadHTML($result);

        $form = $doc->getElementsByTagName('form');
        $data['URL'] = $form->item(0)->attributes->getNamedItem('action')->textContent;

        $inputs = $form->item(0)->getElementsByTagName('input');
        for ($i = 0; $i < $inputs->length; ++$i) {
            if ('DATA' === $inputs->item($i)->attributes->getNamedItem('name')->textContent) {
                $data['DATA'] = $inputs->item($i)->attributes->getNamedItem('value')->textContent;
            }
        }

        $view = 'cb.html.twig';
        $this->getSession()->set('payment', 'Cart');

        if ($payment instanceof Payment) {
            $view = 'payment.html.twig';
            $this->getSession()->set('payment', 'Payment');
        }

        return $this->render('payment/'.$view, [
            'cart' => $payment,
            'data' => $data,
        ]);
    }

    #[Route('/paiement/{id}/cb_systempay', name: 'payment_cb_systempay')]
    #[Route('/paiement/{id}/cb_systempay', name: 'payment_systempay')]
    public function paymentSystemPay(
        Request $request,
        #[ValueResolver('haspayment_resolver')]
        HasPayment $payment,
    ): Response {
        $data = $this->systempay->createData($payment);

        $this->getSession()->set('payment', 'Cart');
        if ($payment instanceof Payment) {
            $this->getSession()->set('payment', 'Payment');
        }

        return $this->render('payment/cb.html.twig', [
            'cart' => $payment,
            'data' => $data,
        ]);
    }

    #[Route('/paiement/{id}/cb_sogecommerce', name: 'payment_cb_sogecommerce')]
    #[Route('/paiement/{id}/cb_sogecommerce', name: 'payment_sogecommerce')]
    public function paymentCbSogeCommerce(
        Request $request,
        #[ValueResolver('haspayment_resolver')]
        HasPayment $payment,
    ): Response {
        $data = $this->sogeCommercePayment->createData($payment);

        $view = 'cb.html.twig';
        $this->getSession()->set('payment', 'Cart');

        if ($payment instanceof Payment) {
            $view = 'payment.html.twig';
            $this->getSession()->set('payment', 'Payment');
        }

        return $this->render('payment/'.$view, [
            'cart' => $payment,
            'data' => $data,
        ]);
    }

    #[Route('/paiement/{id}/cb_axepta', name: 'payment_cb_axepta')]
    #[Route('/paiement/{id}/cb_axepta', name: 'payment_axepta')]
    public function paymentCbAxepta(
        Request $request,
        #[ValueResolver('haspayment_resolver')]
        HasPayment $payment,
    ): Response {
        $data = $this->axeptaPayment->createData($payment);

        $file = 'log_axepta.txt';
        $fullpath = $this->parameterBag->get('kernel.project_dir').$file;

        $log = fopen($fullpath, 'w');
        if (false !== $log) {
            $timestamp = date('Y-m-d H:i:s');
            fwrite($log, "[$timestamp] - $data".\PHP_EOL);
            fclose($log);
        }

        $view = 'cb.html.twig';
        $this->getSession()->set('payment', 'Cart');

        if ($payment instanceof Payment) {
            $view = 'payment.html.twig';
            $this->getSession()->set('payment', 'Payment');
        }

        return $this->render('payment/'.$view, [
            'cart' => $payment,
            'data' => $data,
        ]);
    }

    #[Route('/paiement/{id}/cb_sherlock2', name: 'payment_cb_sherlock2')]
    #[Route('/paiement/{id}/cb_sherlock2', name: 'payment_sherlock2')]
    public function paymentCbSherlock2(
        Request $request,
        #[ValueResolver('haspayment_resolver')]
        HasPayment $payment,
    ): Response {
        $data = $this->sherlock2Payment->createData($payment);

        $view = 'cb.html.twig';
        $this->getSession()->set('payment', 'Cart');

        if ($payment instanceof Payment) {
            $view = 'payment.html.twig';
            $this->getSession()->set('payment', 'Payment');
        }

        return $this->render('payment/'.$view, [
            'cart' => $payment,
            'data' => $data,
        ]);
    }

    #[Route('/paiement/sherlock2/retour', name: 'payment_sherlock2_normal')]
    public function paymentSherlock2Return(Request $request): Response
    {
        $response = $request->request->all();
        $data = $this->sherlock2Payment->valid($response);

        if (($data['Valid'] ?? false) === true) {
            return $this->respondToPaymentReturn('success');
        }

        $reason = $this->extractReturnReason($request, $data);

        return $this->respondToPaymentReturn('refused', $reason);
    }

    #[Route('/paiement/{id}/payplug', name: 'payment_payplug')]
    public function paymentPayPlug(
        Request $request,
        #[ValueResolver('haspayment_resolver')]
        HasPayment $payment,
    ): Response {
        $view = 'cb_payplug.html.twig';

        $form = $this->createFormBuilder()->getForm();

        return $this->render('payment/'.$view, [
            'form' => $form->createView(),
            'cart' => $payment,
        ]);
    }

    #[Route('/paiement/payplug/{id}/process', name: 'payment_payplug_process')]
    public function paymentPayPlugProcess(
        Request $request,
        #[ValueResolver('haspayment_resolver')]
        HasPayment $payment,
    ): RedirectResponse {
        $data = $this->payPlugPayment->createData($payment);

        return $this->redirect($data->hosted_payment->payment_url);
    }

    #[Route('/paiement/payplug/success', name: 'payment_payplug_success')]
    public function paymentPayPlugSuccess(Request $request): Response
    {
        return $this->respondToPaymentReturn('success');
    }

    #[Route('/paiement/payplug/error', name: 'payment_payplug_return_error')]
    public function paymentPayPlugError(Request $request): Response
    {
        $reason = $this->extractReturnReason($request);
        $status = $this->isCanceledReturn($request) ? 'canceled' : 'refused';

        return $this->respondToPaymentReturn($status, $reason);
    }

    #[Route('/paiement/{id}/stripe', name: 'payment_stripe')]
    public function paymentStripe(
        Request $request,
        #[ValueResolver('haspayment_resolver')]
        HasPayment $payment,
    ): RedirectResponse {
        $this->getSession()->set('payment', $payment instanceof Payment ? 'Payment' : 'Cart');
        if ($payment instanceof Payment) {
            $this->getSession()->set('payment_slug', $payment->getSlug());
        }

        $session = $this->stripePayment->createCheckoutSession($payment);
        $this->stripePaymentStateSynchronizer->persistCheckoutInitiation($payment, $session);

        return $this->redirect((string) $session->url);
    }

    #[Route('/paiement/stripe/success', name: 'payment_stripe_success')]
    public function paymentStripeSuccess(Request $request): Response
    {
        if (!$this->synchronizeStripeSuccessReturn($request)) {
            return $this->respondToPendingPaymentReturn($request);
        }

        return $this->respondToPaymentReturn('success');
    }

    #[Route('/paiement/stripe/annule', name: 'payment_stripe_return_canceled')]
    public function paymentStripeCanceled(Request $request): Response
    {
        if ($this->synchronizeStripeSuccessReturn($request)) {
            return $this->respondToPaymentReturn('success');
        }

        return $this->respondToPaymentReturn('canceled');
    }

    #[Route('/paiement/{id}/cawl', name: 'payment_cawl')]
    public function paymentCawl(
        Request $request,
        #[ValueResolver('haspayment_resolver')]
        HasPayment $payment,
    ): Response {
        $data = $this->cawlPayment->createData($payment);

        $view = 'cb_cawl.html.twig';
        $this->getSession()->set('payment', 'Cart');

        if ($payment instanceof Payment) {
            $view = 'payment.html.twig';
            $this->getSession()->set('payment', 'Payment');
        }

        return $this->render('payment/'.$view, [
            'cart' => $payment,
            'data' => $data,
        ]);
    }

    #[Route('/paiement/cawl/return', name: 'payment_cawl_return')]
    public function paymentCawlReturn(Request $request): Response
    {
        $returnData = $request->query->all();

        /** @var GetHostedCheckoutResponse $status */
        $status = $this->cawlPayment->getStatus($returnData['hostedCheckoutId']);

        if ('PAYMENT_CREATED' !== $status->status && 'IN_PROGRESS' !== $status->status) {
            $reason = $this->extractReturnReason($request, ['status' => $status->status]);
            $returnStatus = $this->isCanceledReturn($request, ['status' => $status->status]) ? 'canceled' : 'refused';

            return $this->respondToPaymentReturn($returnStatus, $reason);
        }

        return $this->respondToPaymentReturn('success');
    }
}
