<?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\Groupe;
use App\Entity\GroupeType;
use App\Entity\GroupeUtilisateur;
use App\Entity\TchatMessage;
use App\Entity\Utilisateur;
use App\Form\ClientType;
use App\Form\GroupeEntityType;
use App\Utils\Functions;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\SerializerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Symfony\UX\Turbo\Stream\TurboStreamResponse;

/**
 * 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("/tchat")
 * @IsGranted("ROLE_USER")
 *
 */
class TchatController extends AbstractController
{
    /**
     * @Route("/conversations", name="tchat_conversations_get",  methods="GET")
     */
    public function getConversations(  SerializerInterface $serializer) {

        $groupes = [];
        $groupesAvecMessages= [];
        $user = $this->getUser();
        $groupesNouveauxMessages = $this->getDoctrine()->getManager()->getRepository(Groupe::class)->getGroupesNouveauxMessages($user);
        $totalNouveauxMessages = 0;
        foreach($this->getUser()->getGroupesUtilisateur() as $groupeUtilisateur) {
            $groupEntity = $groupeUtilisateur->getGroupe();
            $groupeTypeId = $groupEntity->getGroupeType()->getId();

            //en groupe interne, le nom du groupe est l'autre personne de la conversation
            if ($groupeTypeId == GroupeType::ID_TCHAT_INTERNE) {
                $otherUtilisateurInterne = $groupEntity->getGroupesUtilisateur()->filter(
                    function($entry) use ($user) {
                        return ($entry->getUtilisateur()->getId() != $user->getId());
                    }
                )->first()->getUtilisateur();
            }
            if ($groupEntity->getGroupeType()->getId()) {
                $groupeInfos = Functions::getSerialisedEntities($groupEntity, $serializer, 'site');
               // $groupeInfos = json_decode($serializer->serialize($groupEntity, 'json', ['ignored_attributes' => Functions::getIgnoredAttributes()], true));
                $groupeInfos['nom'] = ($groupEntity->getNom()) ? $groupEntity->getNom() : $otherUtilisateurInterne->getPrenom() . ' ' . $otherUtilisateurInterne->getNom();
                if (isset($groupesNouveauxMessages[$groupEntity->getId()])) {
                    $groupeInfos['nb_messages'] = $groupesNouveauxMessages[$groupEntity->getId()]['nb_messages'];
                    $totalNouveauxMessages+= $groupesNouveauxMessages[$groupEntity->getId()]['nb_messages'];
                    $groupesAvecMessages[$groupEntity->getGroupeType()->getId()][] =  $groupeInfos;
                } else {
                    $groupes[$groupEntity->getGroupeType()->getId()][] =  $groupeInfos;
                }
            }
        }
        //formulaire de création de groupe
        return  $this->render('tchat/_tchat_groups.html.twig', [
            'groupes' => $groupes,
            'groupesAvecMessages' => $groupesAvecMessages,
            'totalNouveauxMessages' => $totalNouveauxMessages,
            'type_agent' => GroupeType::ID_TCHAT_AGENT,
            'type_interne' => GroupeType::ID_TCHAT_INTERNE,
            'type_groupe' => GroupeType::ID_TCHAT_GROUPE,
        ]);

    }

    /**
     * @Route("/ajout_groupe", name="tchat_groupe_add_get",  methods="GET")
     */
    public function getAjoutGroupe(  SerializerInterface $serializer) {
        $formViewGroup = $this->createForm(GroupeEntityType::class, null, ['action' => $this->generateUrl('tchat_groupe_add', ['page' => 'Groupe'])])->createView();
        return  $this->render('tchat/_tchat_groupe_add.html.twig', [
            'form_groupe' => $formViewGroup,
        ]);

    }

