<?php

namespace Ig\IgReservations\Controller;

use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use DateTime;
use Internetgalerie\IgRender\Utility\PdfUtility;
use Ig\IgReservations\Domain\Repository\BookingTypeRepository;
use Ig\IgReservations\Domain\Repository\CalendarRepository;
use Ig\IgReservations\Domain\Repository\EventRepository;
use Ig\IgReservations\Domain\Repository\FeUserRepository;
use Ig\IgReservations\Domain\Repository\LocationRepository;
use Ig\IgReservations\Domain\Repository\ReservationTypeRepository;
use Ig\IgReservations\Domain\Repository\StatusRepository;
use Ig\IgReservations\Service\UserService;
use Ig\IgReservations\Utility\CalendarViewUtility;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Core\Page\AssetCollector;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\View\JsonView;

/**
 * CalendarController
 */
class CalendarController extends ActionController
{
    protected const fullcalendarMajorVersion = 6;
    protected CalendarRepository $calendarRepository;
    protected EventRepository $eventRepository;
    protected StatusRepository $statusRepository;
    protected FeUserRepository $feUserRepository;
    protected BookingTypeRepository $bookingTypeRepository;
    protected ReservationTypeRepository $reservationTypeRepository;
    protected LocationRepository $locationRepository;
    protected CalendarViewUtility $calendarViewUtility;
    protected UserService $userService;
    protected array $calendars;

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

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

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

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

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

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

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

    public function injectCalendarViewUtility(CalendarViewUtility $calendarViewUtility): void
    {
        $this->calendarViewUtility = $calendarViewUtility;
    }

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

    public function initializeAction(): void
    {
        $assetCollector = GeneralUtility::makeInstance(AssetCollector::class);
        $assetCollector->addStyleSheet('ig-reservations', 'EXT:ig_reservations/Resources/Public/Css/ig_reservations.css');
        $assetCollector->addStyleSheet('ig-timeslot', 'EXT:ig_reservations/Resources/Public/Css/timeslot.css');
        $assetCollector->addStyleSheet('jquery-context-menu', 'EXT:ig_reservations/Resources/Public/Lib/jQuery-contextMenu/dist/jquery.contextMenu.min.css');
        $assetCollector->addJavaScript('jquery-context-menu', 'EXT:ig_reservations/Resources/Public/Lib/jQuery-contextMenu/dist/jquery.contextMenu.min.js');
        $assetCollector->addStyleSheet('select2', 'EXT:ig_reservations/Resources/Public/Lib/select2/select2.css');
        $assetCollector->addJavaScript('select2', 'EXT:ig_reservations/Resources/Public/Lib/select2/select2.min.js');

        /** @var SiteLanguage */
        $siteLanguage = $this->request->getAttribute('language');

        $assetCollector->addJavaScript(
            'select2-i18n-' . $siteLanguage->getLocale()->getLanguageCode(),
            'EXT:ig_reservations/Resources/Public/Lib/select2/i18n/' . $siteLanguage->getLocale()->getLanguageCode() . '.js'
        );

        $assetCollector->addStyleSheet('toastr', 'EXT:ig_reservations/Resources/Public/Lib/toastr/toastr.min.css');
        $assetCollector->addJavaScript('toastr', 'EXT:ig_reservations/Resources/Public/Lib/toastr/toastr.min.js');
        $assetCollector->addJavaScript('ig-confirm-delete', 'EXT:ig_reservations/Resources/Public/JavaScript/ConfirmDelete.js');
        $assetCollector->addJavaScript('ig-calendar', 'EXT:ig_reservations/Resources/Public/JavaScript/calendar.js', ['type' => 'module']);
        if (!empty($this->settings['contextMenuConfigJs'])) {
            $assetCollector->addJavaScript('ig-calendar-context-menu-config', $this->settings['contextMenuConfigJs'], ['type' => 'module']);
        }
    }

