<?php

namespace Ig\IgReservations\Controller;

use Internetgalerie\IgDatapoolFe\Controller\ActionController;
use DateTime;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use DateTimeZone;
use RuntimeException;
use TYPO3\CMS\Extbase\Mvc\Controller\Argument;
use Ig\IgReservations\Domain\Model\Calendar;
use Ig\IgReservations\Domain\Model\Event;
use Ig\IgReservations\Domain\Model\FeUser;
use Ig\IgReservations\Domain\Model\Reservation;
use Ig\IgReservations\Domain\Model\Timeslot;
use Ig\IgReservations\Domain\Repository\BookingTypeRepository;
use Ig\IgReservations\Domain\Repository\CalendarGroupRepository;
use Ig\IgReservations\Domain\Repository\CalendarRepository;
use Ig\IgReservations\Domain\Repository\CategoryRepository;
use Ig\IgReservations\Domain\Repository\EventRepository;
use Ig\IgReservations\Domain\Repository\FeUserRepository;
use Ig\IgReservations\Domain\Repository\LocationRepository;
use Ig\IgReservations\Domain\Repository\PurposeRepository;
use Ig\IgReservations\Domain\Repository\ReservationRepository;
use Ig\IgReservations\Domain\Repository\ReservationTypeRepository;
use Ig\IgReservations\Domain\Repository\StatusRepository;
use Ig\IgReservations\Domain\Repository\TimeslotRepository;
use Ig\IgReservations\Service\MailService;
use Ig\IgReservations\Service\UserService;
use Internetgalerie\IgDatapoolFe\Property\TypeConverter\HtmlConverter;
use Internetgalerie\IgDynval\Controller\DynamicValidationActionController;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Core\Context\Context;
use TYPO3\CMS\Core\Http\HtmlResponse;
use TYPO3\CMS\Core\Http\JsonResponse;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Extbase\Event\Mvc\BeforeActionCallEvent;
use TYPO3\CMS\Extbase\Mvc\RequestInterface;
use TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration;
use TYPO3\CMS\Extbase\Property\TypeConverter\DateTimeConverter;

/**
 * AjaxController
 */
class AjaxController extends ActionController
{
    use DynamicValidationActionController;

    /**
     * Ist ein Fehler aufgetreten
     *
     * @var bool
     */
    protected $error = false;

    /**
     * toastr type (one of 'info', 'success', 'warning', 'error')
     *
     * @var string
     */
    protected $toastType = 'success';

    /**
     * toastr title
     *
     * @var string
     */
    protected $toastTitle = '';

    /**
     * toastr message
     *
     * @var string
     */
    protected $toastMessage = '';

    /**
     * MailService
     *
     * @var MailService
     */
    protected $mailService = null;

    protected $objectClass = \Ig\IgReservations\Domain\Model\Reservation::class;

    protected ?DateTime $date = null;
    protected ?Calendar $calendar = null;
    protected ?Timeslot $timeslot = null;
    protected ?Event $event = null;
    protected ?Reservation $reservation = null;
    protected ?FeUser $frontendUser = null;

    protected EventRepository $eventRepository;
    protected ReservationRepository $reservationRepository;
    protected StatusRepository $statusRepository;
    protected BookingTypeRepository $bookingTypeRepository;
    protected FeUserRepository $feUserRepository;
    protected TimeslotRepository $timeslotRepository;
    protected CalendarGroupRepository $calendarGroupRepository;
    protected CategoryRepository $categoryRepository;
    protected LocationRepository $locationRepository;
    protected CalendarRepository $calendarRepository;
    protected ReservationTypeRepository $reservationTypeRepository;
    protected PurposeRepository $purposeRepository;

    /**
     * @var \Ig\IgReservations\Service\UserService
     */
    protected UserService $userService;

    public function injectEventRepository(EventRepository $eventRepository): void
    {
        $this->eventRepository = $eventRepository;
    }

    public function injectReservationRepository(ReservationRepository $reservationRepository): void
    {
        $this->reservationRepository = $reservationRepository;
    }

    public function injectStatusRepository(StatusRepository $statusRepository): void
    {
        $this->statusRepository = $statusRepository;
    }

    public function injectBookingTypeRepository(BookingTypeRepository $bookingTypeRepository): void
    {
        $this->bookingTypeRepository = $bookingTypeRepository;
    }

    public function injectFeUserRepository(FeUserRepository $feUserRepository): void
    {
        $this->feUserRepository = $feUserRepository;
    }

    public function injectTimeslotRepository(TimeslotRepository $timeslotRepository): void
    {
        $this->timeslotRepository = $timeslotRepository;
    }

    public function injectCalendarGroupRepository(CalendarGroupRepository $calendarGroupRepository): void
    {
        $this->calendarGroupRepository = $calendarGroupRepository;
    }

    public function injectCategoryRepository(CategoryRepository $categoryRepository): void
    {
        $this->categoryRepository = $categoryRepository;
    }

    public function injectPurposeRepository(PurposeRepository $purposeRepository): void
    {
        $this->purposeRepository = $purposeRepository;
    }

    public function injectLocationRepository(LocationRepository $locationRepository): void
    {
        $this->locationRepository = $locationRepository;
    }

    public function injectCalendarRepository(CalendarRepository $calendarRepository): void
    {
        $this->calendarRepository = $calendarRepository;
    }

    public function injectReservationTypeRepository(ReservationTypeRepository $reservationTypeRepository): void
    {
        $this->reservationTypeRepository = $reservationTypeRepository;
    }
    
    public function injectMailService(MailService $mailService): void
    {
        $this->mailService = $mailService;
    }

    public function injectUserService(UserService $userService): void
    {
        $this->userService = $userService;
    }

    /**
     * [frontendUserFormAction description]
     * @param  string $date     [description]
     * @param Timeslot $timeslot [description]
     * @param Calendar $calendar [description]
     * @param Reservation $reservation [description]
     */
    public function initCalendar(
        ?string $date = null,
        ?Timeslot $timeslot = null,
        ?Calendar $calendar = null,
        ?Reservation $reservation = null,
        ?Event $event = null
    ): void {
        $this->date = new DateTime($date ?: null);
        $this->date->setTime(12, 0, 0);

        if ($calendar) {
            $this->calendar = $calendar;
        }
        if ($timeslot) {
            $this->timeslot = $timeslot;
        }
        if ($event) {
            $this->event = $event;
        }
        if ($reservation) {
            $this->reservation = $reservation;
        }

        $user = $this->userService->getUser();
        if ($user) {
            $this->frontendUser = $user;
        }

        if (!$this->event && $this->timeslot) {
            $this->event = $this->eventRepository->findOneByDateAndTimeslotAndCalendar(
                $this->date,
                $this->timeslot->getUid(),
                $calendar->getUid()
            );
        }
    }

