<?php

namespace Ig\IgReservations\Command;

use DateTime;
use Doctrine\DBAL\ParameterType;
use Ig\IgReservations\Domain\Model\Event;
use Ig\IgReservations\Domain\Model\Reminder;
use Ig\IgReservations\Domain\Model\Reservation;
use Ig\IgReservations\Domain\Model\Status;
use Ig\IgReservations\Service\MailService;
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\Core\SystemEnvironmentBuilder;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Http\ServerRequest;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;

class ReminderCommand extends Command
{
    public function __construct(
        protected ConfigurationManager $configurationManager,
        //protected EventRepository $eventRepository
    ) {
        parent::__construct();
    }

    /**
     * Configure the command by defining the name, options and arguments
     */
    protected function configure()
    {
        $this->setDescription('Sends a reminder mail to the participants at a specific time');
        $this->setHelp('Sends a reminder mail at a specific time');
    }

    /**
     * Executes the command for showing sys_log entries
     */
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        Bootstrap::initializeBackendAuthentication();


        $extbaseFrameworkConfiguration = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
        $settings = $extbaseFrameworkConfiguration['plugin.']['tx_igreservations.']['settings.'];

        $pageUid = (int)$settings['adminPageUid'];

        $finder = GeneralUtility::makeInstance(SiteFinder::class);
        $site = $finder->getSiteByPageId($pageUid);