    public function initCalendar($search): void
    {
        if (empty($this->settings['calendar'])) {
            die('no calendar is selected');
        }
        $calendarUids = GeneralUtility::trimExplode(',', $this->settings['calendar']);

        $this->calendars = $this->calendarRepository->getInUids($calendarUids);
        if ($this->settings['days']) {
            $viewDays = GeneralUtility::trimExplode(',', $this->settings['days'], true);
            $calendarRows = count($viewDays);
        } else {
            if ($this->settings['unit'] == 'day') {
                $calendarRows = 1;
                $viewDays = null;
            } else {
                $viewDays = [1, 2, 3, 4, 5, 6, 7];
                $calendarRows = count($viewDays);
            }
        }
        $searchDate = '';
        if (isset($search['date'])) {
            $searchDate = $search['date']['date'] ?? $search['date'];
        }
        //var_dump($search['date']);        die('D='.  $searchDate);
        $date = new DateTime($searchDate ?: null);
        $date->setTime(12, 0, 0);
        foreach ($this->calendars as $calendar) {
            $calendar->setView($this->settings['unit'], $viewDays, $date);
        }
    }
    public function initEventsToApprove(): void
    {
        // Approval list
        $eventsToApprove = $this->eventRepository->findUnapproved();
        $this->view->assign('eventsToApprove', $eventsToApprove);
        $this->view->assign('eventsToApproveCount', $eventsToApprove->count());
    }
    /**
     * initList
     */
    public function initList(array $search, ?string $limitPast = null, ?string $limitFuture = null): void
    {
        $unit = $this->settings['unit'];
        if ($this->settings['days']) {
            $viewDays = GeneralUtility::trimExplode(',', $this->settings['days'], true);
            $calendarRows = count($viewDays);
        } else {
            if ($unit == 'day') {
                $calendarRows = 1;
                $viewDays = null;
            } else {
                $viewDays = [1, 2, 3, 4, 5, 6, 7];
                $calendarRows = count($viewDays);
            }
        }
        $searchDate = $search['date']['date'] ?? $search['date'];
        //var_dump($search['date']);        die('D='.  $searchDate);
        $date = new DateTime($searchDate ?: null);
        $date->setTime(12, 0, 0);
        //die($date->format('Y-m-d'));

        $this->calendarViewUtility->init($date, $limitPast, $limitFuture, $unit, $viewDays);
        $calendarNav = $this->calendarViewUtility->getCalendarNav($this->calendars); //, $limitPast, $limitFuture);
        $calendarData = $this->calendarViewUtility->getCalendarData($this->calendars);

        $user = $this->userService->getUser();
        $this->view->assign('user', $user);

        $this->view->assign('calendarNav', json_encode($calendarNav));
        $this->view->assign('calendarData', $calendarData);
        $this->view->assign('search', $search);
        $this->view->assign('date', $date);
        $this->view->assign('calendarRows', $calendarRows);
        $this->view->assign('unit', $unit);
        $this->view->assign('partial', ucfirst((string) $unit));
    }

    public function listAction(): ResponseInterface
    {
        $this->initEventsToApprove();
        $calendars = $this->calendarRepository->findAll();
        $this->view->assign('calendars', $calendars);

        return $this->htmlResponse();
    }

