<?php

namespace Ig\IgReservations\Command;

use DateTime;
use ICal\ICal;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use TYPO3\CMS\Core\Core\Bootstrap;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Mail\Mailer;
use TYPO3\CMS\Core\Mail\MailMessage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\View\ViewFactoryData;
use TYPO3\CMS\Core\View\ViewFactoryInterface;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;

class ImportCommand extends Command
{
    protected $conn = null;

    public function __construct(private readonly ViewFactoryInterface $viewFactory)
    {
        parent::__construct();
    }

    /**
     * Configure the command by defining the name, options and arguments
     */
    protected function configure()
    {
        $this->setDescription('Import ICS files into calendars');
        $this->setHelp('Import ICS files into calendars');
    }

    /**
     * Executes the command for showing sys_log entries
     */
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $io->title($this->getDescription());
        $io->writeln($this->getHelp());

        Bootstrap::initializeBackendAuthentication();

        $this->conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable(
            'tx_igreservations_domain_model_calendar'
        );
        $this->conn->beginTransaction();
        /** TODO: Outsource mapping **/
        $calendarMapping = [
            'Grosser Saal' => 1,
            'Kirche' => 2,
            'Raum der Stille' => 3,
            'Belpbergzimmer' => 4,
            'Gurtenzimmer' => 5,
            'Längenbergzimmer' => 6,
            'Ulmizzimmer' => 7,
            'Küche' => 8,
            'Foyer' => 9,
            'Clubraum' => 10,
        ];

        $now = time();
        $sql = 'SELECT uid,pid,calendar,path FROM tx_igreservations_domain_model_import
        WHERE deleted = 0 AND hidden = 0 AND (
            (starttime = 0 OR starttime <= ' . $now . ')
            AND
            (endtime = 0 OR endtime >= ' . $now . ')
        ) ORDER BY sorting ASC';

        $stmt = $this->conn->prepare($sql);
        $res = $stmt->executeQuery();
        $imports = $res->fetchAllAssociative();

        $sql = 'DELETE FROM tx_igreservations_domain_model_event WHERE import_id > 0';
        $stmt = $this->conn->prepare($sql);
        $stmt->executeStatement();

