<?php

declare(strict_types=1);

/*
* This file is part of contao-weinanlieferung-bundle.
*
* (c) vonRotenberg
*
* @license commercial
*/

namespace vonRotenberg\WeinanlieferungBundle\Cron;

use Contao\Config;
use Contao\CoreBundle\Monolog\ContaoContext;
use Contao\CoreBundle\ServiceAnnotation\CronJob;
use Contao\Date;
use Contao\MemberModel;
use Contao\StringUtil;
use Contao\System;
use Doctrine\DBAL\Connection;
use NotificationCenter\Model\Notification;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungLageModel;
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungLeseartModel;
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungRebsorteModel;
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungStandortModel;

/**
 * @CronJob("* * * * *")
 */
class SendCheckInNotificationJob
{
    /** @var LoggerInterface */
    private $logger;

    /** @var Connection */
    private $db;

    public function __construct(Connection $db, LoggerInterface $logger)
    {
        $this->logger = $logger;
        $this->db = $db;
    }

    public function __invoke(string $scope)
    {
        System::loadLanguageFile('default', 'de');
        list($admin_name, $admin_email) = StringUtil::splitFriendlyEmail(Config::get('adminEmail'));
        $intNotificationsCount = 0;

        // Get locations
        $Locations = WeinanlieferungStandortModel::findBy('nc_enable', '1');

        if ($Locations !== null) {
            while ($Locations->next()) {
                $Location = $Locations->current();
                $time = Date::floorToMinute();

                // Do we have check-ins that need notifications
                // The key difference from SendBookingChangeNotificationJob is the WHERE clause:
                // We look for r.checked_in = '1' AND r.checked_in_on > r.checked_in_nc_sent
                $Bookings = $this->db->executeQuery(
                    "SELECT r.id, r.pid, r.uid, r.behaelter, r.sorten, r.lage, r.ernteart, r.upload, r.nc_sent, r.checked_in_nc_sent,
                    s.date as slot_date, s.time as slot_time, s.behaelter as slot_behaelter,
                    s.sorten as slot_sorten, s.ernteart as slot_ernteart, s.lage as slot_lage,
                    s.anmerkungen as slot_anmerkungen, r.approved, r.approved_on, r.checked_in,
                    r.checked_in_on, r.behaelter_numbers
                    FROM tl_vr_wa_reservation r
                    INNER JOIN tl_vr_wa_slot s ON s.id = r.pid
                    WHERE s.pid = ? AND r.checked_in = '1' AND r.checked_in_on > r.checked_in_nc_sent AND s.published='1'",
                    [$Location->id]
                );

                // Load notification model if we have check-ins to notify
                if ($Bookings->rowCount() && ($Notification = Notification::findByPk($Location->nc_notification_checkin)) !== null) {
                    foreach ($Bookings->iterateAssociative() as $Booking) {
                        // Get member
                        $Member = MemberModel::findOneBy(
                            ["id = ?", "login='1' AND (start='' OR start<='$time') AND (stop='' OR stop>'" . ($time + 60) . "') AND disable=''"],
                            [$Booking['uid']]
                        );

                        // Send notification to member
                        if ($Member !== null) {
                            $arrSortenAvailable = [];
                            $arrErnteartAvailable = [];
                            $arrLageAvailable = [];
                            $arrSortenBooked = [];
                            $arrErnteartBooked = [];
                            $arrLageBooked = [];

                            $SortenLeseart = StringUtil::deserialize($Booking['slot_sorten'], true);
                            foreach ($SortenLeseart as $sorteLeseart) {
                                $objSorte = WeinanlieferungRebsorteModel::findByPk($sorteLeseart['sorte']);
                                $objLeseart = WeinanlieferungLeseartModel::findByPk($sorteLeseart['leseart']);
                                if ($objSorte !== null && $objLeseart !== null) {
                                    $arrSortenAvailable[$objSorte->id . ',' . $objLeseart->id] =
                                        $objSorte->title . ' ' . $objLeseart->title;
                                }
                            }

                            if (!empty($Booking['sorten'])) {
                                $SortenLeseart = explode(';', $Booking['sorten']);
                                foreach ($SortenLeseart as $sorteLeseart) {
                                    if (empty($sorteLeseart)) {
                                        continue;
                                    }
                                    $parts = explode(',', $sorteLeseart);
                                    if (count($parts) >= 2) {
                                        $sorte = $parts[0];
                                        $leseart = $parts[1];
                                        $objSorte = WeinanlieferungRebsorteModel::findByPk($sorte);
                                        $objLeseart = WeinanlieferungLeseartModel::findByPk($leseart);
                                        if ($objSorte !== null && $objLeseart !== null) {
                                            $arrSortenBooked[$objSorte->id . ',' . $objLeseart->id] =
                                                $objSorte->title . ' ' . $objLeseart->title;
                                        }
                                    }
                                }
                            }

                            if (!empty($Booking['ernteart'])) {
                                foreach (explode(',', $Booking['ernteart']) as $ernteart) {
                                    if (empty($ernteart)) {
                                        continue;
                                    }
                                    $arrErnteartBooked[$ernteart] = $GLOBALS['TL_LANG']['REF']['wa_ernteart'][$ernteart] ?? $ernteart;
                                }
                            }

                            if (!empty($Booking['slot_ernteart'])) {
                                foreach (explode(',', $Booking['slot_ernteart']) as $ernteart) {
                                    if (empty($ernteart)) {
                                        continue;
                                    }
                                    $arrErnteartAvailable[$ernteart] = $GLOBALS['TL_LANG']['REF']['wa_ernteart'][$ernteart] ?? $ernteart;
                                }
                            }

                            if (!empty($Booking['slot_lage'])) {
                                foreach (explode(',', $Booking['slot_lage']) as $lage) {
                                    if (empty($lage)) {
                                        continue;
                                    }
                                    if (($Lage = WeinanlieferungLageModel::findByPk($lage)) !== null) {
                                        $arrLageAvailable[$Lage->id] = $Lage->title;
                                    }
                                }
                            }

                            if (!empty($Booking['lage'])) {
                                foreach (explode(',', $Booking['lage']) as $lage) {
                                    if (empty($lage)) {
                                        continue;
                                    }
                                    if (($Lage = WeinanlieferungLageModel::findByPk($lage)) !== null) {
                                        $arrLageBooked[$Lage->id] = $Lage->title;
                                    }
                                }
                            }

                            // Behaelter numbers handling
                            $blnIsIncomplete = false;
                            $arrBehaelterNumbers = [];

                            $behaelterNumbers = json_decode($Booking['behaelter_numbers'] ?? '[]', true);
                            $isNewFormat = isset($behaelterNumbers[0]) && is_array($behaelterNumbers[0]) && isset($behaelterNumbers[0]['behaelter']);

                            // If it's the old format, convert it to the new format for compatibility
                            if (!$isNewFormat) {
                                $oldFormat = $behaelterNumbers;
                                $memberModel = MemberModel::findById($Booking['uid']);

                                $behaelterNumbers = [];
                                foreach ($oldFormat as $number) {
                                    $behaelterNumbers[] = [
                                        'behaelter' => $number,
                                        'member' => $memberModel->memberno
                                    ];
                                }
                            }
                            foreach ($behaelterNumbers as $behaelterNumber) {
                                if ($behaelterNumber['behaelter'] === '9999') {
                                    $blnIsIncomplete = true;
                                }
                                $arrBehaelterNumbers[] = $behaelterNumber['behaelter'] . ' [Mitglied: ' . $behaelterNumber['member'] . ']';
                            }

                            // Send notification with all booking data
                            // We include the check-in specific fields: checked_in, checked_in_on, behaelter_numbers
                            $Notification->send(
                                [
                                    'member_email'       => $Member->email . ($Member->nc_news_additionalEmail ? ',' . $Member->nc_news_additionalEmail : ''),
                                    'member_firstname'   => $Member->firstname,
                                    'member_lastname'    => $Member->lastname,
                                    'member_memberno'    => $Member->memberno,
                                    'slot_date'          => Date::parse(Date::getNumericDateFormat(), $Booking['slot_date']),
                                    'slot_time'          => Date::parse(Date::getNumericTimeFormat(), $Booking['slot_time']),
                                    'slot_standort'      => $Location->title,
                                    'slot_behaelter'     => $Booking['slot_behaelter'],
                                    'slot_sorten'        => implode(', ', $arrSortenAvailable),
                                    'slot_ernteart'      => implode(', ', $arrErnteartAvailable),
                                    'slot_lage'          => implode(', ', $arrLageAvailable),
                                    'slot_anmerkungen'   => $Booking['slot_anmerkungen'],
                                    'booking_ncsent'     => $Booking['nc_sent'],
                                    'booking_behaelter'  => $Booking['behaelter'],
                                    'booking_sorten'     => implode(', ', $arrSortenBooked),
                                    'booking_ernteart'   => implode(', ', $arrErnteartBooked),
                                    'booking_lage'       => implode(', ', $arrLageBooked),
                                    'booking_approved'   => $Booking['approved'],
                                    'booking_approved_on'=> $Booking['approved_on'],
                                    'booking_checked_in' => $Booking['checked_in'],
                                    'booking_checked_in_on' => $Booking['checked_in_on'],
                                    'booking_checked_in_ncsent'     => $Booking['checked_in_nc_sent'],
                                    'booking_checkin_incomplete'     => $blnIsIncomplete,
                                    'booking_behaelter_numbers' => \implode(', ', $arrBehaelterNumbers),
                                    'admin_email'        => $admin_email,
                                ],
                                $GLOBALS['TL_LANGUAGE']
                            );

                            // Update the checked_in_nc_sent timestamp to mark this notification as sent
                            $intNotificationsCount++;
                            $this->db->executeStatement(
                                "UPDATE tl_vr_wa_reservation SET checked_in_nc_sent = ? WHERE id = ?",
                                [$time, $Booking['id']]
                            );
                        }
                    }
                }
            }

            // Log notifications sent
            if ($intNotificationsCount) {
                $this->logger->log(
                    LogLevel::INFO,
                    sprintf('WA check-in notifications(%s) has been sent', $intNotificationsCount),
                    ['contao' => new ContaoContext(__METHOD__, 'CRON')]
                );
            }
        }
    }
}