    /**
     * [assignCalendar description]
     * @param  boolean $error [description]
     */
    public function assignCalendar(bool $error): void
    {
        $this->error = $error;
        if ($this->error) {
            $this->toastType = 'error';
            $this->toastTitle = 'Fehler beim Speichern';
            $this->toastMessage = 'Reservation nicht möglich';
        }
        $this->view->assign('error', $this->error);
        $this->view->assign('calendar', $this->calendar);
        $this->view->assign('date', $this->date);
        $this->view->assign('dateValue', $this->date ? $this->date->format('Y-m-d') : '');
        $this->view->assign('timeslot', $this->timeslot);
        $this->view->assign('event', $this->event);
        $this->view->assign('user', $this->frontendUser);
        $this->view->assign('purposes', $this->purposeRepository->findAll());

        // used for redirects - todo check if this can be different
        $this->view->assign('source', [
            'controller' => 'Calendar',
            'action' => 'show',
            'pluginName' => 'PublicCalendar',
        ]);
    }

    /**
     * [frontendUserFormAction description]
     * @param  string $date     [description]
     * @param Timeslot $timeslot [description]
     * @param Calendar $calendar [description]
     */
    public function frontendUserFormAction(
        ?string $date = null,
        ?Timeslot $timeslot = null,
        ?Calendar $calendar = null
    ): ResponseInterface {
        $this->initCalendar($date, $timeslot, $calendar);

        $frontendUsers = $this->feUserRepository->findAjaxRaw();
        $this->view->assign('frontendUsers', $frontendUsers);

        $this->assignCalendar(false);

        return new HtmlResponse($this->view->render());
    }

    /**
     * [frontendUserFormAction description]
     * @param  string $date     [description]
     * @param Timeslot $timeslot [description]
     * @param Calendar $calendar [description]
     */
    public function guestFormAction(
        ?string $date = null,
        ?Timeslot $timeslot = null,
        ?Calendar $calendar = null
    ): ResponseInterface {
        $this->initCalendar($date, $timeslot, $calendar);
        $this->assignCalendar(false);

        return new HtmlResponse($this->view->render());
    }

    /**
     * [frontendUserFormAction description]
     * @param  string $date     [description]
     * @param Reservation $reservation [description]
     * @param Timeslot $timeslot [description]
     * @param Calendar $calendar [description]
     */
    public function reservationCreateFormAction(
        ?string $date = null,
        ?Reservation $reservation = null,
        ?Timeslot $timeslot = null,
        ?Calendar $calendar = null,
        ?Event $event = null
    ): ResponseInterface {
        if ($event && !$reservation) {
            $reservation = GeneralUtility::makeInstance(Reservation::class);
            $reservation->setEvent($event);
        } elseif ($event && $reservation) {
            $reservation->setEvent($event);
        }
        $this->initCalendar($date, $timeslot, $calendar, null, $event);
        $this->view->assign('event', $event);
        $this->view->assign('reservation', $reservation);

        if ($this->calendar->getAcl() && $this->calendar->getAcl()->hasPermission('team')) {
            $this->view->assign('categories', $this->categoryRepository->findAll());
        } else {
            $this->view->assign('categories', $this->categoryRepository->findBy(['public' => 1]));
        }
        $this->view->assign('calendarGroups', $this->calendarGroupRepository->findAll());
        $this->view->assign('bookingTypes', $this->bookingTypeRepository->findAll());
        $this->view->assign('statusses', $this->statusRepository->findAll());
        $this->view->assign('defaultStatus', $this->statusRepository->findOneBy(['isDefault' => 1]));
        $this->view->assign('locations', $this->locationRepository->findAll());
        $this->view->assign('purposes', $this->purposeRepository->findAll());
        $this->assignCalendar(false);

        return new HtmlResponse($this->view->render());
    }

    /**
     * [frontendUserFormAction description]
     * @param  string $date     [description]
     * @param Timeslot $timeslot [description]
     * @param Calendar $calendar [description]
     * @param Reservation $reservation [description]
     */
    public function reservationEditFormAction(
        ?string $date = null,
        ?Timeslot $timeslot = null,
        ?Calendar $calendar = null,
        ?Reservation $reservation = null
    ): ResponseInterface {
        $this->initCalendar($date, $timeslot, $calendar, $reservation);
        $this->view->assign('reservation', $reservation);
        if ($this->calendar->getAcl() && $this->calendar->getAcl()->hasPermission('team')) {
            $this->view->assign('categories', $this->categoryRepository->findAll());
        } else {
            $this->view->assign('categories', $this->categoryRepository->findBy(['public' => 1]));
        }
        $this->view->assign('calendarGroups', $this->calendarGroupRepository->findAll());
        $this->view->assign('statusses', $this->statusRepository->findAll());
        $this->view->assign('defaultStatus', $this->statusRepository->findOneBy(['isDefault' => 1]));
        $this->view->assign('bookingTypes', $this->bookingTypeRepository->findAll());
        $this->view->assign('locations', $this->locationRepository->findAll());
        $this->view->assign('purposes', $this->purposeRepository->findAll());
        $this->assignCalendar(false);

        return new HtmlResponse($this->view->render());
    }

    /**
     * event show
     * @param Event $event event
     */
    public function eventShowAction(?Event $event = null): ResponseInterface
    {
        if ($event === null) {
            if (!$this->request->hasArgument('date')) {
                die('missing date');
            }

            $dateString = $this->request->getArgument('date');
            $date = new DateTime($dateString ?: null);
            $date->setTime(12, 0, 0);
            $calendarUid = $this->request->getArgument('calendar');
            $calendar = $this->calendarRepository->findByUid($calendarUid);

            $timeslotUid = $this->request->getArgument('timeslot');
            $timeslot = $this->timeslotRepository->findByUid($timeslotUid);
            $event = GeneralUtility::makeInstance(Event::class);
            $event->setStartDate($date);
            $event->setCalendar($calendar);
            $event->setTimeslot($timeslot);
            $event = $this->eventRepository->resolveExistentEvent($event);
        }
        $acl = $event->getCalendar()
->getAcl();

        $hasReservationForUser = $event->hasReservationForUser();

        if ($hasReservationForUser || ($acl && ($acl->getIsAdmin() || $acl->hasPermission(
            'team'
        ) || $acl->hasPermission(
            'read'
        )))) {
            $this->initCalendar(null, null, $event->getCalendar(), null, $event);
            $redirect = $this->request->hasArgument('redirect') ? $this->request->getArgument('redirect') : 'callendar';
            $this->view->assign('redirect', $redirect);

            $this->assignCalendar(false);
        }

        return new HtmlResponse($this->view->render());
    }

