<?php

namespace AppBundle\Controller\Legacy;

use AppBundle\Entity\DemandePEE;
use AppBundle\Entity\OperationPEE;
use AppBundle\Entity\User;
use AppBundle\Enum\DemandePEEState;
use AppBundle\Enum\DemandePEEType;
use AppBundle\Enum\UserType;
use AppBundle\Form\Type\Front\PEE\Legacy\UserDemandePEEType;
use AppBundle\Helper\OperationHelper;
use AppBundle\Mail\PeeMailer;
use AppBundle\Pdf\PdfGenerator;
use Doctrine\ORM\EntityManagerInterface;
use FOS\UserBundle\Event\FilterUserResponseEvent;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Model\UserInterface;
use FOS\UserBundle\Model\UserManagerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Translation\TranslatorInterface;

class OperationPeeController extends Controller
{
    /**
     * @var EventDispatcherInterface
     */
    private $dispatcher;

    /**
     * @var EntityManagerInterface
     */
    private $em;

    /**
     * @var PdfGenerator
     */
    private $pdfGenerator;

    /**
     * @var PeeMailer
     */
    private $peeMailer;

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

    /**
     * @var UserManagerInterface
     */
    private $userManager;

    /**
     * @var SessionInterface
     */
    private $session;

    
    public function __construct(
        EntityManagerInterface $em,
        EventDispatcherInterface $dispatcher,
        PdfGenerator $pdfGenerator,
        PeeMailer $peeMailer,
        TranslatorInterface $translator,
        UserManagerInterface $userManager,
        SessionInterface $session
    )
    {
        $this->dispatcher = $dispatcher;
        $this->em = $em;
        $this->pdfGenerator = $pdfGenerator;
        $this->peeMailer = $peeMailer;
        $this->translator = $translator;
        $this->userManager = $userManager;
        $this->session = $session;
    }

