<?php

namespace Ig\IgReservations\Command;

use DateTime;
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\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager;
use Undkonsorten\ExtbaseCliAwareConfigurationManager\Configuration\CliAwareConfigurationManager;

class ReminderCommand extends Command
{
    public function __construct(
        protected CliAwareConfigurationManager $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);


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

        $pageUid = (int)$settings['adminPageUid'];
        // set TYPO3_REQUEST for link builder from site with adminPageUid
        $finder = GeneralUtility::makeInstance(SiteFinder::class);
        $site = $finder->getSiteByPageId($pageUid);
        //$siteUrl = (string) $site->getBase();

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

        $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();
        //$confirmedStatusses = $this->statusRepository->findForReminder();

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

        /** @var Reminder $reminder */
        foreach($reminders as $reminder) {
            $events = $this->getEventsForReminder($conn, $reminder);
            //$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 Event $event */
            foreach($events as $event) {
                $reservations = $this->getReservationsForEvent($conn, $event);
                //$reservations = $this->reservationRepository->findForReminder($event);

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

                /** @var Reservation $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();

                    $mailService->sendMail(
                        $from,
                        $mailsTo,
                        $subject . ($debugMail !== '' ? ' (' . $reservation['email'] . ')' : ''),
                        'IgReservations/Command/Reminder/User',
                        [
                            'event' => $event,
                            'reservation' => $reservation,
                            '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
    {
        $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', $now->format('Y-m-d')),
                    $qb->expr()->gte('start_time', $now->format('H:i:s')),
                ),
                $qb->expr()->and(
                    $qb->expr()->gt('start_date', $now->format('Y-m-d')),
                    $qb->expr()->lte('start_date', $limit->format('Y-m-d')),
                )
            ));

        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;
    }
}