    /**
     * [frontendUserFormAction description]
     * @param Reservation $reservation [description]
     */
    public function reservationCreateAction(
        ?Reservation $reservation = null
    ): HtmlResponse {
        $this->frontendUser = $this->userService->getUser();

        $noError = true;
        $calendarUid = $this->request->getArgument('calendar');
        $calendar = $this->calendarRepository->findByUid($calendarUid);
        $acl = $calendar->getAcl();

        if ($this->settings['agbFile'] && !($acl && $acl->getIsAdmin())) {
            $agbAccepted = $this->request->hasArgument('agb') ? $this->request->getArgument('agb') : 0;

            if (!$agbAccepted) {
                $this->error = true;
                $this->toastType = 'error';
                $this->toastTitle = 'Es ist ein Fehler aufgetreten';
                $this->toastMessage = 'Daten aktualisiert';

                $noError = false;
            }
        }

        $repeatEvent = false;
        $repetition = '';
        $date = null;
        $timeslot = null;

        // Create reservation from startDate, calendar and timeslot
        if ($reservation === null) {
            $reservation = GeneralUtility::makeInstance(Reservation::class);

            $dateString = $this->request->getArgument('date');
            $date = new DateTime($dateString ?: null);
            $date->setTime(12, 0, 0);

            $timeslotUid = $this->request->getArgument('timeslot');
            $timeslot = $this->timeslotRepository->findByUid($timeslotUid);
            //$this->initCalendar($date, $timeslot, $calendar, $reservation, $event);

            $event = GeneralUtility::makeInstance(Event::class);
            $event->setStartDate($date);
            $event->setCalendar($calendar);
            $event->setTimeslot($timeslot);
            $event = $this->eventRepository->resolveExistentEvent($event);
            $reservation->setEvent($event);
        //$this->event = $this->eventRepository->findOneByDateAndTimeslotAndCalendar($this->date, $this->timeslot->getUid(), $calendar->getUid());
        } else {
            $event = $reservation->getEvent();
            //var_dump($event->getFiles()->toArray());die();

            $calendar = $event->getCalendar();
            $isNew = $event->_isNew();
            $modifyString = '+1 week';
            $modifyInIntervalString = '';

            if ($isNew && $event->getEventGroup()) {
                if ($event->getEventGroup()->getRepetition() && $event->getEventGroup()->getRepetition() != 'None') {
                    $repeatEvent = true;
                    $repetition = $event->getEventGroup()
->getRepetition();
                    if ($repetition == 'Weekly') {
                        $modifyString = '+1 week';
                        $modifyInIntervalString = '';
                    } elseif ($repetition == 'Monthly') {
                        $modifyString = '+1 month';
                        $modifyInIntervalString = '';
                    } elseif ($repetition == 'FirstInMonth') {
                        $modifyString = '+1 month';
                        $modifyWeekday = strtolower((string) $event->getStartDateTime()->format('l')); // Get the current weekday name (e.g., 'monday', 'tuesday')
                        $modifyInIntervalString = 'first ' . $modifyWeekday . ' of this month';
                    } elseif ($repetition == 'LastInMonth') {
                        $modifyString = '+1 month';
                        $modifyWeekday = strtolower((string) $event->getStartDateTime()->format('l')); // Get the current weekday name (e.g., 'monday', 'tuesday')
                        $modifyInIntervalString = 'last ' . $modifyWeekday . ' of this month';
                    } elseif ($repetition == 'Yearly') {
                        $modifyString = '+1 year';
                        $modifyInIntervalString = '';
                    } elseif ($repetition == 'TwoWeeks') {
                        $modifyString = '+2 weeks';
                        $modifyInIntervalString = '';
                    }
                }
            }

            $calendarGroup = null;
            if ($event->getCalendarGroup() && $event->getCalendarGroup()->getCalendars()->count() > 0) {
                $calendarGroup = $event->getCalendarGroup();
                $calendarGroup->addCalendar($calendar);
                $event->setCalendarGroup($calendarGroup);
            } else {
                $event->setCalendarGroup(null);
            }

            if ($repeatEvent && $calendarGroup) {
                $calendarGroup = null;
                $event->setCalendarGroup(null);
            }

            if ($calendar->getIsDateTimeMode()) {
                if ($repeatEvent && $isNew) {
                    $startDateTime = $event->getStartDateTime();
                    $endDateTime = $event->getEndDateTime();

                    if ($event->getEventGroup()->getRepeatTill()) {
                        $lastStartDateTime = clone $event->getEventGroup()
->getRepeatTill();
                    } else {
                        $lastStartDateTime = clone $startDateTime;
                        $lastStartDateTime->modify('+1 year');
                    }

                    $lastEndDateTime = clone $endDateTime;
                    $originalEvent = clone $event;
                    for ($d = clone $startDateTime; $d <= $lastStartDateTime; $d->modify($modifyString)) {
                        if ($modifyInIntervalString) {
                            $d->modify($modifyInIntervalString);
                        }
                        $ev = clone $event;
                        $ev->setMainEvent(true);
                        $ev->setStartDate(clone $d);
                        $ev->setStartTime($d->format('H:i:s'));
                        $ev->setEndDate(clone $lastEndDateTime);
                        $ev->setEndTime($lastEndDateTime->format('H:i:s'));

                        $ev->setOwner($originalEvent->getOwner());
                        $ev->setBookingType($originalEvent->getBookingType());
                        $ev->setStatus($originalEvent->getStatus());
                        $ev->setLocation($originalEvent->getLocation());
                        $ev->setCategory($originalEvent->getCategory());
                        /** @var ObjectStorage<FileReference> */
                        $fileStorage = GeneralUtility::makeInstance(
                            ObjectStorage::class
                        );
                        foreach ($originalEvent->getFiles() as $fileReference) {
                            $file = clone $fileReference;
                            //$file->setUidForeign(null);
                            $fileStorage->attach($file);
                        }
                        $ev->setFiles($fileStorage);
                        /*foreach($event->getReservationTypes() as $reservationType) {
                            $ev->addReservationType($reservationType);
                        }*/

                        if ($calendarGroup && $calendarGroup->getCalendars()) {
                            $cals = $calendarGroup->getCalendars()
->toArray();

                            foreach ($cals as $cal) {
                                $evt = clone $ev;

                                $evt->setOwner($originalEvent->getOwner());
                                $evt->setBookingType($originalEvent->getBookingType());
                                $evt->setStatus($originalEvent->getStatus());
                                $evt->setLocation($originalEvent->getLocation());
                                $evt->setCategory($originalEvent->getCategory());
                                
                                /** @var ObjectStorage<FileReference> */
                                $fileStorage = GeneralUtility::makeInstance(
                                    ObjectStorage::class
                                );
                                foreach ($originalEvent->getFiles() as $fileReference) {
                                    $file = clone $fileReference;
                                    //$file->setUidForeign(null);
                                    $fileStorage->attach($file);
                                }
                                $evt->setFiles($fileStorage);
                                /*foreach($event->getReservationTypes() as $reservationType) {
                                                    $evt->addReservationType($reservationType);
                                                }*/

                                if ($cal->getUid() == $calendar->getUid()) {
                                    $evt->setMainEvent(true);
                                } else {
                                    $evt->setMainEvent(false);
                                }
                                $evt->setCalendar($cal);
                                $noError = $this->eventRepository->secureAdd($evt);
                            }
                        } else {
                            $noError = $this->eventRepository->secureAdd($ev);
                        }
                        $lastEndDateTime->modify($modifyString);
                        if ($modifyInIntervalString) {
                            $lastEndDateTime->modify($modifyInIntervalString);
                        }
                    }
                } else {
                    if ($calendarGroup && $calendarGroup->getCalendars()) {
                        $cals = $calendarGroup->getCalendars()
->toArray();
                        foreach ($cals as $cal) {
                            $evt = clone $event;
                            if ($cal->getUid() == $calendar->getUid()) {
                                $evt->setMainEvent(true);
                            } else {
                                $evt->setMainEvent(false);
                            }
                            $evt->setCalendar($cal);
                            $noError = $this->eventRepository->secureAdd($evt);
                        }
                    //DebuggerUtility::var_dump($noError);
                    } else {
                        $event->setMainEvent(true);
                        if ($reservation->isEmpty() && $isNew) {
                            $noError = $this->eventRepository->secureAdd($event);
                        } elseif (!$isNew) {
                            $defaultStatus = $this->statusRepository->findOneBy(['isDefault' => 1]);
                            if ($defaultStatus) {
                                $event->setStatus($defaultStatus);
                            }
                            $this->eventRepository->secureUpdate($event);
                        }
                        //$reservation->setEvent($event);
                    }
                }
                if ($noError === false) {
                    // error
                    //$this->toastType = 'error';
                    //$this->toastTitle = 'Daten nicht verfügbar';
                    //$this->toastMessage = 'Die gewünschten Zeiten können nicht reserviert werden';
                }
            } else {
                $dateString = $this->request->getArgument('date');
                $date = new DateTime($dateString ?: null);
                $date->setTime(12, 0, 0);
                $event->setStartDate($date);
                $event = $this->eventRepository->resolveExistentEvent($event);
                $timeslot = $event->getTimeslot();
                /*
            // timeslot
            if($event->getTimeslot() ===null) {
            $event->setTimeslot($this->timeslot);
            }
             */
            }
        }

        $this->date = $date;
        $this->event = $event;
        //$this->initCalendar($dateString, $timeslot, $calendar, $reservation, $event);
        $this->calendar = $calendar;
        $this->timeslot = $timeslot;

        //$event->setStartDate($this->date);
        //$event->setCalendar($calendar);

        if ($noError) {
            $toastMessage = 'Daten aktuallisiert';
            // $calendar->getIsDateTimeMode() ist fuer Spital FMI (Alternativ: $reservation->getFrontendUser() || $this->frontendUser)
            if (!$repeatEvent && !($reservation->isEmpty() && $calendar->getIsDateTimeMode())) {
                if ($reservation->getName()) {
                    $toastMessage .= ' (Gast)';
                }

                // testen ob user isAdmin
                if ($reservation->getFrontendUser()) {
                    $toastMessage .= ' (Benutzer)';
                } else {
                    $reservation->setFrontendUser($this->frontendUser);
                }

                $reservation->setEvent($event);

                if ($reservation->_isNew()) {
                    $context = GeneralUtility::makeInstance(Context::class);
                    $languageUid = $context->getPropertyFromAspect('language', 'id');
                    $reservation->setLanguage($languageUid);

                    if ($this->request->hasArgument('multi')) {
                        $multi = (int) $this->request->getArgument('multi');

                        for ($i = 0; $i < $multi; $i++) {
                            $noError = $this->reservationRepository->secureAdd(clone $reservation);
                        }
                        $toastMessage .= ' (Anzahl: ' . $multi . ')';
                    } else {
                        $noError = $this->reservationRepository->secureAdd($reservation);
                    }

                    // Mails
                    $acl = $calendar->getAcl();

                    if (!$acl->hasPermission('team')) {
                        $this->mailService->sendMailAfterBookingCoordinationpersonAndTeam(
                            $calendar,
                            $event,
                            $reservation
                        );
                        /*
                        if ($calendar->hasMailToSend('after-booking-coordinationperson') || $calendar->hasMailToSend('after-booking-team')) {
                            $mailTo = [];
                            if ($calendar->hasMailToSend('after-booking-coordinationperson')) {
                                $mailTo = array_merge($mailTo, array_filter(GeneralUtility::trimExplode(',', $this->settings['coordinationPersonMail'])));
                            }
                            if ($calendar->hasMailToSend('after-booking-team')) {
                                $teammembers = $this->feUserRepository->findTeammembers($this->settings['usergroupForTeammembers'] ? $this->settings['usergroupForTeammembers'] : 0);

                                foreach ($teammembers as $teammember) {
                                    $email = $teammember->getEmail();
                                    if (GeneralUtility::validEmail($email) && !in_array($email, $mailTo)) {
                                        $mailTo[] = $email;
                                    }
                                }
                            }

                            $email = GeneralUtility::makeInstance(FluidEmail::class)
                                ->subject($this->settings['adminNewBookingSubject'] ?? 'Neue Buchung')
                                ->from($this->settings['coordinationPersonMailFrom'])
                                ->to(...$mailTo)
                                ->setTemplate('IgReservations/Event/Create/Admin')
                                ->format('html')
                                ->assign('event', $event)
                                ->assign('reservation', $reservation)
                                ->assign('settings', $this->settings);
                            if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface) {
                                $email->setRequest($GLOBALS['TYPO3_REQUEST']);
                            }
                            GeneralUtility::makeInstance(Mailer::class)->send($email);
                        }
                        */
                    }

                    $this->mailService->sendMailAfterBookingUser($calendar, $event, $reservation);
                /*
                if ($calendar->hasMailToSend('after-booking-user')) {
                    if (GeneralUtility::validEmail($reservation->getEmail())) {
                        $email = GeneralUtility::makeInstance(FluidEmail::class)
                            ->subject(LocalizationUtility::translate('mail.subject.after_booking_user', 'IgReservations'))
                            ->from($this->settings['coordinationPersonMailFrom'])
                            ->to(...[$reservation->getEmail()])
                            ->setTemplate('IgReservations/Event/Create/User')
                            ->format('html')
                            ->assign('event', $event)
                            ->assign('reservation', $reservation)
                            ->assign('settings', $this->settings);
                        if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface) {
                            $email->setRequest($GLOBALS['TYPO3_REQUEST']);
                        }
                        GeneralUtility::makeInstance(Mailer::class)->send($email);
                    }
                }
                */
                } else {
                    $this->reservationRepository->secureUpdate($reservation);
                }
            } elseif (!$event->_isNew()) {
                $this->eventRepository->secureUpdate($event);
            }
            $event->reset();
            $this->toastType = 'success';
            $this->toastTitle = 'Daten wurden gespeichert';
            $this->toastMessage = $toastMessage;
            $this->event = $event;
        }
        $this->assignCalendar(!$noError);
        //echo($this->view->render());var_dump($this->error);exit(0);
        return new HtmlResponse($this->view->render());
    }

