<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Requirement\Requirement;
use Symfony\Component\Routing\Attribute\Route;
use Doctrine\ORM\EntityManagerInterface;

use App\Entity\Slot;
use App\Entity\Party;
use App\Entity\Gamemaster;
use App\Entity\Game;
use App\Entity\Event;
use App\Repository\SlotRepository;
use App\Repository\GamemasterRepository;
use App\Repository\GameRepository;
use App\Form\PartyType;

use App\Security\Voter\EventAccessVoter;

final class PartyController extends AbstractController
{

    // supprimer une partie
    #[Route('/party/delete/{id}', name: 'app_party_delete', requirements: ['id' => Requirement::UUID_V7], methods: ['GET'])]
    public function delete(?Party $party, Request $request, EntityManagerInterface $manager, SlotRepository $slotRepository): Response
    {
        // Seuls admin (ADMIN)
        $user = $this->getUser();
        $roles = $user->getRoles();
        if (in_array('ROLE_ADMIN', $roles)) {
            if ($party) {
                $party->purgeSlots();
                $manager->remove($party);
                $manager->flush($party);
                $this->addFlash('success', 'Partie supprimée !');
            } else {
                $this->addFlash('danger', 'Partie inexistante');
            }
        } else {
            $this->addFlash('danger', 'Seuls les admins peuvent supprimer une partie.');
        }
        $referer = $request->headers->get('referer'); 
        return $this->redirect($referer);  
    }

    // valider une partie proposée par un MJ
    #[Route('/party/validate/{id}', name: 'app_party_validate', requirements: ['id' => Requirement::UUID_V7], methods: ['GET'])]
    public function validate(?Party $party, Request $request, EntityManagerInterface $manager, SlotRepository $slotRepository): Response
    {
        // Seuls gestionnaires (MANAGER), admin (ADMIN)
        $user = $this->getUser();
        $roles = $user->getRoles();
        if (in_array('ROLE_ADMIN', $roles) || in_array('ROLE_MANAGER', $roles)) {
            if ($party) {
                $party->setValidated(true);
                $manager->persist($party);
                $manager->flush($party);
                $this->addFlash('success', 'Partie validée !');
            } else {
                $this->addFlash('danger', 'Partie inexistante');
            }
        } else {
            $this->addFlash('danger', 'Seuls les rôles Gestionnaires et Admin peuvent valider une partie');
        }
            $referer = $request->headers->get('referer'); 
            return $this->redirect($referer); 
    }

    // modifier une partie
    #[Route('/party/modify/{id}', name: 'app_party_modify', requirements: ['id' => '\d+'], methods: ['GET','POST'])]
    public function modify(?Slot $slot, Request $request, SlotRepository $slotRepository, GamemasterRepository $gamemasterRepository, GameRepository $gameRepository, EntityManagerInterface $manager): Response
    {
        // Seuls gestionnaires (MANAGER), admin (ADMIN) ou un MJ de l'asso (STAFF) qui est associé à l'événement
        $this->denyAccessUnlessGranted(EventAccessVoter::ACCESS_EVENT, $slot->getEvent());

        $user = $this->getUser();

        $party = $slot->getParty();
        if (!$party) {
            $this->addFlash('danger', 'Pas de partie trouvée.');
            $referer = $request->headers->get('referer'); 
            return $this->redirect($referer);
        }

        $roles = $user->getRoles();

        // Check MJ 
        if (in_array('ROLE_STAFF', $roles) && !(in_array('ROLE_ADMIN', $roles) || in_array('ROLE_MANAGER', $roles))) {
            // C'est un MJ, est-ce qu'il édite bien l'une de ses parties
            $gamemasters[] = $user->getLinkToGamemaster();
            if ($party->gamemaster != $gamemasters[0]) {
                // Alors dégage !
                $this->addFlash('danger', 'Un MJ ne peut éditer que ses parties.');
                $referer = $request->headers->get('referer'); 
                return $this->redirect($referer);              
            }
        } else {
            $gamemasters = $slot->getEvent()->getGamemastersAssigned();
        }

        // Création des valeurs dispo pour les formulaire
        $games = $slot->getEvent()->getGameAssigned();
        $lastSlot = $party->getSlots()->last();
        $getSlotsAvailables = $slotRepository->findNextsAvailables($lastSlot);
        $slotStart = $slot;
        $slotsAvailables = array_merge($party->getSlots()->toArray(), $getSlotsAvailables);

        $form = $this->createForm(PartyType::class, $party);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {

            // Ajouter les slots séléctionnés
            $slotsString = $request->request->get('party_slots');
            $gamemasterSelectedId = $request->request->get('party_gamemaster');
            $gamemasterSelected = $gamemasterRepository->findByStrID($gamemasterSelectedId);
            $gameSelectedId = $request->request->get('party_game');
            $gameSelected = $gameRepository->findByStrID($gameSelectedId);

            if ($gameSelected && $gamemasterSelected) {
                $party->purgeSlots();
                $new_slots = explode("|", $slotsString);
                foreach($new_slots as $add_this_slot) {
                    $add_this_slot_obj = $slotRepository->findById($add_this_slot);
                    $party->addSlot($add_this_slot_obj);
                }
                $slots = $party->getSlots();
                $party->setStartOn(clone $slots->first()->getStartOn());
                $party->setEndOn(clone $slots->last()->getEndOn());

                $party->setGamemaster($gamemasterSelected);
                $party->setGame($gameSelected);
                
                // Si gamemaster = author, alors !
                if (in_array($party->getGame(), $party->getGamemaster()->getAuthorOfGames()->toArray())) {
                    $party->setGamemasterIsAuthor(true);
                } else {
                    $party->setGamemasterIsAuthor(false);
                }

                $manager->persist($party);
                $manager->flush();

                // TODO: si c'est une partie non validée, envoyer un mail aux admin+gestionnaires pour validation

                $this->addFlash('success', 'Partie modifiée.');
            } else {
                $this->addFlash('danger', 'Pas de MJ ou de jeu sélectionné.');
            }
            $referer = $request->headers->get('referer'); 
            return $this->redirect($referer);
        }

        return $this->render('party/_modal.edit.html.twig', [
            'form' => $form,
            'party' => $party,
            'gamemasters' => $gamemasters,
            'games' => $games,
            'slotStart' => $slotStart,
            'slotsAvailables' => $slotsAvailables,
            'mod' => true,
            'pathController' => 'app_party_modify'
        ]);
    }