    /**
     * action show
     */
    public function showAction(array $search = []): ResponseInterface
    {
        $this->settings['calendarAjaxPageUid'] = (int)($this->settings['calendarAjaxPageUid'] ?? 0);
        $this->view->assign('settings', $this->settings);
        foreach ($search as $key => $searchArg) {
            if ($searchArg == '') {
                unset($search[$key]);
            }
        }
        $this->initCalendar($search);

        if ($_GET['debugCalendar'] ?? false) {
            echo'<h1>Calendar Debug</h1>';
            foreach ($this->calendars as $calendar) {
                echo'<h2>Calendar: ' . $calendar->getName() . '</h2>';
                echo('<h3>getPermissions</h3><ul>');
                foreach ($calendar->getPermissions() as $name => $value) {
                    echo('<li>' . $name  . '= ' . ($value ? '1' : '0'). '</li>');
                }
                echo('</ul>');
                echo('<h3>getFullcalendarSettings</h3>');
                foreach ($calendar->getFullcalendarSettings() as $name => $value) {
                    echo($name . '=' . ($value ? 'true' : 'false') . '<br />');
                }
            }
            exit(0);
        }


        $assetCollector = GeneralUtility::makeInstance(AssetCollector::class);
        if ($this->calendars[0]->getCalendarType()->getPartial() == 'FullCalendar') {
            /** @var SiteLanguage */
            $siteLanguage = $this->request->getAttribute('language');
            $languageIsoCode = $siteLanguage->getLocale()->getLanguageCode();
            if (self::fullcalendarMajorVersion == 4) {
                // V4.4
                $assetCollector->addJavaScript('moment', 'https://cdn.jsdelivr.net/npm/moment@2.27.0/min/moment.min.js');
                $assetCollector->addJavaScript('fullcalendar-core', 'EXT:ig_reservations/Resources/Public/Lib/fullcalendar/packages/core/main.js');
                $assetCollector->addJavaScript('fullcalendar-moment', 'EXT:ig_reservations/Resources/Public/Lib/fullcalendar/packages/moment/main.js');
                $assetCollector->addJavaScript('fullcalendar-interaction', 'EXT:ig_reservations/Resources/Public/Lib/fullcalendar/packages/interaction/main.js');
                $assetCollector->addJavaScript('fullcalendar-daygrid', 'EXT:ig_reservations/Resources/Public/Lib/fullcalendar/packages/daygrid/main.js');
                $assetCollector->addJavaScript('fullcalendar-timegrid', 'EXT:ig_reservations/Resources/Public/Lib/fullcalendar/packages/timegrid/main.js');
                $assetCollector->addJavaScript('fullcalendar-locale-' . $languageIsoCode, 'EXT:ig_reservations/Resources/Public/Lib/fullcalendar/packages/core/locales/' . $languageIsoCode . '.js');
                $assetCollector->addJavaScript('ig-handle-purposes', 'EXT:ig_reservations/Resources/Public/JavaScript/handlePurposes.js', ['type' => 'module']);
                $assetCollector->addJavaScript('fullcalendar-4', 'EXT:ig_reservations/Resources/Public/JavaScript/fullcalendar-4.js');
            } else {
                $jsFile = 'index.global.min.js';
                //$assetCollector->addJavaScript('moment', 'EXT:ig_reservations/Resources/Public/Lib/moment/moment.min.js', [], ['priority' => true]);
                $assetCollector->addJavaScript(
                    'fullcalendar-main',
                    'EXT:ig_reservations/Resources/Public/Lib/fullcalendar-6.1.10/dist/index.global.min.js',
                    []
                );//,  ['priority' => true]); // im header
                $assetCollector->addJavaScript(
                    'fullcalendar-locale-' . $languageIsoCode,
                    'EXT:ig_reservations/Resources/Public/Lib/fullcalendar-6.1.10/packages/core/locales/' . $languageIsoCode . '.global.min.js',
                    []
                );
                $assetCollector->addJavaScript(
                    'fullcalendar-handle-purpose',
                    'EXT:ig_reservations/Resources/Public/JavaScript/handlePurposes.js',
                    ['type' => 'module']
                );
                $assetCollector->addJavaScript(
                    'fullcalendar-reservation',
                    'EXT:ig_reservations/Resources/Public/JavaScript/fullcalendar-6.js',
                    ['type' => 'module']
                );
                GeneralUtility::makeInstance(PageRenderer::class)->loadJavaScriptModule('@dp/ig_datapool_fe.js');
            }
            $assetCollector->addStyleSheet('ig-fullcalendar', 'EXT:ig_reservations/Resources/Public/Css/fullcalendar.css');
            $assetCollector->addStyleSheet('fullcalendar-core-css', 'EXT:ig_reservations/Resources/Public/Lib/fullcalendar/packages/core/main.css');
            $assetCollector->addStyleSheet('fullcalendar-daygrid-css', 'EXT:ig_reservations/Resources/Public/Lib/fullcalendar/packages/daygrid/main.css');
            $assetCollector->addStyleSheet('fullcalendar-timegrid-css', 'EXT:ig_reservations/Resources/Public/Lib/fullcalendar/packages/timegrid/main.css');
            $this->view->assign('statusses', $this->statusRepository->findAll());
            $this->view->assign('bookingTypes', $this->bookingTypeRepository->findAll());
            $this->view->assign(
                'users',
                $this->feUserRepository->findTeammembers($this->settings['usergroupForTeammembers'] ?: 0)
            );
            $this->view->assign('languageIsoCode', $languageIsoCode);
            $locations = null;
            $reservationTypes = null;
            if (isset($search['bookingType']) && $search['bookingType']) {
                $locations = $this->locationRepository->findByBookingType($search['bookingType']);
                $reservationTypes = $this->reservationTypeRepository->findByBookingType($search['bookingType']);
                $this->view->assign('reservationTypes', $reservationTypes);
                $this->view->assign('bookingType', $search['bookingType']);
                $this->view->assign('locations', $locations);
            } elseif (isset($this->settings['bookingType']) && $this->settings['bookingType']) {
                $locations = $this->locationRepository->findByBookingType($this->settings['bookingType']);
                $reservationTypes = $this->reservationTypeRepository->findByBookingType($this->settings['bookingType']);
                $this->view->assign('reservationTypes', $reservationTypes);

                $this->view->assign('bookingType', $this->settings['bookingType']);
                $this->view->assign('locations', $locations);
            } else {
                $locations = $this->locationRepository->findAll();
                $reservationTypes = $this->reservationTypeRepository->findAll();
                $this->view->assign('reservationTypes', $this->reservationTypeRepository->findAll());
                $this->view->assign('locations', $locations);
            }

            if ((is_countable($locations) ? count($locations) : 0) == 1 && (is_countable($reservationTypes) ? count(
                $reservationTypes
            ) : 0) == 0) {
                $search['location'] = $locations[0]->getUid();
            }

            $calendar = $this->calendars[0];
            $acl = $calendar->getAcl();
            if ((!isset($search['bookingType']) || !$search['bookingType']) && (isset($this->settings['bookingType']) && $this->settings['bookingType'])) {
                $search['bookingType'] = $this->settings['bookingType'];
            }
            $events = [];
            if (($acl && $acl->hasPermission(
                'team'
            ) && !$acl->getIsAdmin()) || $this->settings['calendarShowMode'] != 'onlyWithFilter' || !empty($search)) {
                /*if($acl && $acl->getIsAdmin()) {
                    $events = $calendar->getEventsRawWithInfo($search);
                } else if($acl && $acl->hasPermission('team')) {
                    $events = $calendar->getMyEventsRawWithInfo($search);
                } else {
                    $events = $calendar->getEventsRawPublic($search);
                }*/
            }
            //$this->view->assign('events', json_encode($events));
            $this->view->assign('statusses', $this->statusRepository->findAll());

        //$events = $this->eventRepository->findByCalendar($this->calendars[0]->getUid());
        //$this->view->assign('events', $events);
        } else {
            $this->initList(
                $search,
                $this->settings['showBeginDateTimeModifier'],
                $this->settings['showEndDateTimeModifier']
            );
            $this->view->assign('statusses', $this->statusRepository->findAll());

            /*
        $frontendUsers = $this->frontendUserRepository->findAjaxRaw();
        $this->view->assign('frontendUsers', $frontendUsers);
         */
        }

        $assetCollector->addStyleSheet('jquery-confirm', 'EXT:ig_reservations/Resources/Public/Lib/jquery-confirm/jquery-confirm.min.css');
        $assetCollector->addJavaScript('jquery-confirm', 'EXT:ig_reservations/Resources/Public/Lib/jquery-confirm/jquery-confirm.min.js');

        $this->initEventsToApprove();
        $this->view->assign('calendars', $this->calendars);
        $this->view->assign('search', $search);
        $allCalendars = $this->calendarRepository->findAll();
        $this->view->assign('allCalendars', $allCalendars);

        if($acl) {
            $jsonView = GeneralUtility::makeInstance(JsonView::class);
            $jsonView->setVariablesToRender(['acl']);
            $jsonView->assign('acl', $acl);
            $aclJson = $jsonView->render();
            $this->view->assign('aclJson', $aclJson);
        }

        if (isset($_COOKIE['eventClipboard'])) {
            $eventClipboard = $this->eventRepository->findByUid($_COOKIE['eventClipboard']);
            $this->view->assign('eventClipboard', $eventClipboard);
        }

        return $this->htmlResponse();
    }