        // TODO: See if ical entry is around for an entry that we already have in db
        $insertCount = 0;
        $updateCount = 0;
        $deleteCount = 0;
        foreach ($imports as $import) {
            $importId = $import['uid'];
            $defaultCalendar = $import['calendar'];
            $pid = $import['pid'];
            $content = GeneralUtility::getUrl($import['path']);
            $ical = new ICal($content);
            $events = $ical->events();
            $eventsToNotDelete = [];

            $sql = 'SELECT uid, external_id, start_date, start_time, end_date, end_time
            FROM tx_igreservations_domain_model_event WHERE import_id = ' . $importId;

            $stmt = $this->conn->prepare($sql);
            $res = $stmt->executeQuery();
            $importedEventsRes = $res->fetchAllAssociative();

            /*$eventsToDelete = [];
            foreach($importedEventsRes as $ev) {
                $deleteIndex = $ev['external_id'] . '-' . $ev['start_date'] . '-' . $ev['start_time'] . '-' . $ev['end_date'] . '-' . $ev['end_time'];
                $eventsToDelete[$deleteIndex] = $ev['uid'];
            }*/

            foreach ($events as $event) {
                $location = $event->location;
                $locationDescription = '';
                $summary = $event->summary == 'Busy' ? '' : $event->summary;
                $startDateTime = new DateTime($event->dtstart);
                $startDate = $startDateTime->format('Y-m-d');
                $startTime = $startDateTime->format('H:i:s');

                $endDateTime = new DateTime($event->dtend);
                $endDate = $endDateTime->format('Y-m-d');
                $endTime = $endDateTime->format('H:i:s');

                $externalId = $event->uid;

                $publicEvent = 0;
                if ($summary) {
                    $publicEvent = 1;
                }

                $calendars = [];
                if (!$defaultCalendar) {
                    if ($location && $calendarMapping[$location]) {
                        $sql = 'SELECT uid FROM tx_igreservations_domain_model_calendar
                        WHERE uid = ' . $calendarMapping[$location] . ' AND deleted = 0';
                        $stmt = $this->conn->prepare($sql);
                        $res = $stmt->executeQuery();
                        $row = $res->fetchAssociative();
                        if ($row) {
                            $calendars[] = $row['uid'];
                        } else {
                            $io->writeln('Fehler, calendarMapping für location ist falsch: ' . $location);
                        }
                    } elseif ($location) {
                        $locationDescription = $location;
                        $calendars[] = 0;
                        $io->writeln('Fehler, location nicht in DB: ' . $location);
                    }
                } elseif ($defaultCalendar) {
                    $calendars[] = $defaultCalendar;
                }

                /*if($locationDescription == 'Alle Räume') {
                    $sql = 'SELECT uid FROM tx_igreservations_domain_model_calendar WHERE deleted = 0';
                    $stmt = $this->conn->prepare($sql);
                    $stmt->execute([]);
                    $res = $stmt->fetchAll();
                    foreach($res as $row) {
                        $calendars[] = $row['uid'];
                    }
                }*/

                $row = [
                    'pid' => $pid,
                    'name' => $summary,
                    'import_id' => $importId,
                    'is_public' => $publicEvent,
                    'external_id' => $externalId,
                    'start_date' => $startDate,
                    'start_time' => $startTime,
                    'end_date' => $endDate,
                    'end_time' => $endTime,
                    'location_description' => $locationDescription,
                ];

                $i = 0;
                foreach ($calendars as $calendar) {
                    $sql = 'SELECT * FROM tx_igreservations_domain_model_event
                    WHERE calendar = ' . $calendar . '
                    AND (
                        (start_date = \'' . $startDate . '\' AND external_id = \'' . $externalId . '\')
                        OR (
                            start_date = \'' . $startDate . '\' AND start_time <= \'' . $startTime . '\'
                            AND end_date = \'' . $endDate . '\' AND end_time >= \'' . $endTime . '\'
                        )
                    )';
                    $stmt = $this->conn->prepare($sql);
                    $res = $stmt->executeQuery();

                    $row['calendar'] = $calendar;
                    if ($i == 0) {
                        $row['main_event'] = 1;
                    }

                    $existingEvent = $res->fetchAssociative();
                    if ($existingEvent) {
                        // Update (Use original import id and external_id)
                        $this->conn->update('tx_igreservations_domain_model_event', $row, [
                            'uid' => $existingEvent['uid'],
                        ]);
                        $updateCount++;
                    } else {
                        // Insert
                        $this->conn->insert('tx_igreservations_domain_model_event', $row);
                        $insertCount++;
                    }
                }
            }
        }

        $this->conn->commit();

        $io->writeln('Insert Count: ' . (int)$insertCount);
        $io->writeln('Update Count: ' . (int)$updateCount);
        //$io->writeln('Delete Count: ' . (int)$deleteCount);

        return 0;
    }

    protected function insertOrUpdateEvent($row, $calendars)
    {
    }

    /**
     * Sends an email
     */
    protected function sendHtmlMail(
        string $subject,
        array $from,
        array $to,
        string $template,
        array $variables = [],
        $debug = false
    ) {
        $html = $this->renderFluidTemplate($template, $variables);

        if ($debug) {
            die($html);
        }

        $mail = GeneralUtility::makeInstance(MailMessage::class);
        $mail->setSubject($subject)
            ->setFrom($from)
            ->setTo($to)
            ->text($html);
        GeneralUtility::makeInstance(Mailer::class)->send($mail);
    }

    private function renderFluidTemplate(string $template, array $variables = []): string
    {
        $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
        $conf = $configurationManager->getConfiguration(
            ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT
        )['plugin.']['tx_igreservations.'];

        $view = $this->viewFactory->create(new ViewFactoryData(
            templateRootPaths: $conf['view.']['templateRootPaths.'] ?? [],
            partialRootPaths: $conf['view.']['partialRootPaths.'] ?? [],
            layoutRootPaths: $conf['view.']['layoutRootPaths.'] ?? [],
        ));
        $view->assignMultiple($variables);
        return $view->render($template);
    }
}