    /**
     * @Route("/post", name="tchat_post",  methods="POST")
     */
    public function postMessage(Request $request, HubInterface $mercureHub)
    {
        $message = $request->request->get('message');
        $idGroupe = $request->get('id');

        $groupe = $this->getDoctrine()->getManager()->getRepository(Groupe::class)->find($idGroupe);
        $groupeUtilisateur = $this->getDoctrine()->getManager()->getRepository(GroupeUtilisateur::class)->findOneBy([
            'groupe' => $groupe,
            'utilisateur' => $this->getUser()
        ]);

        $em = $this->getDoctrine()->getManager();
        $tchat = new TchatMessage();
        $tchat->setContenu($message);
        $tchat->setUtilisateur($this->getUser());
        $tchat->setGroupe($groupe);

        $em->persist($tchat);
        $em->flush();
        $em->refresh($tchat);

        if ($groupeUtilisateur) {
            $groupeUtilisateur->setDernierMessageLu($tchat);
            $groupeUtilisateur->setDateDernierMessageLu(new \DateTime());
            $em->persist($groupeUtilisateur);
            $em->flush();
        }

        if ($request->isMethod('POST')) {
            $update = new Update(
                'canal/'. $idGroupe,
                json_encode(['id' => $idGroupe, 'name' => $groupe->getNom(), 'class_name' => GroupeType::TYPE_COLOR[$groupe->getGroupeType()->getId()], 'id_utilisateur' => $this->getUser()->getId()])
            );

            $mercureHub->publish($update);
        }

       return new JsonResponse();
    }

    /**
     * @Route("/load", name="tchat_get",  methods="GET")
     */
    public function loadMessages(Request $request, HubInterface $mercureHub) {
        $em = $this->getDoctrine()->getManager();
        //todo gérer restriction si le user a bien le droit d'afficher la conversation
        $idGroupe = $request->get('id');
        $name = $request->get('name');
        $class_name = $request->get('class_name');
        $read = $request->get('read');

        $groupe = $em->getRepository(Groupe::class)->find($idGroupe);
        //on insert le dernier message du group dans le tchat groupe utilisateur
        $tchatGroupeUtilisateur = $em->getRepository(GroupeUtilisateur::class)->findOneBy(['groupe' => $groupe, 'utilisateur' => $this->getUser()]);
        $sendMercure = false;
        $newMessage = false;
        if ($tchatGroupeUtilisateur) {
            $dernierMessageAutre = $em->getRepository(TchatMessage::class)->getDernierMessageAutre($this->getUser(), $groupe);
            if ($dernierMessageAutre) {
                if ($tchatGroupeUtilisateur->getDernierMessageLu() == $dernierMessageAutre && empty($tchatGroupeUtilisateur->getDateDernierMessageLu())) {
                    $tchatGroupeUtilisateur->setDateDernierMessageLu(new \DateTime());
                    $sendMercure = true;
                }

                elseif ($tchatGroupeUtilisateur->getDernierMessageLu() != $dernierMessageAutre) {
                    if ($read == "true") {
                        $tchatGroupeUtilisateur->setDernierMessageLu($dernierMessageAutre);
                        $tchatGroupeUtilisateur->setDateDernierMessageLu(new \DateTime());
                        $sendMercure = true;
                    } else  $newMessage = true;
                }

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

                if ($sendMercure) {
                    //on prévient sur mercure qu'un message a été lu
                    $update = new Update(
                        'canal/'. $idGroupe,
                        json_encode(['id' => $idGroupe, 'name' => $groupe->getNom(), 'class_name' => GroupeType::TYPE_COLOR[$groupe->getGroupeType()->getId()], 'id_utilisateur' => $this->getUser()->getId()])
                    );

                    $mercureHub->publish($update);
                }

            }
        }


        return  $this->render('tchat/_popup_messages.html.twig', [
            'messages' => $groupe->getMessages(),
            'id' => $idGroupe,
            'name' => $name,
            'class_name' => $class_name,
            'new_message'=> $newMessage,
            'nb_utilisateur_groupe' => count($groupe->getGroupesUtilisateur())
        ]);
    }

