<?php

namespace App\Controller\Admin\EventConfig;

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

use App\Entity\Event;
use App\Entity\Slot;
use App\Repository\SlotRepository;

use App\Service\DateTimeHelper;

final class SlotController extends AbstractController
{
    #[Route('/api/slot/{id}/toggleStatus', name: 'api_slot_toggle_status', requirements: ['id' => '\d+'], methods: ['POST'])]
    public function apiSlotToggleStatus(?Slot $slot, EntityManagerInterface $manager): JsonResponse
    {
        // Accès uniquement aux admin
        if (!$this->isGranted('ROLE_ADMIN')) {
            return $this->json(['error' => 'Unauthorized'], 403);
        }
        if (!$slot) {
            return $this->json(['error' => 'Slot not found'], 404);
        }

        $returnCode = "ERROR";

        // Partie, on arrête et modifie pas la BDD
        if ($slot->getParty()) {
            $returnCode = "PARTY|".$slot->getParty()->getId()->toString();
        } else {
            // Bascule Unavaible -> Available
            if ($slot->isUnavailable()) {
                $slot->setUnavailable(false);
                $manager->persist($slot);
                $manager->flush();
                $returnCode = "UNLOCKED";
            } else {
                $slot->setUnavailable(true);
                $manager->persist($slot);
                $manager->flush();
                $returnCode = "LOCKED";
            }
        }
        return $this->json(["status" => $returnCode]);
    }

    #[Route('/api/slot/{id}/nexts', name: 'api_slot_nexts', requirements: ['id' => '\d+'], methods: ['POST'])]
    public function apiSlotNexts(?Slot $slot, SlotRepository $repository): JsonResponse
    {
        // Accès uniquement aux gestionnaires ou admin
        if (!$this->isGranted('ROLE_MANAGER')) {
            return $this->json(['error' => 'Unauthorized'], 403);
        }
        if (!$slot) {
            return $this->json(['error' => 'Slot not found'], 404);
        }

        $nextSlots = $repository->findNextsAvailables($slot);
        array_unshift($nextSlots, $slot);

        // On extrait les IDs des slots suivants
        $ids = array_map(fn($s) => $s->getId(), $nextSlots);
        
        // On choppe aussi début et un tableau des horaires de fin
        $startDate = $slot->getStartOn();
        $startDate->setTimezone(new \DateTimeZone($_ENV['APP_TZ']));
        $startDateStr = $startDate->format('d/m/y H:i');

        $endDatesStr = array_map(fn($s) => $s->getEndOn()
                                          ->setTimezone(new \DateTimeZone($_ENV['APP_TZ']))
                                          ->format('d/m/y H:i'),
                              $nextSlots);

        
        return $this->json(["next_slots" => $ids,
                            "start_date" => $startDateStr,
                            "end_dates" => $endDatesStr]);
    }



    #[Route('/admin/event/{id}/configure/slot', name: 'app_admin_event_config_slot', requirements: ['id' => Requirement::UUID_V7], methods: ['GET'])]
    public function index(?Event $event, Request $request, EntityManagerInterface $manager, SlotRepository $repository): Response
    {
        return $this->render('admin/event/config/slot.html.twig', [
            'event' => $event,
        ]);
    }

    #[Route('/admin/event/{id}/configure/slot/generate', name: 'app_main_event_config_slot_generate', requirements: ['id' => Requirement::UUID_V7], methods: ['GET'])]
    public function generate(?Event $event, Request $request, EntityManagerInterface $manager, SlotRepository $repository, DateTimeHelper $dateTimeHelper): Response
    {
        // On réalise avant tous les contrôles, sinon, on alerte
        if (count($event->getSpaces()) < 1)
        {
            // Aucun slot n'est généré, on quitte
            $this->addFlash('danger', 'Aucun espace disponible !');
        }
        if (count($event->getPeriods()) < 1)
        {
            // Aucun slot n'est généré, on quitte
            $this->addFlash('danger', 'Aucune période disponible !');
        }
        if (count($event->getSlots()) > 0)
        {
            // Des slots existent déjà, on quitte
            $this->addFlash('danger', 'Supprimez les slots existants avant de régénérer !');
        }
        else
        {
            // C'est bon, on a des espaces, des périodes et pas encore de slots
            // On incrémente sur les espaces
            $countGenSlot = 0;
            foreach ($event->getSpaces() as $space)
            {
                // Et ensuite sur les périodes
                foreach ($event->getPeriods() as $period)
                {
                    // RAPPEL : l'id généré n'est pas une donnée FIABLE !
                    // Composer les plannings avec startOn suivent == endOn précédent pour descendre les colonnes
                    // et startOn courant == startOn courant avec un même "event" pour les lignes
                    
                    // StatIndex, on commence à la première heure entière ou demi-heure entière qui suit le début de la période
                    $startIndex = $dateTimeHelper->roundUpToNextSlot($period->getStartOn());

                    // Tant que $startIndex est < $period->getEndOn(), on s'arrête au dernier "bout de slot" avant la fin
                    while ($startIndex < $period->getEndOn())
                    {
                        // On génère chaque slot de cette période pour cet espace et surtout, cet événement et on le marque comme disponible
                        $newSlot = new Slot();
                        $newSlot->setEvent($event);
                        $newSlot->setSpace($space);
                        $newSlot->setPeriod($period);
                        $newSlot->setUnavailable(false);
                        // Ajout de la date de début = Index
                        $newSlot->setStartOn(clone $startIndex);
                        // on incrémente l'index de 30 minutes pour la suite
                        $startIndex->add(new \DateInterval('PT30M'));
                        // et on l'utilise aussi pour la fin
                        $newSlot->setEndOn(clone $startIndex);
                        $event->addSlot($newSlot);
                        // Hop, dans la BDD en attente de sauvegarde
                        $manager->persist($newSlot);
                        $countGenSlot++;
                    }
                    // On marque la période comme utilisée et vérouillée
                    $period->setLocked(true);
                    $manager->persist($period);
                }
                // On marque l'espace comme utilisé et vérouillé
                $space->setLocked(true);
                $manager->persist($space);
            }
            $manager->flush();
            $controlValue = count($event->getSlots());
            $this->addFlash('info', $countGenSlot.' slots générés. '.$controlValue.' slots enregistrés dans la base de données.');
        }

        // On retourne à la page de configuration
        return $this->redirectToRoute('app_admin_event_config_slot', ['id' => $event->getId()]);
    }

    #[Route('/admin/event/{id}/configure/slot/delete', name: 'app_main_event_config_slot_delete', requirements: ['id' => Requirement::UUID_V7], methods: ['GET'])]
    public function delete(?Event $event, Request $request, EntityManagerInterface $manager, SlotRepository $repository): Response
    {
        $slots = $event->getSlots();
        foreach ($slots as $slot) {
            $slot->getPeriod()->setLocked(false);
            $slot->getSpace()->setLocked(false);
            $manager->remove($slot);
        }
        $manager->flush();
        // On retourne à la page de configuration
        return $this->redirectToRoute('app_admin_event_config_slot', ['id' => $event->getId()]);        
    }


}
