<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\CalendarBundle\Controller;

use Chill\CalendarBundle\Repository\CalendarRepository;
use Chill\CalendarBundle\Repository\InviteRepository;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Serializer\Model\Collection;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Annotation\Route;

class CalendarAPIController extends ApiController
{
    public function __construct(
        private readonly CalendarRepository $calendarRepository,
        private readonly InviteRepository $inviteRepository,
    ) {}

    #[Route(path: '/api/1.0/calendar/calendar/by-user/{id}.{_format}', name: 'chill_api_single_calendar_list_by-user', requirements: ['_format' => 'json'])]
    public function listByUser(User $user, Request $request, string $_format): JsonResponse
    {
        $this->denyAccessUnlessGranted('ROLE_USER');

        if (!$request->query->has('dateFrom')) {
            throw new BadRequestHttpException('You must provide a dateFrom parameter');
        }

        if (false === $dateFrom = \DateTimeImmutable::createFromFormat(
            \DateTimeImmutable::ATOM,
            $request->query->get('dateFrom')
        )) {
            throw new BadRequestHttpException('dateFrom not parsable');
        }

        if (!$request->query->has('dateTo')) {
            throw new BadRequestHttpException('You must provide a dateTo parameter');
        }

        if (false === $dateTo = \DateTimeImmutable::createFromFormat(
            \DateTimeImmutable::ATOM,
            $request->query->get('dateTo')
        )) {
            throw new BadRequestHttpException('dateTo not parsable');
        }

        // Get calendar items where user is the main user
        $ownCalendars = $this->calendarRepository->findByUser(
            $user,
            $dateFrom,
            $dateTo
        );

        // Get calendar items from accepted invites
        $acceptedInvites = $this->inviteRepository->findAcceptedInvitesByUserAndDateRange($user, $dateFrom, $dateTo);
        $inviteCalendars = array_map(fn ($invite) => $invite->getCalendar(), $acceptedInvites);

        // Merge
        $allCalendars = array_merge($ownCalendars, $inviteCalendars);
        $uniqueCalendars = [];
        $seenIds = [];

        foreach ($allCalendars as $calendar) {
            $id = $calendar->getId();
            if (!in_array($id, $seenIds, true)) {
                $seenIds[] = $id;
                $uniqueCalendars[] = $calendar;
            }
        }

        $total = count($uniqueCalendars);
        $paginator = $this->getPaginatorFactory()->create($total);

        $offset = $paginator->getCurrentPageFirstItemNumber();
        $limit = $paginator->getItemsPerPage();
        $ranges = array_slice($uniqueCalendars, $offset, $limit);

        $collection = new Collection($ranges, $paginator);

        return $this->json($collection, Response::HTTP_OK, [], ['groups' => ['calendar:light']]);
    }

    protected function customizeQuery(string $action, Request $request, $qb): void
    {
        if ($request->query->has('main_user')) {
            $qb->where('e.mainUser = :main_user')
                ->setParameter('main_user', $request->query->get('main_user'));
        }
    }

    protected function getContextForSerialization(string $action, Request $request, string $_format, $entity): array
    {
        switch ($action) {
            case '_index':
                switch ($request->getMethod()) {
                    case Request::METHOD_GET:
                        return ['groups' => ['calendar:read']];
                }
        }

        return parent::getContextForSerialization($action, $request, $_format, $entity);
    }
}
