<?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\ZimbraBundle\Calendar\Connector\ZimbraConnector;

use Chill\CalendarBundle\Entity\Calendar;
use Chill\CalendarBundle\Entity\CalendarRange;
use Chill\CalendarBundle\Entity\Invite;
use Chill\ZimbraBundle\Exception\CalendarWithoutMainUserException;
use Symfony\Contracts\Translation\TranslatorInterface;
use Zimbra\Mail\Struct\InvitationInfo;
use Zimbra\Mail\Struct\MimePartInfo;
use Zimbra\Mail\Struct\Msg;

/**
 * Updates an existing calendar event in Zimbra.
 *
 * This class handles the modification of existing calendar events in the Zimbra system.
 * It uses the Zimbra SOAP API to update event details while maintaining the original
 * event's metadata like IDs and sequences.
 */
final readonly class UpdateEvent
{
    public function __construct(
        private SoapClientBuilder $soapClientBuilder,
        private CreateZimbraComponent $createZimbraComponent,
        private TranslatorInterface $translator,
        private ZimbraIdSerializer $zimbraIdSerializer,
    ) {}

    /**
     * Updates an existing calendar event in Zimbra.
     *
     * @param Calendar|CalendarRange $calendar The calendar event to update
     *
     * @throws CalendarWithoutMainUserException When the calendar has no associated user email
     */
    public function __invoke(Calendar|CalendarRange|Invite $calendar): void
    {
        if ($calendar instanceof Calendar) {
            $organizerEmail = $calendar->getMainUser()->getEmail();
            $organizerLang = $calendar->getMainUser()->getLocale();
        } elseif ($calendar instanceof Invite) {
            $organizerEmail = $calendar->getCalendar()->getMainUser()->getEmail();
            $organizerLang = $calendar->getCalendar()->getMainUser()->getLocale();
        } else {
            $organizerEmail = $calendar->getUser()->getEmail();
            $organizerLang = $calendar->getUser()->getLocale();
        }

        if (null === $organizerEmail) {
            throw new CalendarWithoutMainUserException();
        }

        $api = $this->soapClientBuilder->getApiForAccount($organizerEmail);

        ['calItemId' => $calItemId, 'calInvId' => $calInvId, 'inviteComponentCommonUid' => $inviteComponentCommonUid]
            = $this->zimbraIdSerializer->deSerializeId($calendar->getRemoteId());

        $existing = $api->getAppointment(sync: true, includeContent: true, includeInvites: true, id: $calItemId);
        $appt = $existing->getApptItem();

        $comp = $this->createZimbraComponent->createZimbraInviteComponentFromCalendar($calendar);
        $comp->setUid($inviteComponentCommonUid);

        $inv = new InvitationInfo();
        $inv->setInviteComponent($comp)
            ->setUid($calInvId);

        $mp = new MimePartInfo();
        $mp->addMimePart(new MimePartInfo('text/plain', $this->translator->trans('zimbra.event_created_by_chill', locale: $organizerLang)));

        $msg = new Msg();
        $msg->setSubject($this->translator->trans('zimbra.event_created_trough_soap', locale: $organizerLang))
            ->setFolderId('10')
            ->setInvite($inv)
            ->setMimePart($mp)
        ;

        $response = $api->modifyAppointment(
            id: $calInvId,
            componentNum: 0,
            modifiedSequence: $appt->getModifiedSequence(),
            revision: $appt->getRevision(),
            msg: $msg,
            echo: true
        );
    }
}