    /**
     * overview
     */
    public function overviewAction(array $search = []): ResponseInterface
    {
        $searchDate = $search['date']['date'] ?? ($search['date'] ?? null);
        $startDate = new DateTime($searchDate ?: null);
        $startDate->setTime(12, 0, 0);

        $calendars = $this->calendarRepository->findBy(['hideInList' => 0]);

        foreach ($calendars as $calendar) {
            $calendar->setView('week', [1, 2, 3, 4, 5, 6, 7], $startDate);
        }

        $date = clone $startDate;

        $date->modify('monday this week');

        $dates = [];
        for ($d = (int) $date->format('N'); $d >= 1 && $d <= 7; $d++, $date->modify('+1 day')) {
            $dates[] = clone $date;
        }

        $this->calendarViewUtility->init(
            $startDate,
            $this->settings['showBeginDateTimeModifier'],
            $this->settings['showEndDateTimeModifier'],
            'week'
        );
        $calendarNav = $this->calendarViewUtility->getCalendarNav($calendars); //, $limitPast, $limitFuture);

        $this->view->assign('calendars', $calendars);
        $this->view->assign('dates', $dates);
        $this->view->assign('search', $search);
        $this->view->assign('date', $startDate);
        $this->view->assign('calendarNav', $calendarNav);

        return $this->htmlResponse();
    }

