<?php
/**
 * @author Colinet Julien
 */

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Payment;

use CpCreation\VitiCore\Behavior\HasPayment;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Utils\Mailer;
use CpCreation\VitiCore\Cart\Model\Payment\Monetico;
use CpCreation\VitiCore\Cart\Repository\PaymentMethodRepository;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Serializer\SerializerInterface;

class MoneticoPayment
{
    const METHOD             = 'monetico';
    const TEST_URL           = 'https://p.monetico-services.com/test/paiement.cgi';
    const PROD_URL           = 'https://p.monetico-services.com/paiement.cgi';
    const DEVISE             = 'EUR';
    const OPTIONS            = '';
    const CTLHMAC            = 'V4.0.sha1.php--[CtlHmac%s%s]-%s';
    const CTLHMACSTR         = 'CtlHmac%s%s';
    const PHASE2BACK_RECEIPT = 'version=2\ncdr=%s';
    const PHASE2BACK_FIELDS  = '%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*%s*';
    const PHASE1GO_FIELDS    = '%s*%s*%s*%s%s*%s*%s*%s*%s*%s';

    const NBR_ECH       = '';
    const DATE_ECH_1    = '';
    const MONTANT_ECH_1 = '';
    const DATE_ECH_2    = '';
    const MONTANT_ECH_2 = '';
    const DATE_ECH_3    = '';
    const MONTANT_ECH_3 = '';
    const DATE_ECH_4    = '';
    const MONTANT_ECH_4 = '';

    private $paymentMethodRepository;
    private $serializer;
    private $router;
    private $paths;
    private $request;
    private $mailer;

    public function __construct(PaymentMethodRepository $paymentMethodRepository,
        SerializerInterface $serializer,
        RouterInterface $router,
        RequestStack $requestStack,
        Mailer $mailer,
        $paths
    ) {
        $this->paymentMethodRepository = $paymentMethodRepository;
        $this->serializer              = $serializer;
        $this->router                  = $router;
        $this->request                 = $requestStack;
        $this->mailer                  = $mailer;
        foreach ($paths as $key => $path) {
            if ($path['name'] === static::METHOD) {
                $this->paths[$key] = $path;
            }
        }
    }

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

        /** @var Monetico $config */
        $config = $this->serializer->denormalize($paymentMethod->getConfiguration(), Monetico::class);
        $total                   = $payment->getTotal() / 100;
        $data['TPE']             = $config->getEptNumber();
        $data['societe']         = $config->getCompanyCode();
        $data['lgue']            = strtoupper($this->request->getCurrentRequest()->getLocale());
        $data['version']         = $config->getVersion();
        $data['reference']       = strtoupper($payment->getToken());
        $data['date']            = date("d/m/Y:H:i:s");
        $data['montant']         = $total.static::DEVISE;
        $contexteCommandeBilling = [];
        if ($payment->getCompany()) {
            $contexteCommandeBilling = array_merge($contexteCommandeBilling, ['name' => $payment->getCompany(),]);
        }
        $contexteCommandeBilling = array_merge($contexteCommandeBilling, [
             'firstName'   => substr($payment->getFirstname(), 0, 44),
            'lastName'     => substr($payment->getLastname(), 0, 44),
            'addressLine1' => substr($payment->getStreet(),0, 48),
            'city'         => $payment->getCity(),
            'postalCode'   => $payment->getPostalCode(),
            'country'      => $payment->getCountry(),
        ]);
        $contexteCommande          = [
            'billing' => $contexteCommandeBilling,
        ];

        $data['contexte_commande'] = base64_encode(utf8_encode(json_encode($contexteCommande)));
        $data['mail']            = $payment->getEmail();
        $data['url_retour']      = $this->request->getCurrentRequest()->getUriForPath($this->router->generate($this->paths['monetico']['canceled'], [], true));
        $data['url_retour_ok']   = $this->request->getCurrentRequest()->getUriForPath($this->router->generate($this->paths['monetico']['done'], [], true));
        $data['url_retour_err']  = $this->request->getCurrentRequest()->getUriForPath($this->router->generate($this->paths['monetico']['refused'], [], true));

        ksort($data);

        $formFields = $data ;
        array_walk($formFields, function (&$item, $key) {
            $item = "$key=$item";
        });
        $msg =  implode('*', $formFields);

        if ($config->isProduction()) {
            $data['URL'] = static::PROD_URL;
        } else {
            $data['URL'] = static::TEST_URL;
        }
        $data['MAC'] = $this->computeHmac($msg, $config->getHmacKey());

        return $data;
    }

    private function _getUsableKey($key)
    {
        $hexStrKey = substr($key, 0, 38);
        $hexFinal = "" . substr($key, 38, 2) . "00";

        $cca0 = ord($hexFinal);

        if ($cca0 > 70 && $cca0 < 97)
            $hexStrKey .= chr($cca0 - 23) . substr($hexFinal, 1, 1);
        else {
            if (substr($hexFinal, 1, 1) == "M")
                $hexStrKey .= substr($hexFinal, 0, 1) . "0";
            else
                $hexStrKey .= substr($hexFinal, 0, 2);
        }

        return $hexStrKey;
    }

    public function computeHmac($sData, $hmac)
    {

        return strtolower(hash_hmac("sha1", $sData, hex2bin($this->_getUsableKey($hmac))));
    }

    public function valid($response = null)
    {

        if ($response) {
            $paymentMethod = $this->paymentMethodRepository->findOneBy(['method' => static::METHOD]);
            /** @var Monetico $config */
            $config = $this->serializer->denormalize($paymentMethod->getConfiguration(), Monetico::class);
            $mac = $response['MAC'];
            if (!isset($response['texte-libre'])) {
                $response['texte-libre'] = '';
            }

            if (!isset($response['motifrefus'])) {
                $response['motifrefus'] = '';
            }

            if (!isset($response['TPE'])
                || !isset($response['date'])
                || !isset($response['contexte_commande'])
                || !isset($response['montant'])
                || !isset($response['reference'])
                || !isset($response['texte-libre'])
                || !isset($response['code-retour'])
                || !isset($response['cvx'])
                || !isset($response['vld'])
                || !isset($response['brand'])
                || !isset($response['status3ds'])
                || !isset($response['numauto'])
                || !isset($response['motifrefus'])
                || !isset($response['originecb'])
                || !isset($response['bincb'])
                || !isset($response['hpancb'])
                || !isset($response['ipclient'])
                || !isset($response['originetr'])
                || !isset($response['veres'])
                || !isset($response['pares'])
            ) {
                $this->mailer->sendErrorValidReturnPayment(json_encode($response));

                return true;
            }
            $msgBack = sprintf(
                static::PHASE2BACK_FIELDS,
                $response['TPE'],
                $response['contexte_commande'],
                $response['date'],
                $response['montant'],
                $response['reference'],
                $response['texte-libre'],
                $config->getVersion(),
                $response['code-retour'],
                $response['cvx'],
                $response['vld'],
                $response['brand'],
                $response['status3ds'],
                $response['numauto'],
                $response['motifrefus'],
                $response['originecb'],
                $response['bincb'],
                $response['hpancb'],
                $response['ipclient'],
                $response['originetr'],
                $response['veres'],
                $response['pares']
            );

            if ($this->computeHmac($msgBack, $config->getHmacKey()) == strtolower($mac)) {

                return true;
            } else {
                $this->mailer->sendErrorValidReturnPayment(json_encode($response));

                return true;
            }
        }

        return false;
    }
}