        if (!isset($GLOBALS['TYPO3_REQUEST'])) {
            $GLOBALS['TYPO3_REQUEST'] = (new ServerRequest('/', 'GET'))
                ->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_FE)
                ->withAttribute('site', $site);
        } else {
            $GLOBALS['TYPO3_REQUEST'] = $GLOBALS['TYPO3_REQUEST']
                ->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_FE)
                ->withAttribute('site', $site);
        }

        $this->configurationManager->setRequest($GLOBALS['TYPO3_REQUEST']);

        // set TYPO3_REQUEST for link builder from site with adminPageUid
        //$siteUrl = (string) $site->getBase();

        $mailService = GeneralUtility::makeInstance(MailService::class);
        $mailService->setSettings($settings);
        $mailService->setRequest($GLOBALS['TYPO3_REQUEST']);

        $canelledStatusUid = $settings['canceledStatus'] ?? 0;

        $conn = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_igreservations_domain_model_event');
        $qb = $conn->createQueryBuilder();
        $reminders = $qb->select('*')
                        ->from('tx_igreservations_domain_model_reminder')
                        ->executeQuery()
                        ->fetchAllAssociative();
        //$reminders = $this->reminderRepository->findAll();

        $io->writeln(count($reminders) . ' Reminder-Configurations found');
        $io->writeln('');

        $qb = $conn->createQueryBuilder();
        $confirmedStatusses = $qb->select('*')
                        ->from('tx_igreservations_domain_model_status')
                        ->where($qb->expr()->eq('confirmed', 1))
                        ->executeQuery()
                        ->fetchAllAssociative();

        $cancelledStatus = null;
        if($canelledStatusUid > 0) {
            $cancelledStatus = $conn->createQueryBuilder()
                ->select('*')
                ->from('tx_igreservations_domain_model_status')
                ->where($qb->expr()->eq('uid', $canelledStatusUid))
                ->executeQuery()
                ->fetchAssociative();
        }
        //$confirmedStatusses = $this->statusRepository->findForReminder();

        $confirmedStatusUids = [];
        /** @var array $status */
        foreach($confirmedStatusses as $status) {
            $confirmedStatusUids[] = $status['uid'];
        }

        /** @var array $reminder */
        foreach($reminders as $reminder) {
            $events = $this->getEventsForReminder($conn, $reminder, $confirmedStatusUids);
            //$events = $this->eventRepository->findForReminder($reminder, $confirmedStatusUids);
            $from = $reminder['mail_from'] ?? '';
            $subject = $reminder['subject'] ?? '';
            $debugMail = $reminder['debug_email'] ?? '';

            if($debugMail !== '') {
                $io->writeln('All mails sent to debug mail: ' . $debugMail);
                $io->writeln('');
            }

            $timeModifier = $reminder['time_modifier'];

            $limit = new DateTime();
            $limit->modify($timeModifier);

            $io->writeln(count($events) . ' Events found for Reminder ' . $reminder['uid']);

            /** @var array $event */
            foreach($events as $event) {
                if($cancelledStatus && $event['status'] == $canelledStatusUid) {
                    $io->writeln('Event ' . $event['uid'] . ' is cancelled. No reminder sent.');
                    continue;
                }
                $reservations = $this->getReservationsForEvent($conn, $event);
                //$reservations = $this->reservationRepository->findForReminder($event);

                $io->writeln(count($reservations) . ' Reservations found for Event ' . $event['uid']);


                $location = null;
                if ($event['location']) {
                    $qb = $conn->createQueryBuilder();
                    $location = $qb->select('*')
                        ->from('tx_igreservations_domain_model_location')
                        ->where($qb->expr()->eq('uid', $event['location']))
                        ->executeQuery()
                        ->fetchAssociative();
                }
                /** @var array $reservation */
                foreach($reservations as $reservation) {
                    if($reservation['reminder_sent']) {
                        $io->writeln('Reminder already sent for Reservation ' . $reservation['uid'] . ' to ' . $reservation['email']);
                        continue;
                    }
                    if($reservation['reminder_sent'] || $reservation['email'] === '' || ($reservation['email'] !== '' && !GeneralUtility::validEmail($reservation['email']))) {
                        $io->writeln('Not sending reminder mail for Reservation ' . $reservation['uid'] . ' to ' . $reservation['email']);
                        continue;
                    }

                    $io->writeln('Sending reminder mail for Reservation ' . $reservation['uid'] . ' to ' . $reservation['email']);

                    $mailsTo = [$debugMail !== '' ? $debugMail : $reservation['email']];
                    $siteLanguage = $site->getLanguageById($reservation['language']);
                    $reservationLanguage = $siteLanguage;
                    $locale = $reservationLanguage->getLocale();
                    $languageKey = $locale->getLanguageCode();

                    $qb = $conn->createQueryBuilder();
                    
                    $mailService->sendMail(
                        $from,
                        $mailsTo,
                        $subject . ($debugMail !== '' ? ' (' . $reservation['email'] . ')' : ''),
                        'IgReservations/Command/Reminder/User',
                        [
                            'greeting' => $this->getGreeting($reservation, $languageKey),
                            'event' => $event,
                            'reservation' => $reservation,
                            'location' => $location,
                            'reminder' => $reminder,
                            'settings' => $settings,
                            'languageKey' => $languageKey
                        ],
                        $locale
                    );


                    //$reservation->setReminderSent(true);
                    $conn->update('tx_igreservations_domain_model_reservation', ['reminder_sent' => 1], ['uid' => $reservation['uid']]);
                }
                $io->writeln('');
            }
            $io->writeln('');
        }
        GeneralUtility::makeInstance(PersistenceManager::class)->persistAll();
        $io->writeln('DONE');
        return 0;
    }

    protected function getEventsForReminder(Connection $conn, $reminder, array $confirmedStatusUids = []): array
    {
        $timeModifier = $reminder['time_modifier'];
        $now = new DateTime();

        $limit = new DateTime();
        $limit->modify($timeModifier);

        $qb = $conn->createQueryBuilder();
        $qb->select('*')
            ->from('tx_igreservations_domain_model_event')
            ->where($qb->expr()->or(
                $qb->expr()->and(
                    $qb->expr()->eq('start_date', $qb->createNamedParameter($now->format('Y-m-d'), ParameterType::STRING)),
                    $qb->expr()->gte('start_time', $qb->createNamedParameter($now->format('H:i:s'), ParameterType::STRING)),
                ),
                $qb->expr()->and(
                    $qb->expr()->gt('start_date', $qb->createNamedParameter($now->format('Y-m-d'), ParameterType::STRING)),
                    $qb->expr()->lte('start_date', $qb->createNamedParameter($limit->format('Y-m-d'), ParameterType::STRING)),
                )
            ));

        if (!empty($confirmedStatusUids)) {
            $qb->andWhere($qb->expr()->in('status', $confirmedStatusUids));
        }

        $events = $qb->executeQuery()->fetchAllAssociative();
        return $events;
    }

    protected function getReservationsForEvent(Connection $conn, $event): array
    {
        $qb = $conn->createQueryBuilder();
        $reservations = $qb->select('*')
            ->from('tx_igreservations_domain_model_reservation')
            ->where($qb->expr()->eq('event', $event['uid']))
            ->executeQuery()
            ->fetchAllAssociative();

        return $reservations;
    }

    protected function getGreeting($reservation, $languageKey)
    {
        $greeting = '';
        if ($reservation['salutation']) {
            $greeting .= LocalizationUtility::translate('tx_igreservations_domain_model_address.salutation.' . $reservation['salutation'], 'IgReservations', null, $languageKey);
        }
        /*if($this->getFirstName()) {
            if ($greeting != '') {
                $greeting .= ' ';
            }
            $greeting .= $this->getFirstName();
        }*/
        if ($reservation['last_name']) {
            if ($greeting != '') {
                $greeting .= ' ';
            }
            $greeting .= $reservation['last_name'];
        }
        return $greeting;
    }
}
