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

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

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

class RecaptchaFormSubscriber implements EventSubscriberInterface
{
    /** @var string */
    private $reCaptchaKeyPrivate;
    private $reCaptchaKeyPublic;
    private $reCaptchaKeyEnterprise;
    private $reCaptchaProject;

    /**
     * @var FlashBagInterface
     */
    private $flashBag;

    /**
     * @var TranslatorInterface
     */
    private $translator;
    private $router;

    public function __construct(string $reCaptchaKeyPrivate,
        string $reCaptchaKeyPublic,
        bool $reCaptchaEnterprise,
        string $reCaptchaProject,
        FlashBagInterface $flashBag,
        TranslatorInterface $translator,
        RouterInterface $router
    ) {
        $this->reCaptchaKeyPrivate = $reCaptchaKeyPrivate;
        $this->reCaptchaKeyPublic  = $reCaptchaKeyPublic;
        $this->reCaptchaEnterprise = $reCaptchaEnterprise;
        $this->reCaptchaProject    = $reCaptchaProject;
        $this->flashBag            = $flashBag;
        $this->translator          = $translator;
        $this->router              = $router;
    }

    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::REQUEST => 'onKernelRequest',
        ];
    }

    public function onKernelRequest(RequestEvent $event)
    {
        if (($event->getRequest()->getMethod() != "POST" && $event->getRequest()->request->count() > 0) || (strpos($event->getRequest()->getPathInfo(), 'request') == 1) || $event->getRequest()->get("_route") === "shop"  || $event->getRequest()->get("_route") === "payment" || preg_match('/Controller\\\\Admin/', $event->getRequest()->attributes->get('_controller')) || 'turbo_stream' === $event->getRequest()->getPreferredFormat()) {
            return;
        }
        foreach ($event->getRequest()->request->all() as $key => $form) {
            if (($event->getRequest()->request->get('g-recaptcha-response'))) {
                return;
            }
            if (is_array($form)) {
                if (!array_key_exists('g_recaptcha_response', $form) || $form['g_recaptcha_response'] === "") {

                    $redirectUrl = $event->getRequest()->getUri();
                    $event->getRequest()->setMethod("GET");
                    $this->flashBag->add('error', $this->translator->trans('form.error-recaptcha', [], 'validators'));

                    return new RedirectResponse($redirectUrl);
                }
                $token  = $form['g_recaptcha_response'];
                $action = $key."_g_recaptcha_response";

                // call curl to POST request
                $ch = curl_init();
                if ($this->reCaptchaEnterprise) {
                    curl_setopt($ch, CURLOPT_URL, "https://recaptchaenterprise.googleapis.com/v1/projects/".$this->reCaptchaProject."/assessments?key=".$this->reCaptchaKeyPrivate);
                    curl_setopt($ch, CURLOPT_POST, 1);
                    $data     = [
                        "event" => [
                            "token"          => $token,
                            "siteKey"        => $this->reCaptchaKeyPublic,
                            'userAgent'      => $event->getRequest()->headers->get('User-Agent'),
                            'userIpAddress'  => $event->getRequest()->getClientIp(),
                            'expectedAction' => $action,
                        ],
                    ];
                    $dataJson = json_encode($data, JSON_UNESCAPED_UNICODE);
                    curl_setopt(
                        $ch, CURLOPT_POSTFIELDS, $dataJson
                    );
                    curl_setopt(
                        $ch, CURLOPT_HTTPHEADER, [
                            'Content-Type: application/json',
                            'charset=utf-8',
                        ]
                    );
                    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                    $response = curl_exec($ch);
                    curl_close($ch);
                    $arrResponse = json_decode($response, true);

                    if (isset($arrResponse["error"])) {
                        $redirectUrl = $event->getRequest()->getUri();
                        $route       = $event->getRequest()->attributes->get('_route');
                        $event->getRequest()->setMethod("GET");
                        $this->flashBag->add('error', $arrResponse["error"]['message']);

                        return new RedirectResponse($redirectUrl);
                    }
                    // verify the response
                    if ($arrResponse["tokenProperties"]["valid"] === true && $arrResponse["tokenProperties"]["action"] === $action && $arrResponse["riskAnalysis"]["score"] >= 0.9) {
                        return;
                    }
                } else {
                    curl_setopt($ch, CURLOPT_URL, "https://www.google.com/recaptcha/api/siteverify");
                    curl_setopt($ch, CURLOPT_POST, 1);
                    curl_setopt(
                        $ch, CURLOPT_POSTFIELDS, http_build_query(
                            [
                                'secret'   => $this->reCaptchaKeyPrivate,
                                'response' => $token,
                                'remoteip' => $event->getRequest()->getClientIp(),
                            ]
                        )
                    );
                    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                    $response = curl_exec($ch);
                    curl_close($ch);
                    $arrResponse = json_decode($response, true);

                    // verify the response
                    if ($arrResponse["success"] == '1' && $arrResponse["score"] >= 0.9) {
                        return;
                    }
                }

                $redirectUrl = $event->getRequest()->getUri();
                $event->getRequest()->setMethod("GET");
                $this->flashBag->add('error', $this->translator->trans('form.error-recaptcha', [], 'validators'));

                return new RedirectResponse($redirectUrl);
            }
        }
    }
}