    /**
     * [frontendUserFormAction description]
     * @param  string $date     [description]
     * @param Timeslot $timeslot [description]
     * @param Calendar $calendar [description]
     * @param Reservation $reservation [description]
     * @param Event $event [description]
     */
    public function reservationRemoveAction(
        ?string $date = null,
        ?Timeslot $timeslot = null,
        ?Calendar $calendar = null,
        ?Reservation $reservation = null,
        ?Event $event = null
    ): ResponseInterface {
        $noError = null;
        $this->initCalendar($date, $timeslot, $calendar, $reservation);

        //$event = $reservation->getEvent();

        if ($reservation) {
            $noError = $this->reservationRepository->secureRemove($reservation);
        }
        $this->event->reset();

        $events = [];

        if ($this->event->getReservations()->count() == 0) {
            if (isset($_COOKIE['eventClipboard']) && $_COOKIE['eventClipboard'] != $this->event->getUid()) {
                $eventClipboard = $this->eventRepository->findByUid($_COOKIE['eventClipboard']);
                $this->view->assign('eventClipboard', $eventClipboard);
            } else {
                setcookie('eventClipboard', '', [
                    'expires' => time() - 3600,
                ]);
            }
            $this->event->setStatus(null);
            $noError = $this->eventRepository->secureRemove($this->event);
            $newEvent = GeneralUtility::makeInstance(Event::class);
            $newEvent->setCalendar($calendar);
            $newEvent->setTimeslot($timeslot);
            $theDate = new DateTime($date);
            $theDate->setTime(12, 0, 0);
            $newEvent->setStartDate($theDate);
            $this->event = $newEvent;
        }
        $events[] = $this->event;

        $this->view->assign('events', $events);

        $this->toastType = 'info';
        $this->toastTitle = 'Daten wurden gelöscht';
        $this->toastMessage = 'Daten aktuallisiert';

        $this->assignCalendar(!$noError);
        return new HtmlResponse($this->view->render());
    }

