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

use CpCreation\VitiCore\Behavior\HasPayment;
use CpCreation\VitiCore\Cart\Model\Cart;
use CpCreation\VitiCore\Cart\Model\Payment\SogeCommerce;
use CpCreation\VitiCore\Cart\Repository\PaymentMethodRepository;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Serializer\SerializerInterface;

final class SogeCommercePayment
{
    public const METHOD = 'sogecommerce';
    public const DEVISE = 978;

    private array $paths = [];

    public function __construct(
        private readonly PaymentMethodRepository $paymentMethodRepository,
        private readonly SerializerInterface $serializer,
        array $paths,
        private readonly RouterInterface $router,
    ) {
        foreach ($paths as $path) {
            if (($path['name'] ?? null) === self::METHOD) {
                // On stocke UNIQUEMENT la config sogecommerce, et on l’indexe par son name
                $this->paths[self::METHOD] = $path;
                break;
            }
        }
    }

    public function createData(HasPayment $payment): array
    {
        $paymentMethod = $this->paymentMethodRepository->findOneBy(['method' => self::METHOD]);

        /** @var SogeCommerce $config */
        $config = $this->serializer->denormalize($paymentMethod->getConfiguration(), SogeCommerce::class);

        $hmac = $config->getKey();
        $hmacAlgo = $config->getHmacAlgo();

        $returnParameters = $this->buildReturnParameters($payment);

        $data = [];
        $data['URL'] = 'https://sogecommerce.societegenerale.eu/vads-payment/';
        $data['vads_action_mode'] = 'INTERACTIVE';
        $data['vads_amount'] = $payment->getTotal();
        $data['vads_ctx_mode'] = $config->getMode();
        $data['vads_currency'] = '978';
        $data['vads_page_action'] = 'PAYMENT';
        $data['vads_payment_config'] = 'SINGLE';
        $data['vads_threeds_mpi'] = 4;
        $data['vads_site_id'] = $config->getSiteId();
        $data['vads_trans_date'] = gmdate('YmdHis');
        $data['vads_trans_id'] = $payment->getToken();

        // Symfony 7: URLs absolues via RouterInterface::ABSOLUTE_URL
        $data['vads_url_cancel'] = $this->router->generate(
            $this->paths[self::METHOD]['canceled'],
            $returnParameters,
            UrlGeneratorInterface::ABSOLUTE_URL
        ); // Annulé

        $data['vads_url_return'] = $this->router->generate(
            $this->paths[self::METHOD]['canceled'],
            $returnParameters,
            UrlGeneratorInterface::ABSOLUTE_URL
        ); // Retour boutique

        $data['vads_url_success'] = $this->router->generate(
            $this->paths[self::METHOD]['done'],
            $returnParameters,
            UrlGeneratorInterface::ABSOLUTE_URL
        ); // Paiement validé

        $data['vads_url_check'] = $this->router->generate(
            $this->paths[self::METHOD]['response_at'],
            [],
            UrlGeneratorInterface::ABSOLUTE_URL
        ); // Réponse serveur

        $data['vads_version'] = 'V2';

        // Message "à l'ancienne" conservé pour minimiser les changements
        $msg = $data['vads_action_mode'].'+'.
            $data['vads_amount'].'+'.
            $data['vads_ctx_mode'].'+'.
            $data['vads_currency'].'+'.
            $data['vads_page_action'].'+'.
            $data['vads_payment_config'].'+'.
            $data['vads_site_id'].'+'.
            $data['vads_trans_date'].'+'.
            $data['vads_trans_id'].'+'.
            $data['vads_url_cancel'].'+'.
            $data['vads_url_check'].'+'.
            $data['vads_url_return'].'+'.
            $data['vads_url_success'].'+'.
            $data['vads_version'].'+'.
            $hmac;

        $signature = hash_hmac($hmacAlgo, $msg, $hmac);
        if ('sha256' === $hmacAlgo) {
            $signature = base64_encode(hash_hmac($hmacAlgo, $msg, $hmac, true));
        }
        $data['signature'] = $signature;

        return $data;
    }

    /**
     * @return array<string, string>
     */
    private function buildReturnParameters(HasPayment $payment): array
    {
        if ($payment instanceof Cart) {
            return ['cartId' => $payment->getId()->toString()];
        }

        return [];
    }

    public function valid(?array $response = null): bool
    {
        if (
            !\is_array($response)
            || !isset($response['vads_hash'], $response['vads_auth_result'], $response['signature'])
        ) {
            return false;
        }

        $auth = (string) $response['vads_auth_result'];
        if (!\in_array($auth, ['00', '08', '000', '001'], true)) {
            return false;
        }

        $paymentMethod = $this->paymentMethodRepository->findOneBy(['method' => self::METHOD]);

        /** @var SogeCommerce $config */
        $config = $this->serializer->denormalize($paymentMethod->getConfiguration(), SogeCommerce::class);

        $hmac = $config->getKey();
        $hmacAlgo = $config->getHmacAlgo();
        $signature = (string) $response['signature'];

        ksort($response);

        $msg = '';
        foreach ($response as $nom => $valeur) {
            if (str_starts_with((string) $nom, 'vads_')) {
                $msg .= (string) $valeur.'+';
            }
        }
        $msg .= $hmac;

        $signatureNew = hash_hmac($hmacAlgo, $msg, $hmac);
        if ('sha256' === $hmacAlgo) {
            $signatureNew = base64_encode(hash_hmac($hmacAlgo, $msg, $hmac, true));
        }

        return hash_equals($signatureNew, $signature);
    }
}
