<?php

namespace App\Controller;

use App\Entity\AchatMonnaieAConfirmerPrestataire;
use App\Entity\AchatMonnaiePrestataire;
use App\Entity\Caissier;
use App\Entity\GlobalParameter;
use App\Entity\Payment;
use App\Entity\Prestataire;
use App\Entity\Reconversion;
use App\Entity\TransactionPrestataireAdherent;
use App\Entity\User;
use App\Entity\Usergroup;
use App\Events\MLCEvents;
use App\Events\PrestataireEvent;
use App\Form\Type\AchatMonnaieAConfirmerPrestataireFormType;
use App\Form\Type\AchatMonnaiePrestataireFormType;
use App\Form\Type\GroupePrestataireInscriptionFormType;
use App\Form\Type\PrestataireInfosFormType;
use App\Form\Type\ReconversionFormType;
use FOS\UserBundle\Event\UserEvent;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Validator\Constraints as Assert;

class UserPrestataireController extends FluxController
{
    /**
     * @Route("/prestataireinfos", name="prestataire_infos")
     * @IsGranted("ROLE_PRESTATAIRE")
     */
    public function prestataireInfosAction(Request $request)
    {
        $presta = $this->session->get('_prestagere');
        $presta = $this->em->getRepository(Prestataire::class)->findOneById($presta->getId());
        $originalAdresses = $presta->getGeolocs();
        $originalCaissiers = $presta->getCaissiers();

        $form = $this->createForm(PrestataireInfosFormType::class, $presta);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $errorText = '';
            foreach ($originalAdresses as $adresse) {
                if (false === $presta->getGeolocs()->contains($adresse)) {
                    $adresse->getPrestataires()->removeElement($presta);
                }
                $this->em->persist($adresse);
            }

            // caissiers validations
            if (!empty($form->get('newcaissiers')->getData())) {
                $caissiers = explode(';', $form->get('newcaissiers')->getData());
                $errors = [];
                foreach ($caissiers as $caissier) {
                    $emailConstraint = new Assert\Email();
                    $emailConstraint->message = "Courriel '" . $caissier . "' invalide!";

                    $errors[] = $this->validator->validate(
                        $caissier,
                        $emailConstraint
                    );
                }
                foreach ($errors as $error) {
                    if ($error->count()) {
                        $errorText .= $error[0]->getMessage();
                    }
                }
                if ('' !== $errorText) {
                    $form->get('newcaissiers')->addError(new FormError($errorText));
                    $this->addFlash(
                        'error',
                        $this->translator->trans($errorText)
                    );
                } else {
                    // Remove caissier(s) if deleted from the field
                    foreach ($originalCaissiers as $oldCaissier) {
                        if (!in_array($oldCaissier->getUser()->getEmail(), $caissiers)) {
                            // if user is only caissier for this prestataire and caissier is removed,
                            // remove role caissier for user
                            if (count($oldCaissier->getUser()->getCaissiers()) === 1) {
                                $groupeCaissier = $this->em->getRepository(Usergroup::class)->findOneByName('Caissier');
                                $oldCaissier->getUser()->removePossibleGroup($groupeCaissier);
                                $this->em->persist($oldCaissier->getUser());
                            }

                            $form->getData()->getCaissiers()->removeElement($oldCaissier);
                        }
                    }
                    // Add caissier(s)
                    foreach ($caissiers as $caissier) {
                        $this->addCaissers($caissier, $form->getData(), $request);
                    }
                }
            }
            if ('' == $errorText) {
                $this->em->persist($form->getData());
                $this->em->flush();
                $this->addFlash(
                    'success',
                    $this->translator->trans('Informations modifiées !')
                );
            }
            $referer = $request->headers->get('referer');
            if ($referer && !$request->isXmlHttpRequest()) {
                return $this->redirect($referer);
            } elseif (!$request->isXmlHttpRequest()) {
                return new Response('', Response::HTTP_BAD_REQUEST);
            }
        } else {
            foreach ($form->getErrors(true, true) as $error) {
                // Errors detected here can be productFamily errors or other errors like csrf token errors
                // Add flash message showing the first error message
                $this->addFlash(
                    'error',
                    $error->getMessage()
                );
                break;
            }
        }