    /**
     * [assignTeammemberAction description]
     * @param  string $date     [description]
     * @param Timeslot $timeslot [description]
     * @param Calendar $calendar [description]
     * @param Event $event [description]
     */
    public function teammemberAssignmentFormAction(
        ?string $date = null,
        ?Timeslot $timeslot = null,
        ?Calendar $calendar = null,
        ?Event $event = null
    ): ResponseInterface {
        $this->initCalendar($date, $timeslot, $calendar, null, $event);

        $feUser = $this->userService->getUser();
        $users = $this->feUserRepository->findTeammembers($this->settings['usergroupForTeammembers'] ?: 0);

        $this->view->assign('users', $users);
        $this->view->assign('feUser', $feUser);

        $this->assignCalendar(false);
        return new HtmlResponse($this->view->render());
    }

    /**
     * [assignTeammemberAction description]
     * @param  string $date     [description]
     * @param Timeslot $timeslot [description]
     * @param Calendar $calendar [description]
     * @param Event $event [description]
     */
    public function assignTeammemberAction(
        ?string $date = null,
        ?Timeslot $timeslot = null,
        ?Calendar $calendar = null,
        ?Event $event = null
    ): ResponseInterface {
        $reservation = null;
        $this->initCalendar($date, $timeslot, $calendar, null, $event);

        if ($event->getOwner() && $this->settings['notAvailableStatus']) {
            $notAvailableStatus = $this->statusRepository->findByUid($this->settings['notAvailableStatus']);
            $event->setStatus($notAvailableStatus);
        } elseif (!$event->getOwner()) {
            $defaultStatus = $this->statusRepository->findOneBy(['isDefault' => 1]);

            if ($defaultStatus) {
                $event->setStatus($defaultStatus);
            }
        }

        $this->eventRepository->secureUpdate($event);

        $acl = $calendar->getAcl();
        $feUser = $this->userService->getUser();
        $this->view->assign('user', $feUser);


        $this->mailService->sendMailAfterConfirmationCoordinationperson($calendar, $event, $reservation);


        //$debugMail = $this->settings['debugMail'] ? :  false;
        /*
        if($calendar->hasMailToSend('after-confirmation-coordinationperson') && $event->getOwner()) {
            if(GeneralUtility::validEmail($this->settings['coordinationPersonMailTo'])) {
                $subject = LocalizationUtility::translate('mail.subject.after_confirmation_coordinationperson', 'IgReservations');
                $mailTo = $this->settings['coordinationPersonMailTo'];
                if ($debugMail) {
                    $subject .= ' (DEBUG: ' . $mailTo . ')';
                    $mailTo = $debugMail;
                }
                $email = GeneralUtility::makeInstance(FluidEmail::class)
                    ->subject($subject)
                    ->from($this->settings['coordinationPersonMailFrom'])
                    ->to($mailTo)
                    ->setTemplate('IgReservations/Event/Update/CoordinationPerson')
                    ->format('html')
                    ->assign('event', $event)
                    ->assign('status', $event->getStatus());
                if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface) {
                    $request = $GLOBALS['TYPO3_REQUEST'];
                    $request->setLocale($reservation->getLanguageConfig()->getLocale());
                    $email->setRequest($request);
                }
                GeneralUtility::makeInstance(Mailer::class)->send($email);
            }
        }
        */
        $this->mailService->sendMailAfterConfirmationOwner($calendar, $event, $reservation);

        /*
        if($calendar->hasMailToSend('after-confirmation-owner') && $event->getOwner() ) {
            if(GeneralUtility::validEmail($event->getOwner()->getEmail())) {
                $subject = LocalizationUtility::translate('mail.subject.after_confirmation_owner', 'IgReservations');
                $mailTo = $event->getOwner()->getEmail();
                if ($debugMail) {
                    $subject .= ' (DEBUG: ' . $mailTo . ')';
                    $mailTo = $debugMail;
                }
                $email = GeneralUtility::makeInstance(FluidEmail::class)
                    ->subject($subject)
                    ->from($this->settings['coordinationPersonMailFrom'])
                    ->to($mailTo)
                    ->setTemplate('IgReservations/Event/Update/Owner')
                    ->format('html')
                    ->assign('event', $event)
                    ->assign('status', $event->getStatus());
                if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface) {
                    $request = $GLOBALS['TYPO3_REQUEST'];
                    $request->setLocale($reservation->getLanguageConfig()->getLocale());
                    $email->setRequest($request);
                }
                GeneralUtility::makeInstance(Mailer::class)->send($email);
            }
        }
        */
        $this->mailService->sendMailAfterConfirmationTeam($calendar, $event, $reservation);
        /*
        if($calendar->hasMailToSend('after-confirmation-team') && $event->getTeammembers()) {

            $subject = LocalizationUtility::translate('mail.subject.after_confirmation_team', 'IgReservations');
            $mailsTo = [];
            foreach($event->getTeammembers() as $teammember) {
                if(GeneralUtility::validEmail($teammember->getEmail())) {
                    $mailsTo[] = $teammember->getEmail();
                }
            }
            if ($debugMail) {
                $subject .= ' (DEBUG: ' . implode(',', $mailsTo) . ')';
                $mailsTo = [$debugMail];
            }
            $email = GeneralUtility::makeInstance(FluidEmail::class)
                ->subject($subject)
                ->from($this->settings['coordinationPersonMailFrom'])
                ->to(...$mailsTo)
                ->setTemplate('IgReservations/Event/Update/Team')
                ->format('html')
                ->assign('event', $event)
                ->assign('status', $event->getStatus());
            if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface) {
                $request = $GLOBALS['TYPO3_REQUEST'];
                $request->setLocale($reservation->getLanguageConfig()->getLocale());
                $email->setRequest($request);
            }
            GeneralUtility::makeInstance(Mailer::class)->send($email);
        }
        */
        if ($this->mailService->sendMailAfterConfirmationUser($calendar, $event, $reservation)) {
            $event->setConfirmationSent(true);
            $this->eventRepository->secureUpdate($event);
        }
        /*
        if ($calendar->hasMailToSend('after-confirmation-user') && $event->getOwner()) {
            if (!$event->getConfirmationSent() && $event->getReservations()) {
                foreach ($event->getReservations() as $reservation) {
                    if (GeneralUtility::validEmail($reservation->getEmail())) {
                        $subject = LocalizationUtility::translate('mail.subject.after_confirmation_user', 'IgReservations');
                        $mailTo = $reservation->getEmail();
                        if ($debugMail) {
                            $subject .= ' (DEBUG: ' . $mailTo . ')';
                            $mailTo = $debugMail;
                        }

                        if ($reservation->getLanguage() > 0) {
                            setlocale(LC_ALL, $reservation->getLanguageConfig()->getLocale());
                        }

                        $email = GeneralUtility::makeInstance(FluidEmail::class)
                            ->subject($subject)
                            ->from($this->settings['coordinationPersonMailFrom'])
                            ->to($mailTo)
                            ->setTemplate('IgReservations/Event/Update/User')
                            ->format('html')
                            ->assign('event', $event)
                            ->assign('reservation', $reservation)
                            ->assign('status', $event->getStatus());
                        if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface) {
                            $request = $GLOBALS['TYPO3_REQUEST'];
                            $request->setLocale($reservation->getLanguageConfig()->getLocale());
                            $email->setRequest($request);
                        }
                        GeneralUtility::makeInstance(Mailer::class)->send($email);
                    }
                }
                $event->setConfirmationSent(true);
                $this->eventRepository->secureUpdate($event);
            }
        }
        */
        $this->toastType = 'success';
        $this->toastTitle = 'Daten wurden gespeichert';
        $this->toastMessage = 'Daten aktuallisiert';
        $this->event = $event;

        $this->assignCalendar(false);
        return new HtmlResponse($this->view->render());
    }