    /**
     * @Route("/load/groupe/{id}", name="tchat_get_groupe_config",  methods="GET")
     */
    public function loadGroupConfig(Request $request, $id) {
        $em = $this->getDoctrine()->getManager();
        $groupe = $em->getRepository(Groupe::class)->find($id);

        return  $this->render('tchat/_tchat_groupe_config.html.twig', [
            'groupe' => $groupe
        ]);
    }

    /**
     * @Route("/patch/group_utilisateur/{idgroupe}/{idutilisateur}", name="tchat_groupe_utilisateur_patch",  methods="PATCH")
     */
    public function patchGroupeUtilisateur($idgroupe, $idutilisateur) {
        $em = $this->getDoctrine()->getManager();
        $groupe = $em->getRepository(Groupe::class)->find($idgroupe);
        $utilisateur = $em->getRepository(Utilisateur::class)->find($idutilisateur);
        if ($groupe != null && $utilisateur != null) {
            $groupeUtilisateur = $em->getRepository(GroupeUtilisateur::class)->findOneBy(['utilisateur' => $utilisateur, 'groupe' => $groupe]);
            if ($groupeUtilisateur != null) {
                //seul l'admin peut faire la modif
                if ($this->getUser() == $groupeUtilisateur->getGroupe()->getAdmin()) {
                    $newNotification = (int)!($groupeUtilisateur->getNotification());
                    $groupeUtilisateur->setNotification($newNotification);
                    $em->persist($groupeUtilisateur);
                    $em->flush();
                    return new JsonResponse(['messages' => ['success' => ["Modification effectuée avec succès"]]], Response::HTTP_OK);
                } else {
                    return new JsonResponse('', Response::HTTP_FORBIDDEN);
                }
            } else {
                return new JsonResponse('', Response::HTTP_NOT_FOUND);
            }
        } else {
            return new JsonResponse('', Response::HTTP_NOT_FOUND);
        }
    }

    /**
     * @Route("/post/group_utilisateur", name="tchat_groupe_utilisateur_post",  methods="POST")
     */
    public function postGroupeUtilisateur(Request $request, SerializerInterface $serializer) {
        $em = $this->getDoctrine()->getManager();

        $idUtilisateur = $request->request->get('utilisateur');
        $idGroupe = $request->request->get('groupe');
        $groupe = $em->getRepository(Groupe::class)->find($idGroupe);
        $user = $em->getRepository(Utilisateur::class)->find($idUtilisateur);

        $groupeUtilisateur = new GroupeUtilisateur();
        $groupeUtilisateur->setUtilisateur($user);
        $groupeUtilisateur->setGroupe($groupe);

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

        $data = [
            'nomComplet' => $user->getNomComplet(),
            'idGroupe' => $groupe->getId(),
            'idUtilisateur' => $groupeUtilisateur->getUtilisateur()->getId(),
        ];

        return new JsonResponse(['entite' => $data], 200);
    }

    /**
     * @Route("/get/user_not_in_groupe/{id}", name="tchat_user_not_in_groupe",  methods="GET")
     */
    public function getUtilisateurNotInGroupe($id) {
        $em = $this->getDoctrine()->getManager();
        $groupe = $em->getRepository(Groupe::class)->find($id);
        if ($groupe != null) {
            //seul l'admin peut faire la modif
            if ($this->getUser() ==  $groupe->getAdmin()) {
                $users = $em->getRepository(Utilisateur::class)->getUtilisateursWithNotIn($groupe->getUtilisateurs());
                return  $this->render('tchat/_list_utilisateurs_groupe.html.twig', ['users' => $users, 'groupe' => $groupe]);
            } else {
                return new Response('', Response::HTTP_FORBIDDEN);
            }
        } else {
            return new Response('', Response::HTTP_NOT_FOUND);
        }
    }

