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

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Site;


use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\UX\Turbo\TurboBundle;
use Twig\Environment;

class RecaptchaType extends AbstractType
{
    private $reCaptchaKeyPrivate;
    private $reCaptchaKeyPublic;
    private $reCaptchaEnterprise;
    private $reCaptchaProject;
    private $requestStack;
    private $translator;

    public function __construct(string              $reCaptchaKeyPrivate,
                                string              $reCaptchaKeyPublic,
                                bool                $reCaptchaEnterprise,
                                string              $reCaptchaProject,
                                RequestStack        $requestStack,
                                TranslatorInterface $translator
    )
    {
        $this->reCaptchaKeyPrivate = $reCaptchaKeyPrivate;
        $this->reCaptchaKeyPublic = $reCaptchaKeyPublic;
        $this->reCaptchaEnterprise = $reCaptchaEnterprise;
        $this->reCaptchaProject = $reCaptchaProject;
        $this->requestStack = $requestStack;
        $this->translator = $translator;
    }

    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        parent::buildView($view, $form, $options);
        $attr = $view->vars['attr'];
        if ($this->reCaptchaEnterprise) {
            $attr['class'] = 'g_recaptcha_enterprise';
        } else {
            $attr['class'] = 'g_recaptcha';

        }
        $attr['data-controller'] = 'recaptcha';
        $attr['data-sitekey'] = $this->reCaptchaKeyPublic;
        $view->vars['attr'] = $attr;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm($builder, $options);
        $builder->addEventListener(
            FormEvents::POST_SUBMIT,
            function (FormEvent $event) {
                if ('turbo_stream' !== $this->requestStack->getMainRequest()->getPreferredFormat()) {
                    return;
                }
                $token = $event->getForm()->getData();
                $action = $event->getForm()->getParent()->getName() . "_g_recaptcha_response";
                $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' => $this->requestStack->getMainRequest()->headers->get('User-Agent'),
                            'userIpAddress' => $this->requestStack->getMainRequest()->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"]) || $arrResponse["tokenProperties"]["valid"] != true || $arrResponse["riskAnalysis"]["score"] < 0.8) {
                        $this->requestStack->getSession()->getFlashBag()->add('error', $this->translator->trans('form.error-recaptcha', [], 'validators'));
                        $event->getForm()->addError(new FormError($arrResponse["error"]['message']));
                    }
                } 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' => $this->requestStack->getMainRequest()->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.8) {
                        $this->requestStack->getSession()->getFlashBag()->add('error', $this->translator->trans('form.error-recaptcha', [], 'validators'));
                        $event->getForm()->addError(new FormError($arrResponse["error"]['message']));
                    }
                }
            }
        );
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(
            [
                'mapped' => false,
            ]
        );
    }

    public function getParent()
    {
        return HiddenType::class;
    }


}