    /**
     * reservationCreateFormStartEndAction for fullCalendar
     */
    public function reservationCreateFormStartEndAction(
        string $eventEnd,
        string $eventStart,
        ?Calendar $calendar = null,
        ?Event $event = null
    ): HtmlResponse {


        $acl = $calendar->getAcl();
        /*
        if (!$acl || (!$acl->getIsAdmin() && $acl->hasPermission('read'))) {
            return new HtmlResponse('no access');
        }
        */

        
        $eventStartDate = new DateTime($eventStart);
        $eventEndDate = new DateTime($eventEnd);
        $lastStartDateTime = clone $eventStartDate;
        $lastStartDateTime->modify('+1 year');

        $localeTimezone = new DateTimeZone(date_default_timezone_get());
        $eventStartDate->setTimezone($localeTimezone);
        $eventEndDate->setTimezone($localeTimezone);

        $startDate = $eventStartDate->format('Y-m-d');
        $startTime =  $eventStartDate->format('H:i:s');
        $endDate = $eventEndDate->format('Y-m-d');
        $endTime = $eventEndDate->format('H:i:s');
        /*
        echo(date_default_timezone_get() .'<br />');
        var_dump($localeTimezone);
        echo($eventStart .' - ' . $eventEnd . '<br />');
        var_dump($eventStartDate);
        echo($startDate . '  ' . $startTime);
        exit(0);
        */
        //var_dump($eventStart, $startTime, $eventStartDate, $eventStartDate->format('Y-m-d'), $eventStartDate->format('H:i:s'));exit(0);

        /*$dates = [];
        for($d = clone $eventStartDate; $d <= $lastStartDateTime; $d->modify('+1 week')) {
        $dates[] = $d->format('Y-m-d');
        }

        $existingEventCalendarIds = $this->eventRepository->findCalendarIdsInDatesAndStartAndEndTime($dates, $startTime, $endTime);*/

        $canRepeat = true;
        /*if(!empty($existingEventCalendarIds)) {
        $canRepeat = false;
        }*/

        $possibleEndTimes = $calendar->getPossibleStartAndEndTimes($startDate, $startTime, $endDate, $endTime);
        $timeslotDateTimes = $calendar->getTimelotDateTimes($startDate, $endDate);

        /*
        $maxTime=    select min(ev_staert_time) from events where ev_start_date=$startDate AND ev_time>$startTime  -block: '22:00';
        $minTime = select max(ev_emd_time) from events where ev_end_date=$startDate AND ev_time<=$startTime +block: '08:00';
        for($time=$minTime;$time+$interval;$time<= $maxTime);
         */
        /*$interval = new \DateInterval('PT1H');
        $daterangeStart = new \DatePeriod($timeslotStartTime, $interval, $timeslotEndTime);
        $daterangeEnd = new \DatePeriod($timeslotStartTime, $interval, $timeslotEndTime);

        $daterangeStart = array_reverse(iterator_to_array($daterangeStart));

        foreach($daterangeStart as $possibleTime) {
        $alreadyExistingEvent = $this->eventRepository->findByCalendarDateAndTime($calendar, $possibleTime);

        if(count($alreadyExistingEvent) > 0) {
        break;
        }
        $possibleStartTimes[$possibleTime->format('H:i:s')] = $possibleTime->format('H:i');
        }
        $possibleStartTimes = array_reverse($possibleStartTimes);
        foreach($daterangeEnd as $possibleTime) {
        $alreadyExistingEvent = $this->eventRepository->findByCalendarDateAndTime($calendar, $possibleTime);

        if(count($alreadyExistingEvent) > 0) {
        break;
        }
        $possibleEndTimes[$possibleTime->format('H:i:s')] = $possibleTime->format('H:i');
        }*/

        //$eventStartDate->modify('+2 hour');
        //$eventEndDate->modify('+2 hour'); // @todo UTC Timezone
        //echo('Selected Time: ' . $eventStartDate->format('H:i.s') .' - ' . $eventEndDate->format('H:i.s') . '<br />');
        /*
        for($d = clone $eventStartDate;$d<$eventEndDate;$d->modify('+1hour')) {
        echo($d->format('d.m.Y H:i') . '<br />');
        }
         */
        //$this->view->assign('startDateTime', $eventStartDate);
        //<f:form.hidden name="startDateTime" value="{startDateTime->f:format.date(format: '%Y-%m-%d %H:%M:%S')}" />

        $this->view->assign('startDate', $startDate);
        $this->view->assign('startTime', $startTime);
        $this->view->assign('endDate', $endDate);
        $this->view->assign('endTime', $endTime);
        $this->view->assign('canRepeat', $canRepeat);
        $this->view->assign('event', $event);

        $date = $eventStartDate->format('Y-m-d');

        if (!$event) {
            $event = null;
        }
        $timeslot = null;
        $this->initCalendar($date, $timeslot, $calendar, null, $event);
        // $this->view->assign('reservation', $reservation);
        if ($acl && $acl->hasPermission('team')) {
            $this->view->assign('categories', $this->categoryRepository->findAll());
        } else {
            $this->view->assign('categories', $this->categoryRepository->findBy(['public' => 1]));
        }
        $this->view->assign('statusses', $this->statusRepository->findAll());
        $this->view->assign('defaultStatus', $this->statusRepository->findOneBy(['isDefault' => 1]));
        $this->assignCalendar(false);
        $this->view->assign('eventStartDate', $eventStartDate);
        $this->view->assign('eventEndDate', $eventEndDate);
        $this->view->assign('possibleEndTimes', $possibleEndTimes);
        $this->view->assign('timeslotDateTimes', $timeslotDateTimes);
        $this->view->assign('calendars', $this->calendarRepository->findByNotInUids([$calendar->getUid()]));
        $this->view->assign('purposes', $this->purposeRepository->findAll());

        $this->view->assign('bookingTypes', $this->bookingTypeRepository->findAll());
        $this->view->assign('reservationTypes', $this->reservationTypeRepository->findAll());
        $this->view->assign('locations', $this->locationRepository->findAll());
        $this->view->assign(
            'users',
            $this->feUserRepository->findTeammembers($this->settings['usergroupForTeammembers'] ?: 0)
        );
        return new HtmlResponse($this->view->render());
    }