    /**
     * @Route("/delete/group_utilisateur/{idgroupe}/{idutilisateur}", name="tchat_groupe_utilisateur_delete",  methods="DELETE")
     */
    public function deleteGroupeUtilisateur($idgroupe, $idutilisateur) {
        $em = $this->getDoctrine()->getManager();
        $groupe = $em->getRepository(Groupe::class)->find($idgroupe);
        $utilisateur = $em->getRepository(Utilisateur::class)->find($idutilisateur);
        if ($groupe != null && $utilisateur != null) {
            $groupeUtilisateur = $em->getRepository(GroupeUtilisateur::class)->findOneBy(['utilisateur' => $utilisateur, 'groupe' => $groupe]);
            if ($groupeUtilisateur != null) {
                //seul l'admin peut faire la modif
                if ($this->getUser() ==  $groupeUtilisateur->getGroupe()->getAdmin()) {
                    $em->remove($groupeUtilisateur);
                    $em->flush();
                    return new JsonResponse(['messages' => ['success' => ["Suppression effectuée avec succès"]]], Response::HTTP_OK);
                } else {
                    return new JsonResponse('', Response::HTTP_FORBIDDEN);
                }
            } else {
                return new JsonResponse('', Response::HTTP_NOT_FOUND);
            }
        } else {
            return new JsonResponse('', Response::HTTP_NOT_FOUND);
        }
    }

    /**
     * @Route("add/groupe", name="tchat_groupe_add", methods="POST")
     */
    public function addGroupe(Request $request) {
        $em = $this->getDoctrine()->getManager();

        $datas = $request->request->get('tchat_groupe_entity');
        $nom = $datas['nom'];
        $user = $datas['user'];

        if ($nom && $user) {
            //on check si un groupe ne porte pas déjà le même nom
            $groupe = $em->getRepository(Groupe::class)->findBy(['nom' => $nom]);
            if ($groupe) return  new JsonResponse(['error' => ['ce groupe existe déjà']], Response::HTTP_OK);

            $tchatGroupe = new Groupe();
            $tchatGroupe->setNom($nom);
            $tchatGroupe->setAdmin($this->getUser());

            $tchatGroupeType = $em->getRepository(GroupeType::class)->find(GroupeType::ID_TCHAT_GROUPE);
            $tchatGroupe->setGroupeType($tchatGroupeType);

            if (!in_array($this->getUser()->getId(), $user)) {
               $user[] = $this->getUser()->getId();
            }
            foreach ($user as $u) {
                $userTmp = $em->getRepository(Utilisateur::class)->find($u);

                $tchatGroupeUtilisateurTmp = new GroupeUtilisateur();
                $tchatGroupeUtilisateurTmp->setUtilisateur($userTmp);
                $tchatGroupeUtilisateurTmp->setGroupe($tchatGroupe);
                $tchatGroupeUtilisateurTmp->setNotification(false);

                $tchatGroupe->addGroupeUtilisateur($tchatGroupeUtilisateurTmp);
                $em->persist($tchatGroupeUtilisateurTmp);
            }
            $em->persist($tchatGroupe);
            $em->flush();
        }

        $response = $this->getConversations($this->get('serializer'))->getContent();
        return new JsonResponse(['messages' => ['success' => ['Groupe ajouté avec succès']], 'groups' => $response], Response::HTTP_OK);
    }

    /**
     * @Route("/delete/groupe/{id}", name="tchat_groupe_delete", methods="DELETE")
     */
    public function deleteGroupe($id, Request $request) {

        $em = $this->getDoctrine()->getManager();
        $groupe = $em->getRepository(Groupe::class)->find($id);

        if ($this->getUser() != $groupe->getAdmin()) return new JsonResponse(['messages' => ['error' => ['Suppression du groupe non autorisé']]], Response::HTTP_FORBIDDEN);

        if ($groupe) {
            $em->remove($groupe);
            $em->flush();

           $response = $this->getConversations($this->get('serializer'))->getContent();
            return new JsonResponse(['messages' => ['success' => ['Groupe supprimé avec succès']], 'groups' => $response], Response::HTTP_OK);
        } else {
            return new JsonResponse(['messages' => ['error' => ['Groupe non trouvé']]], Response::HTTP_NOT_FOUND);
        }
    }
}