    // ajouter une partie
    #[Route('/party/add/{id}', name: 'app_party_add', requirements: ['id' => '\d+'], methods: ['GET','POST'])]
    public function add(?Slot $slot, Request $request, SlotRepository $slotRepository, GamemasterRepository $gamemasterRepository, GameRepository $gameRepository, EntityManagerInterface $manager): Response
    {
        // Seuls gestionnaires (MANAGER), admin (ADMIN) ou un MJ de l'asso (STAFF) qui est associé à l'événement
        $this->denyAccessUnlessGranted(EventAccessVoter::ACCESS_EVENT, $slot->getEvent());

        $user = $this->getUser();
        // Création de l'objet minimaliste
        $party = new Party();
        $party->setEvent($slot->getEvent());
        $party->setSubmitter($user);
        $party->setSubmittedDate(new \Datetime('now'));
        $party->setMinParticipants($_ENV['APP_DEFAULT_MIN_PARTICIPANTS']);
        $party->setMaxParticipants($_ENV['APP_DEFAULT_MAX_PARTICIPANTS']);
        $roles = $user->getRoles();

        if (in_array('ROLE_ADMIN', $roles) || in_array('ROLE_MANAGER', $roles)) {
            $party->setValidated(true);
            $gamemasters = $slot->getEvent()->getGamemastersAssigned();
            
        } else {
            // Note, le rôle admin et/ou manager prend le pas sur le rôle Staff/MJ
            $party->setValidated(false);
            $gamemasters = array();
            $gamemasters[] = $user->getLinkToGamemaster();
        }

        // Création des valeurs dispo pour les formulaire
        $games = $slot->getEvent()->getGameAssigned();
        $getSlotsAvailables = $slotRepository->findNextsAvailables($slot);
        $slotStart = $slot;
        $slotsAvailables = array_merge([$slotStart], $getSlotsAvailables);

        $form = $this->createForm(PartyType::class, $party);

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {

            // Ajouter les slots séléctionnés
            $slotsString = $request->request->get('party_slots');
            $gamemasterSelectedId = $request->request->get('party_gamemaster');
            $gamemasterSelected = $gamemasterRepository->findByStrID($gamemasterSelectedId);
            $gameSelectedId = $request->request->get('party_game');
            $gameSelected = $gameRepository->findByStrID($gameSelectedId);

            if ($gameSelected && $gamemasterSelected) {
                $new_slots = explode("|", $slotsString);
                foreach($new_slots as $add_this_slot) {
                    $add_this_slot_obj = $slotRepository->findById($add_this_slot);
                    $party->addSlot($add_this_slot_obj);
                }
                $party->setStartOn(clone $party->getSlots()[0]->getStartOn());
                $party->setEndOn(clone $party->getSlots()->last()->getEndOn());

                $party->setGamemaster($gamemasterSelected);
                $party->setGame($gameSelected);
                
                // Si gamemaster = author, alors !
                if (in_array($party->getGame(), $party->getGamemaster()->getAuthorOfGames()->toArray())) {
                    $party->setGamemasterIsAuthor(true);
                } else {
                    $party->setGamemasterIsAuthor(false);
                }

                $manager->persist($party);
                $manager->flush();

                // TODO: si c'est une partie non validée, envoyer un mail aux admin+gestionnaires pour validation

                $this->addFlash('success', 'Partie ajoutée au planning.');
            } else {
                $this->addFlash('danger', 'Pas de MJ ou de jeu sélectionné.');
            }
            $referer = $request->headers->get('referer'); 
            return $this->redirect($referer);

        }

        return $this->render('party/_modal.edit.html.twig', [
            'form' => $form,
            'party' => $party,
            'gamemasters' => $gamemasters,
            'games' => $games,
            'slotStart' => $slotStart,
            'slotsAvailables' => $slotsAvailables,
            'mod' => false,
            'pathController' => 'app_party_add'
        ]);
    }


}