    /**
     * Ajout d'une demande PEE
     *
     * @Route(
     *      "/legacy/espace-perso/demande-pee",
     *      name = "legacy_espace_perso_pee_add"
     * )
     *
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
     * @throws \Exception
     */
    public function addAction(Request $request)
    {
        $user = $this->getUser();

        // Stock return path in session and redirect to login if user is anonymous
        if (!is_object($user) || !$user instanceof UserInterface) {
            $this->session->set('_return', base64_encode($this->generateUrl($request->get('_route'), $request->get('_route_params'), UrlGeneratorInterface::ABSOLUTE_URL)));

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

        if (UserType::TEACHER !== $user->getType()) {
            //throw $this->createAccessDeniedException();

            $this->addFlash('error', $this->translator->trans(
                'notice.user.access_denied',
                [],
                'notice'
            ));
            return $this->redirectToRoute('espace_perso');
        }

        $operations = $this->em->getRepository(OperationPEE::class)->findOpenForApplication($user);
        $oChecked = $request->get('operation') ?? [];
        $oCerpepChecked = $request->get('operation_cerpep') ?? [];
        $userSendCard = $user->getSendCard();

        // Filter the operations with applications (from the connected user, see findOpenForApplication() above)
        $userOperations = OperationHelper::filterByUserApplication($operations);

        // Get the number of user applications
        $oUserApplicationQty = OperationHelper::getUserApplicationQty($operations);

        $form = $this->createForm(UserDemandePEEType::class, $user);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            if (count($oChecked) > 0) {
                // Redirect: the teacher has already reached the limit of applications allowed per teacher
                if ($oUserApplicationQty >= $this->getParameter('pee.application.max_per_user')) {
                    $this->addFlash('error', $this->translator->trans(
                        'notice.operationPee.registration.limit.reached',
                        ['%limit%' => $this->getParameter('pee.application.max_per_user')],
                        'notice'
                    ));

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

                // Check if the teacher can apply to the operations he checked:
                // - operation is open for application
                // - teacher does not have an application for the operation OR the application is in a WITHDRAWAL state
                $oAllowedForApplication = array_filter($operations, function(array $o) use ($oChecked) {
                    /** @var OperationPEE $o */
                    $o = $o['details'];

                    return in_array($o->getId(), $oChecked)
                        && (0 === $o->getDemandepee()->count() || DemandePEEState::WITHDRAWAL === $o->getDemandepee()->first()->getState())
                    ;
                });

                $oAllowedForApplicationQty = count($oAllowedForApplication);

                // Redirect: no operation allowed for application
                if (0 === $oAllowedForApplicationQty) {
                    // The teacher did not check any OperationPEE, but checked at least 1 CERPEP option
                    if ($oCerpepCheckedQty = count($oCerpepChecked) > 0) { 
                        $this->addFlash('error', $this->translator->transchoice(
                            'notice.operationPee.registration.cerpep.only',
                            $oCerpepCheckedQty,
                            [],
                            'notice'
                        ));
                    }

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

                // Redirect: the user will overtake the limit of applications per teacher with the number of operations he checked.
                // In that case, $oAllowedForApplicationQty is always > 1,
                // because if = 1, the user has alreaby been redirect by reaching the limit
                if ($oUserApplicationQty + $oAllowedForApplicationQty > $this->getParameter('pee.application.max_per_user')) {
                    $limit = $this->getParameter('pee.application.max_per_user');
                    $remaining = $limit - $oUserApplicationQty;

                    if (0 === $oUserApplicationQty) {
                        $notice = $this->translator->transchoice(
                            'notice.operationPee.registration.limit.overtake.inOneGo',
                            $limit,
                            ['%limit%' => $limit],
                            'notice'
                        );
                    } else {
                        $notice = $this->translator->transchoice(
                            'notice.operationPee.registration.limit.overtake.inSeveralGo',
                            $remaining,
                            ['%remaining%' => $remaining],
                            'notice'
                        ) . ' (' . lcfirst($this->translator->transchoice(
                            'notice.operationPee.registration.limit.status',
                            $oUserApplicationQty,
                            ['%registered%' => $oUserApplicationQty],
                            'notice'
                        )) . ').';
                    }

                    $this->addFlash('error', $notice);

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

                // Check that the user doesn't want to apply for several operations the same day.
                // We suppose that the dates of the operations he already applied for are different;
                // so we need to only check the dates he checked in the form.
                // Algorithm behavior:
                // 1. Retrieve operations visit dates for which the user already has an application
                // 2. Add to this list the visit dates of the operations he checked
                // 3. Make the collected dates unique (using array_unique())
                // 4. Compare the number of dates between the full list and the unique list
                $datesTaken = [];
                foreach ($userOperations as $o) {
                    if (null !== $o['details']->getDateVisite()) {
                        $datesTaken[] = $o['details']->getDateVisite()->format('dmY');
                    }
                }
                foreach ($oAllowedForApplication as $o) {
                    if (null !== $o['details']->getDateVisite()) {
                        $datesTaken[] = $o['details']->getDateVisite()->format('dmY');
                    }
                }
                $datesTakenUnique = array_unique($datesTaken);

                // Redirect: the user want to apply for different operations the same day
                if (count($datesTaken) !== count($datesTakenUnique)) {
                    $this->addFlash('error', nl2br($this->translator->trans(
                        'notice.operationPee.registration.date_identical',
                        array('%mail%' => '<a href="mailto:'.$this->getParameter('cgenial.mail.pee.registration').'">'.$this->getParameter('cgenial.mail.pee.registration').'</a>'),
                        'notice'
                    )));

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

                // Creation of the application and preparation of the mails that will be send to the teacher
                $mails = array();
                foreach ($oAllowedForApplication as $operation) {
                    $o = $operation['details'];

                    $demande = new DemandePEE;
                    $demande->setOperationpee($o);
                    $demande->setCuser($user);

                    if (in_array($o->getId(), $oCerpepChecked)) {
                        $demande->setType(DemandePEEType::CERPEP);
                    }

                    // Si le total des demandes au statut 'Inscrit' ou 'Pré-inscrit'
                    // est inférieur au nombre de places disponibles dans l'opération,
                    // alors la demande du prof a le statut 'Pré-inscrit'.
                    if ($operation['placesTaken'] < $o->getNbPeople()) {
                        $demande->setState(DemandePEEState::PREREGISTERED);
                    } else {
                        $demande->setState(DemandePEEState::WAITING);
                    }
                    $this->em->persist($demande);

                    $mails[] = [
                        'datevisite' => $o->getDateVisite(),
                        'starttime' => $o->getStartTime(),
                        'endtime' => $o->getEndTime(),
                        'company' => $o->getCompany(),
                        'site' => $o->getSite(),
                        'city' => $o->getCity(),
                        'state' => $demande->getState(),
                    ];
                }
                $this->em->flush();

                // Send email
                $this->peeMailer->confirmDemandes($user, $mails);

                // Send flash message
                $mail_subject='Venez visiter le site cgenial.org';
                $mail_body = str_replace("\n", '%0D%0A', // Required for line break representation in the mailto: URL scheme
                    $this->renderView('Front/Mail/invitation.html.twig', array(
                        'firstname' => $user->getFirstname(),
                        'lastname' => $user->getLastname(),
                    ))
                );

                $flashBagMessage = '<div class="confirm">';
                $flashBagMessage .= "<p><strong>Votre demande de participation à l'action <em>Professeurs en entreprise</em> a bien été enregistrée.</strong></p>";
                $flashBagMessage .= "<p>";
                if ('postale' === $user->getSendCard()) {
                    $flashBagMessage .= "<strong>N'oubliez pas de nous faire parvenir votre pièce d'identité afin que nous puissions terminer votre inscription.</strong> Nous vous enverrons ensuite un email pour vous confirmer votre inscription définitive.";
                } else {
                    $flashBagMessage .= "Nous nous efforçons d'y faire suite au plus vite. Nous vous enverrons un email pour vous confirmer votre inscription définitive.";
                }
                $flashBagMessage .= "</p>";
                $flashBagMessage .= '<p><a class="btn btn-mailto" href="mailto:?subject='.$mail_subject.'&body='.$mail_body.'">Invitez vos amis à visiter notre site en 1 clic !</a></p>';
                $flashBagMessage .= '<div class="professeur" id="yesyoucan">
                <p>Souhaitez-vous participer à une autre opération ?</p>
                <p><a class="btn btn-demande-pee" href="'.$this->generateUrl('espace_perso_pee_add').'">Déposer une demande de participation à <em>Professeurs en entreprise</em></a></p>
                <p><a class="btn btn-demande-itdlc" href="'.$this->generateUrl('espace_perso_prof_itdlc_add').'">Déposer une demande de participation à <em>Ingénieurs et techniciens dans les classes</em></a></p>
                </div>';
                $flashBagMessage .= '</div>';

                $this->addFlash('info', $flashBagMessage);
            }

            // Si l'utilisateur change sa préférence d'envoi de pièce d'identité, on envoi un mail à CGénial pour indiquer ce changement.
            $userSendCardNew = $form->getData()->getSendCard();
            if (!empty($userSendCard) && $userSendCard !== $userSendCardNew) {
                $this->peeMailer->changeIdentityCardSendingType($user, $userSendCardNew);
            }

            $event = new FormEvent($form, $request);
            $this->dispatcher->dispatch(FOSUserEvents::PROFILE_EDIT_SUCCESS, $event);

            $user->setIsValideInfo(false);

            $this->userManager->updateUser($user);

            if (null === $response = $event->getResponse()) {
                $response = $this->redirectToRoute('espace_perso_pee_add');
            }

            $this->dispatcher->dispatch(
                FOSUserEvents::PROFILE_EDIT_COMPLETED,
                new FilterUserResponseEvent($user, $request, $response)
            );

            return $this->redirectToRoute('espace_perso');
        } else if ('POST' === $request->getMethod()) { // Form submitted but not valid
            $this->addFlash('error', "Votre demande n'a pu être effectuée car certaines informations ont été mal renseignées. Veuillez les vérifier, puis enregistrez à nouveau votre demande.");
        }

        $academies = $this->em->getRepository(User::class)->findAcademies();

        return $this->render('Front/Demande/PEE/form.html.twig', array(
            'academies' => $academies,
            'form' => $form->createView(),
            'operations' => $operations,
            'registeredQty' => $oUserApplicationQty,
        ));
    }

    /**
     * Liste les opérations PEE actives et qui ne sont pas fermées
     *
     * @Route(
     *      "/legacy/espace-perso/liste-pee",
     *      name = "legacy_espace_perso_pee_list"
     * )
     * @Method({"POST"})
     *
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function listAction(Request $request)
    {
        $user = $this->getUser();
        if (UserType::TEACHER !== $user->getType()) {
            throw $this->createAccessDeniedException();
        }

        $academyName = $request->get('academy_name');

        $filters = array();
        if (!empty($academyName)) {
            $filters['academy'] = $academyName;
        }

        $operations = $this->em->getRepository(OperationPEE::class)->findOpenForApplication($user, $filters);

        $registeredQty = OperationHelper::getUserApplicationQty($operations);

        return $this->render('Front/Demande/_component/listPee.html.twig', array(
            'academy_name' => $academyName,
            'operations' => $operations,
            'registeredQty' => $registeredQty,
        ));
    }

    /**
     * Generate a printable version of a PEE operation.
     *
     * @Route(
     *      "/legacy/operation-pee/{id}/download.{_format}",
     *      name = "legacy_operation_pee_download",
     *      requirements = {"_format": "pdf"},
     *      defaults = {"_format": "pdf"}
     * )
     *
     * @param Request $request
     * @param OperationPEE $o
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function downloadAction(Request $request, OperationPEE $o)
    {
        return $this->pdfGenerator->generateOperationPee($o, $request->getRequestFormat());
    }
}