        return $this->redirectToRoute('index');
    }

    private function addCaissers($email, Prestataire $prestataire, Request $request)
    {
        $return = [];

        $newUser = false;
        $user = $this->em->getRepository(User::class)->findOneBy(['email' => $email]);
        if (null == $user) {
            $newUser = true;
            $user = new User(); // $this->userManager->createUser();
            $user->setConfirmationToken($this->tokenGenerator->generateToken());
            $user->setEnabled(true);
            $user->setPassword(md5(random_bytes(10)));
            $user->setEmail($email);
            $user->setUsername($email);
        }
        $caissier = $this->em->getRepository(Caissier::class)->findOneBy(['prestataire' => $prestataire, 'user' => $user]);
        if (null === $caissier) {
            $caissier = new Caissier();
            $caissier->setUser($user);
            $caissier->setPrestataire($prestataire);
            $this->em->persist($caissier);
        }
        $prestataire->addCaissier($caissier);
        $groupeCaissier = $this->em->getRepository(Usergroup::class)->findOneByName('Caissier');
        if ($newUser) {
            $this->eventDispatcher->dispatch(MLCEvents::REGISTRATION_CAISSIER, new PrestataireEvent($user, $prestataire, $request));
        }
        $user->addPossiblegroup($groupeCaissier);
        $this->userManager->updateCanonicalFields($user);
        $this->em->persist($user);
        if ($newUser) {
            $this->eventDispatcher->dispatch(MLCEvents::REGISTRATION_ADHERENT, new UserEvent($user, $request));
        }
        $this->em->persist($prestataire);
        $this->em->flush();

        return true;
    }

    /**
     * @Route("/prestatairegroupes/inscription", name="groupeprestataire_inscription")
     * @IsGranted("ROLE_PRESTATAIRE")
     */
    public function groupePrestataireInscriptionAction(Request $request)
    {
        //#180: at this point, the Prestataire entity is detached from the EntityManager (because we get it from the session)
        $presta = $this->session->get('_prestagere');
        //#180: $presta now refers to the fully managed copy returned by the merge operation.
        $presta = $this->em->getRepository(Prestataire::class)->findOneById($presta->getId());
        $originalGroupes = clone $presta->getGroupeprestataires();

        $form = $this->createForm(GroupePrestataireInscriptionFormType::class, $presta);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $prestataire = $form->getData();

            // Add flash messages if add/remove amap/marche
            foreach ($originalGroupes as $grp) {
                if (false === $presta->getGroupeprestataires()->contains($grp)) {
                    $this->addFlash(
                        'success',
                        $this->translator->trans('Vous êtes bien désinscrit de : {name} !', ['{name}' => $grp->getName()])
                    );
                    $grp->getPrestataires()->removeElement($presta);
                    $this->em->persist($grp);
                }
            }
            foreach ($prestataire->getGroupeprestataires() as $key => $groupePresta) {
                if (false === $originalGroupes->contains($groupePresta)) {
                    $this->addFlash(
                        'success',
                        $this->translator->trans('Vous êtes bien inscrit à : {name} !', ['{name}' => $groupePresta->getName()])
                    );
                }
            }

            $this->em->persist($prestataire);
            $this->em->flush();

            if ($request->isXmlHttpRequest()) {
                return new JsonResponse(['status' => 'success']);
            } else {
                $referer = $request->headers->get('referer');
                if ($referer && !$request->isXmlHttpRequest()) {
                    return $this->redirect($referer);
                } elseif (!$request->isXmlHttpRequest()) {
                    return new Response('', Response::HTTP_BAD_REQUEST);
                }
            }
        }

        return $this->redirectToRoute('index');
    }

    /**
     * @Route("/prestataire/transaction/{type}/", name="transactionPrestataireAdherent", defaults={"type": "adherent"})
     * @Route("/prestataire/transaction/{type}/", name="transactionPrestatairePrestataire", defaults={"type": "prestataire"})
     * @IsGranted("ROLE_PRESTATAIRE")
     */
    public function transactionPrestataireAction($type, Request $request)
    {
        $entityName = 'App\Entity\TransactionPrestataire' . ucwords($type);
        $entity = new $entityName();
        $entity->setOperateur($this->getUser());
        $entity->setExpediteur($this->session->get('_prestagere'));
        $form = $this->createForm('App\Form\Type\TransactionPrestataire' . ucwords($type) . 'FormType', $entity);

        return $this->manageFluxForm(
            $request,
            $form
        );
    }

    /**
     * @Route("/prestataire/reconversion/", name="transactionReconversion")
     * @IsGranted("ROLE_PRESTATAIRE")
     */
    public function reconversionAction(Request $request)
    {
        $entity = new Reconversion();
        $entity->setOperateur($this->getUser());
        $entity->setExpediteur($this->session->get('_prestagere'));
        $form = $this->createForm(ReconversionFormType::class, $entity);

        return $this->manageFluxForm(
            $request,
            $form
        );
    }

    /**
     * @Route("/prestataire/achat-monnaie/", name="achatMonnaiePrestataire")
     * @IsGranted("ROLE_PRESTATAIRE")
     */
    public function achatMonnaiePrestataireAction(Request $request)
    {
        if (empty($this->getUser()) || empty($this->session->get('_prestagere'))) {
            return $this->redirectToRoute('index');
        }

        $entity = new AchatMonnaiePrestataire();
        $entity->setReconverti(true);
        $form = $this->createForm(AchatMonnaiePrestataireFormType::class, $entity);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $achat = $form->getData();
            //Manage don if null => delete it !
            if ($achat->getDon() && 0 == $achat->getDon()->getMontant()) {
                $achat->setDon(null);
            }
            if ($form->has('payOther') && $form->get('payOther')->isClicked()) {
                return $this->redirectToRoute('achatMonnaieAConfirmerPrestataire');
            } elseif ($form->has('saveHelloAsso') && $form->get('saveHelloAsso')->isClicked()) {
                $url = $this->em->getRepository(GlobalParameter::class)->val(GlobalParameter::HELLOASSO_URL_EMLC_PRESTATAIRE);

                return $this->redirect($url);
            } elseif ($form->get('save')->isClicked()) {
                return $this->forward('App\Controller\PaymentController::preparePaymentAction', [
                    'form'  => $form,
                    'type'  => Payment::TYPE_ACHAT_MONNAIE_PRESTA
                ]);
    
            }
        }

        return $this->render('@kohinos/flux/transaction.html.twig', [
            'form' => $form->createView(),
            'title' => $this->translator->trans('Achat de monnaie locale'),
        ]);
    }

    /**
     * @Route("/prestataire/demande/achat-monnaie/", name="achatMonnaieAConfirmerPrestataire")
     * @IsGranted("ROLE_PRESTATAIRE")
     */
    public function achatMonnaieAConfirmerPrestataireAction(Request $request)
    {
        if (empty($this->getUser()) || empty($this->session->get('_prestagere'))) {
            return $this->redirectToRoute('index');
        }

        $entity = new AchatMonnaieAConfirmerPrestataire();
        $form = $this->createForm(AchatMonnaieAConfirmerPrestataireFormType::class, $entity);

        return $this->manageFluxForm(
            $request,
            $form,
            '@kohinos/flux/demande_achat_monnaie.html.twig',
            ['title' => $this->translator->trans("Demande d'achat de monnaie locale numérique")]
        );
    }

    /**
     * @Route("/prestataire/liste/demande/achat-monnaie/", name="listachatMonnaieAConfirmerPrestataire")
     * @IsGranted("ROLE_PRESTATAIRE")
     */
    public function listachatMonnaieAConfirmerPrestataireAction(Request $request)
    {
        if (empty($this->getUser()) || empty($this->session->get('_prestagere'))) {
            return $this->redirectToRoute('index');
        }

        $q = $this->em->getRepository(AchatMonnaieAConfirmerPrestataire::class)->findBy(['destinataire' => $this->session->get('_prestagere')], ['createdAt' => 'DESC']);

        return $this->render('@kohinos/flux/list_demande_achat_monnaie.html.twig', [
            'datas' => $q,
        ]);
    }
}
