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

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

use CpCreation\VitiCore\Behavior\HasPayment;
use CpCreation\VitiCore\Cart\Model\Payment\Cawl;
use CpCreation\VitiCore\Cart\Repository\PaymentMethodRepository;
use OnlinePayments\Sdk\Domain\CardPaymentMethodSpecificInputBase;
use OnlinePayments\Sdk\Domain\Feedbacks;
use OnlinePayments\Sdk\Domain\MobilePaymentMethodHostedCheckoutSpecificInput;
use OnlinePayments\Sdk\Domain\OrderReferences;
use OnlinePayments\Sdk\Domain\RedirectPaymentMethodSpecificInput;
use OnlinePayments\Sdk\Domain\SendTestRequest;
use OnlinePayments\Sdk\Domain\ValidateCredentialsRequest;
use OnlinePayments\Sdk\Merchant\Webhooks\WebhooksClient;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Serializer\SerializerInterface;
use OnlinePayments\Sdk\CommunicatorConfiguration;
use OnlinePayments\Sdk\Authentication\V1HmacAuthenticator;
use OnlinePayments\Sdk\Communicator;
use OnlinePayments\Sdk\Client;
use OnlinePayments\Sdk\Domain\CreateHostedCheckoutRequest;
use OnlinePayments\Sdk\Domain\AmountOfMoney;
use OnlinePayments\Sdk\Domain\Order;
use OnlinePayments\Sdk\Domain\HostedCheckoutSpecificInput;
use Symfony\Component\HttpFoundation\Response;

class CawlPayment
{
    const METHOD = 'cawl';
    const TEST_URL = 'https://payment.preprod.cawl-solutions.fr/';
    const PROD_URL = 'https://payment.cawl-solutions.fr/';
    const DEVISE   = 978;
    const CURRENCY = 'EUR';

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

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

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

        /** @var Cawl $config */
        $config      = $this->serializer->denormalize($paymentMethod->getConfiguration(), Cawl::class);
        $apiEndpoint = '';
        if (!$config->isProduction()) {
            $apiEndpoint = self::TEST_URL;
        } else {
            $apiEndpoint = self::PROD_URL;
        }
        $proxyConfiguration        = null;
        $communicatorConfiguration = new CommunicatorConfiguration(
            $config->getApiKey(),
            $config->getApiSecret(),
            $apiEndpoint,
            'CPCREATION',
            $proxyConfiguration
        );
        $authenticator             = new V1HmacAuthenticator($communicatorConfiguration);
        $communicator              = new Communicator($communicatorConfiguration, $authenticator);
        $data['client']            = new Client($communicator);
        $data['pspid']             = $config->getPspId();

        return $data;
    }

    public function createData(HasPayment $payment)
    {
        /** @var Client $client */
        $client = $this->createPaymentMandatoryObjects()['client'];
        /** @var string $pspid */
        $pspid                       = $this->createPaymentMandatoryObjects()['pspid'];
        $createHostedCheckoutRequest = new CreateHostedCheckoutRequest();
        $amountOfMoney               = new AmountOfMoney();
        $amountOfMoney->setAmount($payment->getTotal());
        $amountOfMoney->setCurrencyCode(self::CURRENCY);

        $order = new Order();
        $order->setAmountOfMoney($amountOfMoney);
        $orderReferences = new OrderReferences();
        $orderReferences->setMerchantReference($payment->getToken());
        $order->setReferences($orderReferences);

        $hostedCheckoutSpecificInput = new HostedCheckoutSpecificInput();
        $hostedCheckoutSpecificInput->setReturnUrl($this->request->getCurrentRequest()->getUriForPath($this->router->generate($this->paths['cawl']['done'], [], true)));

        $createHostedCheckoutRequest->setOrder($order);
        $feedbacks = new Feedbacks();
        $feedbacks->setWebhooksUrls([
            $this->request->getCurrentRequest()->getUriForPath($this->router->generate($this->paths['cawl']['response_at'], [], true)),
        ]);
        $createHostedCheckoutRequest->setFeedbacks($feedbacks);
        /** @var CardPaymentMethodSpecificInputBase $cardPaymentMethodSpecificInput */
        $cardPaymentMethodSpecificInput = new CardPaymentMethodSpecificInputBase();
        $cardPaymentMethodSpecificInput->setAuthorizationMode("SALE");
        /** @var MobilePaymentMethodHostedCheckoutSpecificInput $mobilePaymentMethodSpecificInput */
        $mobilePaymentMethodSpecificInput = new MobilePaymentMethodHostedCheckoutSpecificInput();
        $mobilePaymentMethodSpecificInput->setAuthorizationMode("SALE");
        /** @var RedirectPaymentMethodSpecificInput $redirectPaymentMethodSpecificInput */
        $redirectPaymentMethodSpecificInput = new RedirectPaymentMethodSpecificInput();
        $redirectPaymentMethodSpecificInput->setRequiresApproval(false);
        $createHostedCheckoutRequest->setCardPaymentMethodSpecificInput($cardPaymentMethodSpecificInput);
        $createHostedCheckoutRequest->setMobilePaymentMethodSpecificInput($mobilePaymentMethodSpecificInput);
        $createHostedCheckoutRequest->setRedirectPaymentMethodSpecificInput($redirectPaymentMethodSpecificInput);
        $createHostedCheckoutRequest->setHostedCheckoutSpecificInput($hostedCheckoutSpecificInput);
        # Send the request to your PSPID on our platform and receive it via an instance of CreateHostedCheckoutResponse
        $createHostedCheckoutResponse = $client->merchant($pspid)->hostedCheckout()->createHostedCheckout($createHostedCheckoutRequest);
        $createHostedCheckoutResponse->setHostedCheckoutId(strtoupper($payment->getToken()));
        $data['URL'] = $createHostedCheckoutResponse->getRedirectUrl();

        return $data;
    }


    public function getStatus(string $hostedCheckoutId)
    {
        $client = $this->createPaymentMandatoryObjects()['client'];
        $pspid  = $this->createPaymentMandatoryObjects()['pspid'];

        # Get the current status of the transaction
        return $client->merchant($pspid)->hostedCheckout()->getHostedCheckout($hostedCheckoutId);
    }

    public function valid(string $json, string $signature)
    {
        $paymentMethod   = $this->paymentMethodRepository->findOneBy(['method' => static::METHOD]);
        $config          = $this->serializer->denormalize($paymentMethod->getConfiguration(), Cawl::class);
        $secretKey       = $config->getWebhookSecret();
        $signatureCalcul = base64_encode(hash_hmac('sha256', $json, $secretKey, true));
        if ($signatureCalcul === $signature) {
            $result = json_decode($json, true);
            $status = $result['payment']['status'];
            if (isset($status) && $status == "CAPTURED") {
                return true;
            }
        }

        return false;
    }
}