<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace App\Controller\Admin;


use App\Entity\Site;
use App\Entity\UtilisateurFilter;
use App\Entity\UtilisateurFiltre;
use App\Entity\UtilisateurRole;
use App\Repository\ObservationRepository;
use App\Repository\UtilisateurFilterRepository;
use App\Repository\UtilisateurFiltreRepository;
use App\Service\FiltreManager;
use App\Utils\Functions;
use Doctrine\Common\Annotations\AnnotationReader;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;

/**
 * Controller used to manage blog contents in the backend.
 *
 * Please note that the application backend is developed manually for learning
 * purposes. However, in your real Symfony application you should use any of the
 * existing bundles that let you generate ready-to-use backends without effort.
 *
 * See http://knpbundles.com/keyword/admin
 *
 * @Route("/")
 * @IsGranted("ROLE_USER")
 *
 * @author Ryan Weaver <weaverryan@gmail.com>
 * @author Javier Eguiluz <javier.eguiluz@gmail.com>
 */
class ParentAdminController extends AbstractController
{

    /**
     * Lists all entities.
     * @Route("/list/{page}", methods="GET", name="parent_list")
     */
    public function list($page, Request $request): Response
    {
        return $this->render('admin/list.html.twig', ['page' => $page, 'datagrid_style' => $request->get('style')]);
    }

    /**
     * Lists all entities.
     * @Route("/get/{page}", methods="GET", name="parent_get")
     * @Route("/get/{page}/{id}", methods="GET", name="parent_get_id")
     */
    public function getDatas($page,Request $request, SerializerInterface $serializer, $id = null)
    {
        $datas = [];
        $entityName = $this->getEntityName($page);

        if ($id) {
            $entity = $this->getDoctrine()->getManager()->getRepository($entityName)->find($id);
            $datas = json_decode($serializer->serialize($entity, 'json', [
                'ignored_attributes' => Functions::getIgnoredAttributes(),
                'groups' => 'site_list',
            ]), true);
            return new JsonResponse([
                $datas
            ], Response::HTTP_OK);

        } else {
//            if (method_exists($entityName, 'getActif')) {
//                $entities = $this->getDoctrine()->getManager()->getRepository($entityName)->findBy(['actif' => true]);
//            } else {
                $entities = $this->getDoctrine()->getManager()->getRepository($entityName)->findAll();
//            }

            foreach ($entities as $entity) {
                $datas[] = json_decode($serializer->serialize($entity, 'json', [
                    'ignored_attributes' => Functions::getIgnoredAttributes(),
                    'groups' => 'site_list',
                ]), true);
            }
        }

        return new JsonResponse([
            'data' => $datas,
            'totalCount' => count($datas),
        ], Response::HTTP_OK);
    }

    /**
     * Update one entity.
     * @Route("/{page}/{id}", methods="PATCH", name="parent_patch")
     */
    public function patchDatas($page, $id, Request $request) {
        $entityName = $this->getEntityName($page);
        $repository = $this->getDoctrine()->getManager()->getRepository($entityName);
        $em = $this->getDoctrine()->getManager();
        $datas = $request->request->all();

        $metadata = $em->getClassMetadata($entityName);

        if ($entity =  $repository->find($id)) {
            foreach ($datas as $key => $value) {
                if ($key == 'rang_tri') {
                    $this->majRangTri($em, $repository, $value, $entity->getRangTri());
                    $entity->setRangTri($value);
                } else {
                    $methodName = 'set' . $this->formatSetter(ucfirst($key));
                    $value = $this->getRealValue($value, $metadata, $key);

                    if (method_exists($entity, $methodName))
                        $entity->$methodName($value);
                }
            }
        }
        $em->persist($entity);
        $em->flush();

        $this->addFlash('success', "Modification effectuée avec succès");

        return new JsonResponse(['messages' => ['success' => ["Modification effectuée avec succès"]]], Response::HTTP_OK);
    }