    /**
     * eventRemoveAction delete a event
     */
    public function eventRemoveAction(Event $event): ResponseInterface
    {
        if (isset($_COOKIE['eventClipboard']) && $_COOKIE['eventClipboard'] != $event->getUid()) {
            $eventClipboard = $this->eventRepository->findByUid($_COOKIE['eventClipboard']);
            $this->view->assign('eventClipboard', $eventClipboard);
        } else {
            setcookie('eventClipboard', '', [
                'expires' => time() - 3600,
            ]);
        }
        $noError = $this->eventRepository->secureRemove($event);
        $event->reset();

        $this->toastType = 'info';
        $this->toastTitle = 'Daten wurden gelöscht';
        $this->toastMessage = 'Daten aktuallisiert';

        $this->view->assign('event', $event);
        return new HtmlResponse($this->view->render());
    }

    public function getEventsAction(
        Calendar $calendar,
        array $search = []
    ): JsonResponse {
        $events = [];
        $acl = $calendar->getAcl();

        if ($acl && $acl->getIsAdmin()) {
            $events = $calendar->getEventsRawWithInfo($search);
        } elseif ($acl && ($acl->hasPermission('team') && $acl->hasPermission('read'))) {
            $events = $calendar->getMyEventsRawWithInfo($search);
        } else {
            $events = $calendar->getEventsRawPublic($search);
        }

        return new JsonResponse($events);
    }