    /**
     * pdfExport
     */
    public function pdfExportAction(array $search = []): ResponseInterface
    {
        $searchDate = $search['date']['date'] ?? $search['date'];
        $startDate = new DateTime($searchDate ?: null);
        $startDate->setTime(12, 0, 0);

        $calendars = $this->calendarRepository->findAll();

        foreach ($calendars as $calendar) {
            $calendar->setView('week', [1, 2, 3, 4, 5, 6, 7], $startDate);
        }

        $date = clone $startDate;

        $date->modify('monday this week');
        $filename = 'Reservations-Export-Overview-' . $date->format('Y-m-d') . '.pdf';

        $dates = [];
        for ($d = (int) $date->format('N'); $d >= 1 && $d <= 7; $d++, $date->modify('+1 day')) {
            $dates[] = clone $date;
        }

        $this->calendarViewUtility->init(
            $startDate,
            $this->settings['showBeginDateTimeModifier'],
            $this->settings['showEndDateTimeModifier'],
            'week'
        );

        $this->view->assign('calendars', $calendars);
        $this->view->assign('dates', $dates);
        $this->view->assign('search', $search);
        $this->view->assign('date', $startDate);

        $html = $this->view->render();

        $pdf = GeneralUtility::makeInstance(PdfUtility::class);
        $pdf->setFilename($filename);
        $pdf->setCssFile('EXT:ig_reservations/Resources/Public/Css/reservations-pdf.css');
        $pdf->addOption('--orientation Landscape');
        $pdf->out($html);
        die();

        return $this->htmlResponse();
    }
}
