<?php

/**
 * 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.
 */

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\Messenger\Handler;

use Chill\CalendarBundle\Messenger\Message\MSGraphChangeNotificationMessage;
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MapCalendarToUser;
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\RemoteToLocalSync\CalendarRangeSyncer;
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\RemoteToLocalSync\CalendarSyncer;
use Chill\CalendarBundle\Repository\CalendarRangeRepository;
use Chill\CalendarBundle\Repository\CalendarRepository;
use Chill\MainBundle\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;

/**
 * Handle notification of changes made by users directly on Outlook calendar.
 *
 * @AsMessageHandler
 */
class MSGraphChangeNotificationHandler implements MessageHandlerInterface
{
    public function __construct(private readonly CalendarRangeRepository $calendarRangeRepository, private readonly CalendarRangeSyncer $calendarRangeSyncer, private readonly CalendarRepository $calendarRepository, private readonly CalendarSyncer $calendarSyncer, private readonly EntityManagerInterface $em, private readonly LoggerInterface $logger, private readonly MapCalendarToUser $mapCalendarToUser, private readonly UserRepository $userRepository) {}

    public function __invoke(MSGraphChangeNotificationMessage $changeNotificationMessage): void
    {
        $user = $this->userRepository->find($changeNotificationMessage->getUserId());

        if (null === $user) {
            $this->logger->warning(self::class.' notification concern non-existent user, skipping');

            return;
        }

        foreach ($changeNotificationMessage->getContent()['value'] as $notification) {
            $secret = $this->mapCalendarToUser->getSubscriptionSecret($user);

            if ($secret !== ($notification['clientState'] ?? -1)) {
                $this->logger->warning(self::class.' could not validate secret, skipping');

                continue;
            }

            $remoteId = $notification['resourceData']['id'];

            // is this a calendar range ?
            if (null !== $calendarRange = $this->calendarRangeRepository->findOneBy(['remoteId' => $remoteId])) {
                $this->calendarRangeSyncer->handleCalendarRangeSync($calendarRange, $notification, $user);
                $this->em->flush();
            } elseif (null !== $calendar = $this->calendarRepository->findOneBy(['remoteId' => $remoteId])) {
                $this->calendarSyncer->handleCalendarSync($calendar, $notification, $user);
                $this->em->flush();
            } else {
                $this->logger->info(self::class.' id not found in any calendar nor calendar range');
            }
        }

        $this->em->flush();
    }
}