    /**
     * disable one Entity
     * @Route("/disable/{page}/{id}", methods="GET", name="parent_disable")
     */
    public function disableEntity($page, $id, Request $request) {
        $entityName = $this->getEntityName($page);
        $entity = $this->getDoctrine()->getManager()->getRepository($entityName)->find($id);

        $entity->setActif(false);
        $this->getDoctrine()->getManager()->persist($entity);
        $this->getDoctrine()->getManager()->flush();

        $this->addFlash('success', "$page désactivé avec succès");

        if ($redirect = $request->query->get('redirect'))
           return $this->redirectToRoute($redirect);

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

    /**
     * update one entity.
     * @Route("/patchform/{page}/{id}", methods="POST", name="parent_patchform")
     */
    public function patchDatasForm(Request $request, $page,$id) : Response
    {
        $formType = "App\\Form\\" . ucfirst($page) . 'Type';
        $entityName = $this->getEntityName($page);
        $entity = $this->getDoctrine()->getManager()->getRepository($entityName)->find($id);
        $form = $this->createForm($formType,  $entity, ['action' => $this->generateUrl('parent_patchform', ['id' => $entity->getId(),'page' => $page])]);


        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $entity = $form->getData();
            $em = $this->getDoctrine()->getManager();
            $em->persist($entity);
            $em->flush();
            $em->refresh($entity);

            $this->addFlash('success', 'Modification effectuée avec succès');

            return new JsonResponse(['js_return' => "$('#utilisateur_login').val('".$entity->getLogin()."');", 'messages' => ['success' => ["Modification effectuée avec succès"]]], 200);
        }

        // render just the form for AJAX, there is a validation error
        else {
            if ($request->isXmlHttpRequest()) {
                $html = $this->renderView('form/utilisateur_edit.html.twig', [
                    'form' => $form->createView(),
                    'user' => $this->getUser(),
                ]);

                return new Response($html, 400);
            }
        }
    }

    /**
     * Delete one entity.
     * @Route("/{page}/{id}", methods="DELETE", name="parent_delete")
     */
    public function deleteEntity($page, $id, Request $request) {
        $entityName = $this->getEntityName($page);
        $repository = $this->getDoctrine()->getManager()->getRepository($entityName);
        $em = $this->getDoctrine()->getManager();

        if ($entity =  $repository->find($id)) {
            $em->remove($entity);
            //si la table comporte une position on met à jour
            if (method_exists($entity, 'getRangTri')) {
                $this->majRangTri($em, $repository, $entity->getRangTri(), null);
            }

            $em->flush();
        }

        return new JsonResponse(['messages' => ['success' => ["Suppression effectuée avec succès"]]], Response::HTTP_OK);
    }

    /**
     * create one entity.
     * @Route("/create/{page}", methods="POST", name="parent_create")
     */
    public function createEntity($page, Request $request) {
        $entityName = $this->getEntityName($page);
        $repository = $this->getDoctrine()->getManager()->getRepository($entityName);
        $em = $this->getDoctrine()->getManager();
        $datas = $request->request->all();
        $metadata = $em->getClassMetadata($entityName);
        if ($datas) {
            $entity = new $entityName();
            foreach ($datas as $key => $value) {
                $methodName = 'set' . $this->formatSetter(ucfirst($key));
                $value = $this->getRealValue($value, $metadata, $key);
                if (method_exists($entity, $methodName))
                    $entity->$methodName($value);
            }

            //récupération derniere position à l'ajout
            if (method_exists($entity, 'setRangTri')) {
                $entity->setRangTri($repository->getMaxRangTri() + 1);
            }

            $em->persist($entity);
            $em->flush();
        }

        return new JsonResponse(['messages' => ['success' => ["Création effectuée avec succès"]]], Response::HTTP_OK);
    }

    /**
     * create one entity.
     * @Route("/createform/{page}", methods="POST", name="parent_createform")
     */
    public function createEntityForm(Request $request, $page) : Response
    {
        $entityName = $this->getEntityName($page);
        $formType = "App\\Form\\" . ucfirst($page) . 'Type';
        $entity = new $entityName();

        $form = $this->createForm($formType, $entity);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            if ($form->get('sites')) $entity->setSites($form->get('sites')->getData());
            $em = $this->getDoctrine()->getManager();
            $em->persist($entity);
            $em->flush();

            $this->addFlash('success', 'création effectuée avec succès');

            return new JsonResponse(['messages' => ['success' => ["Création effectuée avec succès"]]], 200);
        }