    public function updateEventAction(
        Calendar $calendar,
        Event $event,
        string $eventStart,
        string $eventEnd
    ): JsonResponse {
        $acl = $calendar->getAcl();

        $data = [
            'status' => 'failure',
            'error' => 1,
            'debug' => [
                'calendarUid' => $calendar->getUid(),
                'eventUid' => $event->getUid(),
                'eventStart' => $eventStart,
                'eventEnd' => $eventEnd,
                'hasAcl' => $acl !== null,
                'aclIsAdmin' => $acl ? $acl->getIsAdmin() : null,
                'aclName' => $acl ? $acl->getName() : null,
            ],
        ];

        if ($acl && $acl->getIsAdmin()) {
            $eventStartDate = new DateTime($eventStart);
            $eventEndDate = new DateTime($eventEnd);

            $localeTimezone = new DateTimeZone(date_default_timezone_get());
            $eventStartDate->setTimezone($localeTimezone);
            $eventEndDate->setTimezone($localeTimezone);

            $localeTimezone = new DateTimeZone(date_default_timezone_get());
            $startDate = $eventStartDate->format('Y-m-d');
            $startTime =  $eventStartDate->format('H:i:s');
            $endDate = $eventEndDate->format('Y-m-d');
            $endTime = $eventEndDate->format('H:i:s');

            //$eventStartDate->setTime(12, 0, 0);
            //$eventEndDate->setTime(12, 0, 0);
            $event->setStartDate($eventStartDate);
            $event->setStartTime($startTime);
            $event->setEndDate($eventEndDate);
            $event->setEndTime($endTime);

            /*
              echo(date_default_timezone_get() .'<br />');
              var_dump($localeTimezone);
              echo($eventStart .' - ' . $eventEnd . '<br />');
              var_dump($eventStartDate);
              echo($startDate . '  ' . $startTime . ' - ' . $endDate . '  ' . $endTime . '<br />');
              echo ($event->getStartDate()->format('Y-m-d'). ' ' . $event->getStartTime() . '<br />');
              echo ($event->getEndDate()->format('Y-m-d'). ' ' . $event->getEndTime() . '<br />');
              exit(0);
            */

            $this->eventRepository->update($event);

            $data = [
                'status' => 'success',
                'error' => 0,
                'debug' => $data['debug'],
            ];
        }
        return new JsonResponse($data);
    }

    protected function initializeAction(): void
    {
        parent::initializeAction();
        if (isset($this->arguments['reservation'])) {
            $pmc = $this->arguments['reservation']->getPropertyMappingConfiguration();
            $pmc->skipUnknownProperties()->allowProperties('event');

            /** @var PropertyMappingConfiguration $eventPmc */
            $eventPmc = $pmc->forProperty('event');
            $eventPmc->allowAllProperties()->skipUnknownProperties();

            /** @var PropertyMappingConfiguration $eventWildcardPmc */
            $eventWildcardPmc = $pmc->forProperty('event.*');
            $eventWildcardPmc->allowAllProperties()->skipUnknownProperties();

            /** @var PropertyMappingConfiguration $eventFilesPmc */
            $eventFilesPmc = $pmc->forProperty('event.files.*');
            $eventFilesPmc->allowAllProperties()->skipUnknownProperties();

            /** @var PropertyMappingConfiguration $eventFilesDeepPmc */
            $eventFilesDeepPmc = $pmc->forProperty('event.files.*.*');
            $eventFilesDeepPmc->allowAllProperties()->skipUnknownProperties();

            /** @var PropertyMappingConfiguration $startDatePmc */
            $startDatePmc = $pmc->forProperty('event.startDate');
            $startDatePmc->setTypeConverter(GeneralUtility::makeInstance(DateTimeConverter::class))
                ->setTypeConverterOption(
                    DateTimeConverter::class,
                    DateTimeConverter::CONFIGURATION_DATE_FORMAT,
                    'Y-m-d'
                );

            /** @var PropertyMappingConfiguration $endDatePmc */
            $endDatePmc = $pmc->forProperty('event.endDate');
            $endDatePmc->setTypeConverter(GeneralUtility::makeInstance(DateTimeConverter::class))
                ->setTypeConverterOption(
                    DateTimeConverter::class,
                    DateTimeConverter::CONFIGURATION_DATE_FORMAT,
                    'Y-m-d'
                );

            /** @var PropertyMappingConfiguration $descriptionPmc */
            $descriptionPmc = $pmc->forProperty('event.description');
            $descriptionPmc->setTypeConverter(GeneralUtility::makeInstance(HtmlConverter::class));
        }
        $this->mailService->setSettings($this->settings);
        $this->mailService->setRequest($this->request);
    }

    /**
     * Calls the specified action method and passes the arguments.
     *
     * If the action returns a string, it is appended to the content in the
     * response object. If the action doesn't return anything and a valid
     * view exists, the view is rendered automatically.
     */
    protected function callActionMethod(RequestInterface $request): ResponseInterface
    {
        $actionResult = parent::callActionMethod($request);

        if ($actionResult instanceof HtmlResponse) {
            return $this->jsonResponse(json_encode([
                'error' => $this->error,
                'toast' => [
                    'type' => $this->toastType,
                    'title' => $this->toastTitle,
                    'message' => $this->toastMessage,
                ],
                'html' => trim($actionResult->getBody()->__toString()),
            ], JSON_THROW_ON_ERROR));
        } elseif ($actionResult instanceof JsonResponse) {
            return $actionResult;
        } elseif ($actionResult instanceof ResponseInterface) {
            return $actionResult;
        }
        throw new \RuntimeException(
            sprintf(
                'Controller action %s did not return an instance of %s.',
                static::class . '::' . $this->actionMethodName,
                ResponseInterface::class
            ),
            1638554283
        );
    }

    /**
     * action error
     *
     * @return string
     * @api
     */
    protected function errorAction(): ResponseInterface
    {
        $response = [];
        $errors = [];
        if ($this->arguments->validate()->hasErrors()) {
            foreach ($this->arguments->validate()->getFlattenedErrors() as $key => $error) {
                $propertyPathArr = explode('.', (string) $key);
                $propertyPath = '';
                foreach ($propertyPathArr as $part) {
                    $propertyPath .= '[' . $part . ']';
                }
                $errors[] = $propertyPath . '(' . $error[0]->__toString() . ')';
            }
        }

        $response['status'] = 'validation';
        $response['errors'] = $errors;
        $json = json_encode($response, JSON_THROW_ON_ERROR);
        return $this->jsonResponse($json);
    }
}
