<?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\RemoteCalendar\Connector\MSGraph\RemoteToLocalSync;

use Chill\CalendarBundle\Entity\CalendarRange;
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\MachineHttpClient;
use Chill\CalendarBundle\RemoteCalendar\Connector\MSGraph\RemoteEventConverter;
use Chill\MainBundle\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;

class CalendarRangeSyncer
{
    /**
     * @param MachineHttpClient $machineHttpClient
     */
    public function __construct(private readonly EntityManagerInterface $em, private readonly LoggerInterface $logger, private readonly HttpClientInterface $machineHttpClient) {}

    public function handleCalendarRangeSync(CalendarRange $calendarRange, array $notification, User $user): void
    {
        switch ($notification['changeType']) {
            case 'deleted':
                // test if the notification is not linked to a Calendar
                if (null !== $calendarRange->getCalendar()) {
                    return;
                }
                $calendarRange->preventEnqueueChanges = true;

                $this->logger->info(self::class.' remove a calendar range because deleted on remote calendar');
                $this->em->remove($calendarRange);

                break;

            case 'updated':
                try {
                    $new = $this->machineHttpClient->request(
                        'GET',
                        $notification['resource']
                    )->toArray();
                } catch (ClientExceptionInterface $clientException) {
                    $this->logger->warning(self::class.' could not retrieve event from ms graph. Already deleted ?', [
                        'calendarRangeId' => $calendarRange->getId(),
                        'remoteEventId' => $notification['resource'],
                    ]);

                    throw $clientException;
                }

                $lastModified = RemoteEventConverter::convertStringDateWithTimezone($new['lastModifiedDateTime']);

                if ($calendarRange->getRemoteAttributes()['lastModifiedDateTime'] === $lastModified->getTimestamp()) {
                    $this->logger->info(self::class.' change key is equals. Source is probably a local update', [
                        'calendarRangeId' => $calendarRange->getId(),
                        'remoteEventId' => $notification['resource'],
                    ]);

                    return;
                }

                $startDate = RemoteEventConverter::convertStringDateWithoutTimezone($new['start']['dateTime']);
                $endDate = RemoteEventConverter::convertStringDateWithoutTimezone($new['end']['dateTime']);

                $calendarRange
                    ->setStartDate($startDate)->setEndDate($endDate)
                    ->addRemoteAttributes([
                        'lastModifiedDateTime' => $lastModified->getTimestamp(),
                        'changeKey' => $new['changeKey'],
                    ])
                    ->preventEnqueueChanges = true;

                break;

            default:
                throw new \RuntimeException('This changeType is not suppored: '.$notification['changeType']);
        }
    }
}