        // render just the form for AJAX, there is a validation error
        else {
            if ($request->isXmlHttpRequest()) {
                $html = $this->renderView('form/'. strtolower($page) .'_add.html.twig', [
                    'form' => $form->createView()
                ]);

                return new Response($html, 400);
            }
        }

//        return $this->render('admin/blog/new.html.twig', [
//            'post' => $post,
//            'form' => $form->createView(),
//        ]);
    }


    /**
     * @Route("/filters/{page}", methods="GET", name="get_filters")
     *
     */
    public function getUtilisateurFilters($page, SerializerInterface $serializer, FiltreManager $filtreManager) {
        $datas = [];
        if ($this->getUser()->getRole()->getEstResponsable()) {
            $filters = $this->getUser()->getUtilisateurFiltres()->filter(function($element)use ($page){
                return ($element->getPage() == $page);
            });
        } else {
            //si non responsable, on récupère les filtres associés à son role
            $utilisateurSites = $this->getUser()->getSites();
            $filters = $this->getDoctrine()->getManager()->getRepository(UtilisateurFiltre::class)->findBy(
                [
                    'utilisateur_role' => $this->getUser()->getRole(),
                    'page' => $page,
                    'site' => $utilisateurSites[0],
                ]
            );
        }

        foreach ($filters as $filter) {
            $datas[] =  $filtreManager->formatFilter(json_decode($serializer->serialize($filter, 'json'), true));
        }

        return new JsonResponse([
            'data' => $datas,
            'totalCount' => count($datas),
        ], Response::HTTP_OK);
    }

    /**
     * @Route("/filters/{page}", methods="POST", name="post_filters")
     *
     */
    public function postUtilisateurFilters($page, Request $request, UtilisateurFiltreRepository $repository) {
        $status = 0;
        $message = '';
        $em = $this->getDoctrine()->getManager();
        $titre = $request->request->get('titre');
        $filtre = $request->request->get('filtres');
        $colonnes = $request->request->get('colonnes');
        $role = $request->request->get('role');
        $defaut = $request->request->get('defaut');
        $defaut_utilisateur = $request->request->get('defaut_utilisateur');
        $id_site = $request->request->get('site');

        $site = $em->getRepository(Site::class)->find((int)$id_site);
        if (!$userFilter = $repository->findOneBy(['titre' => $titre, 'utilisateur' => $this->getUser(), 'page' => $page, 'site' => $site])) {
            $userFilter = new UtilisateurFiltre();
            $userFilter
                ->setUtilisateur($this->getUser())
                ->setTitre($titre)
                ->setFiltre(json_encode($filtre))
                ->setColonnes(json_encode($colonnes))
                ->setPage($page)
                ->setSite($site);
                ;
            if ($defaut == "true") {
                //il faut mettre defaut = false sur tous les autres puis mettre celui la à defaut true
                $allFiltres = $em->getRepository(UtilisateurFiltre::class)->findBy(['utilisateur_role' => $userFilter->getUtilisateurRole(), 'page' => $userFilter->getPage(), 'site' => $userFilter->getSite()]);
                foreach ($allFiltres as $filtre) {
                    $filtre->setDefaut(false);
                    $em->persist($filtre);
                }
                $userFilter->setDefaut(true);
            }
            if ($defaut_utilisateur == "true") {
                //il faut mettre defaut = false sur tous les autres puis mettre celui la à defaut true
                $allFiltres = $em->getRepository(UtilisateurFiltre::class)->findBy(['page' => $userFilter->getPage(), 'utilisateur' => $this->getUser()]);
                foreach ($allFiltres as $filtre) {
                    $filtre->setDefautUtilisateur(false);
                    $em->persist($filtre);
                }
                $userFilter->setDefautUtilisateur(true);
            }
            if ($role) {
                $roleEntity = $this->getDoctrine()->getManager()->getRepository(UtilisateurRole::class)->find((int)$role);
                if ($roleEntity) {
                    $userFilter->setUtilisateurRole($roleEntity);
                    if ($defaut == "true") {
                        $allFiltres = $em->getRepository(UtilisateurFiltre::class)->findBy(['utilisateur_role' => $roleEntity, 'page' => $page, 'site' => $site]);
                        foreach ($allFiltres as $filtre) {
                            $filtre->setDefaut(false);
                            $em->persist($filtre);
                        }
                    }
                }
            }

            $em->persist($userFilter);
            $em->flush();

            $status = 1;
            $this->addFlash('success', 'Filtre ajouté avec succès');
        } else {
            $message = 'Un filtre existe déjà avec ce nom';
        }

        return new JsonResponse(['status' => $status, 'message' => $message], Response::HTTP_OK);
    }

    /**
     * @Route("/utilisateur/filtres/{id}", methods="PATCH", name="patch_filters")
     *
     */
    public function patchUtilisateurFilters($id, Request $request, UtilisateurFiltreRepository $repository) {
        $em = $this->getDoctrine()->getManager();
        $newTitre = $request->request->get('titre');
        $newRole = $request->request->get('utilisateur_role_id');
        $defaut = $request->request->get('defaut');
        $defaut_utilisateur = $request->request->get('defaut_utilisateur');
        $userFilter = $repository->findOneBy(['id' => $id, 'utilisateur' => $this->getUser()]);

        if ($newTitre && $userFilter) {
            $userFilter->setTitre($newTitre);
        }
        if ($newRole && $userFilter) {
            $newRoleEntite = $em->getRepository(UtilisateurRole::class)->find((int)$newRole);
            if ($newRoleEntite)$userFilter->setUtilisateurRole($newRoleEntite);
        }
        if ($defaut == "false" && $userFilter) $userFilter->setDefaut(false);
        if ($defaut_utilisateur == "false" && $userFilter) $userFilter->setDefautUtilisateur(false);
        if ($defaut == "true" && !$userFilter->getDefaut()) {
            //il faut mettre defaut = false sur tous les autres puis mettre celui la à defaut true
            $allFiltres = $em->getRepository(UtilisateurFiltre::class)->findBy(['utilisateur_role' => $userFilter->getUtilisateurRole(), 'page' => $userFilter->getPage(), 'site' => $userFilter->getSite()]);
            foreach ($allFiltres as $filtre) {
                $filtre->setDefaut(false);
                $em->persist($filtre);
            }
            $userFilter->setDefaut(true);
        }
        if ($defaut_utilisateur == "true" && !$userFilter->getDefautUtilisateur()) {
            //il faut mettre defaut = false sur tous les autres puis mettre celui la à defaut true
            $allFiltres = $em->getRepository(UtilisateurFiltre::class)->findBy(['page' => $userFilter->getPage(), 'utilisateur' => $this->getUser()]);
            foreach ($allFiltres as $filtre) {
                $filtre->setDefautUtilisateur(false);
                $em->persist($filtre);
            }
            $userFilter->setDefautUtilisateur(true);
        }

        $em->persist($userFilter);
        $em->flush();

        return new JsonResponse('', Response::HTTP_OK);
    }

    /**
     * @Route("/filters/{id}", methods="DELETE", name="remove_filters")
     *
     */
    public function removeUtilisateurFilters($id, UtilisateurFilterRepository $repository) {
        if ( $userFilter = $repository->findOneBy(['id' => $id, 'user' => $this->getUser()])) {
            $em = $this->getDoctrine()->getManager();
            $em->remove($userFilter);
            $em->flush();
        }

        return new JsonResponse('', Response::HTTP_OK);
    }

    private function majRangTri($em, $repository, $newRangTri, $oldRangTri) {
        //on récupère les entités et on les mets à jour
        $delta = ($oldRangTri) ? abs($oldRangTri - $newRangTri) : null;
        if ($delta == null)  {
            $entities = $repository->findNextRangTri($newRangTri, $delta);
            $addSub = '-';
        }
        elseif ($oldRangTri > $newRangTri) {
            $entities = $repository->findNextRangTri($newRangTri, $delta);
            $addSub = '+';
        } elseif ($oldRangTri < $newRangTri) {
            $entities = $repository->findPrevRangTri($newRangTri, $delta);
            $addSub = '-';
        }
        foreach ($entities as $entity) {
            $currentRangTri = $entity->getRangTri();
            $tmpRangTri = ($addSub == '+') ?  $currentRangTri + 1 : $currentRangTri - 1;
            $entity->setRangTri($tmpRangTri);
            $em->persist($entity);
        }
    }

    public function formatSetter ($name) {
        $return ='';
        $split = explode('_', $name);
        foreach ($split as $string) {
            $return .= ucfirst($string);
        }
        return $return;
    }

    public function getRealValue($value, $metadata, $key) {
        if ($value == 'true') $value = 1;
        elseif ($value == 'false') $value = 0;
        //si c'est un type date
        elseif (is_string($value) && false !== strtotime($value) && (isset($metadata->fieldMappings[$key]) &&in_array($metadata->fieldMappings[$key]['type'], ['date', 'datetime']))) {
            $value = new \DateTime($value);
        }
        elseif(isset($metadata->associationMappings[$key])) {
            $value = $this->getDoctrine()->getManager()->getRepository($metadata->associationMappings[$key]['targetEntity'])->find($value);
        }
        //si on a un ensemble d'id a transformer en object
        elseif(str_contains($key, 'IDs')) {
            $repoName = $this->getEntityName($this->formatSetter(substr(ucfirst($key),0,-4)));
            $value = $this->getDoctrine()->getManager()->getRepository($repoName)->findBy(['id' => $value]);
        }

        return $value;
    }

    private function getEntityName($page) {
        return "App\\Entity\\" .ucfirst($page);
    }

    public function getSerialisedEntities($entities, $serializer) {

        //$datas = [];

        $encoder = new JsonEncoder();
        $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
        $metadataAwareNameConverter = new MetadataAwareNameConverter($classMetadataFactory);
        $normalizer = new ObjectNormalizer($classMetadataFactory, $metadataAwareNameConverter);

        $serializer = new Serializer(array($normalizer), array($encoder));
        $datas = $serializer->serialize($entities, 'json', [
            'ignored_attributes' => Functions::getIgnoredAttributes()
        ]);

//        foreach ($entities as $entity) {
//            $datas[] = json_decode($serializer->serialize($entity, 'json', [
//                'ignored_attributes' => Functions::getIgnoredAttributes()
//            ]), true);
//        }

        return $datas;
    }

}
