<?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\InviteComponent;
use Zimbra\Mail\Struct\MimePartInfo;
use Zimbra\Mail\Struct\Msg;

/**
 * Creates a new calendar event in Zimbra.
 *
 * This class handles the creation of new calendar events in the Zimbra system.
 * It uses the Zimbra SOAP API to create events and returns a serialized ID that
 * can be used as remoteId for Calendar and CalendarRange.
 */
final readonly class CreateEvent
{
    public function __construct(
        private SoapClientBuilder $soapClientBuilder,
        private CreateZimbraComponent $createEvent,
        private TranslatorInterface $translator,
        private ZimbraIdSerializer $zimbraIdSerializer,
    ) {}

    /**
     * Creates a new calendar event in Zimbra.
     *
     * @param Calendar|CalendarRange|Invite $calendar The calendar event to create
     *
     * @return string The serialized Zimbra ID for the created event
     *
     * @throws CalendarWithoutMainUserException When the calendar has no associated user email
     */
    public function __invoke(Calendar|CalendarRange|Invite $calendar): string
    {
        if ($calendar instanceof Calendar) {
            $organizerEmail = $calendar->getMainUser()->getEmail();
            $organizerLang = $calendar->getMainUser()->getLocale();
        } elseif ($calendar instanceof Invite) {
            $organizerEmail = $calendar->getUser()->getEmail();
            $organizerLang = $calendar->getUser()->getLocale();
        } else {
            $organizerEmail = $calendar->getUser()->getEmail();
            $organizerLang = $calendar->getUser()->getLocale();
        }

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

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

        $comp = $this->createEvent->createZimbraInviteComponentFromCalendar($calendar);

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

        $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->createAppointment($msg, echo: true);

        $echo = $response->getEcho();
        $invite = $echo->getInvite();
        $MPInviteInfo = $invite->getInvite();
        /** @var InviteComponent $firstInvite */
        $firstInvite = $MPInviteInfo->getInviteComponents()[0];

        return $this->zimbraIdSerializer->serializeId(
            $response->getCalItemId(),
            $response->getCalInvId(),
            $firstInvite->getUid(),
        );
    }
}
