<?php

declare(strict_types=1);

/*
* This file is part of newsmailer bundle for Contao.
*
* (c) Benjamin Roth
*
* @license LGPL-3.0-or-later
*/

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\WeinanlieferungSlotsModel;
use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungStandortModel;

/**
 * @CronJob("*\/10 * * * *")
 */
class SendSlotChangeNotificationJob
{
    /** @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();

                // Get members
                $memberGroupIds = StringUtil::deserialize($Location->nc_notification_groups,true);
                $memberGroupSqlFragment = [];
                if (!count($memberGroupIds))
                {
                    continue;
                }
                foreach ($memberGroupIds as $memberGroupId)
                {
                    $memberGroupSqlFragment[] = "`groups` LIKE '%\"$memberGroupId\"%'";
                }
                $Members = MemberModel::findBy(array("(".implode(' OR ',$memberGroupSqlFragment).")","(start='' OR start<='$time') AND (stop='' OR stop>'" . ($time + 60) . "') AND disable=''"),null);

                // Do we have updateable items
                $Slots = $this->db->executeQuery("SELECT s.id, s.date, s.time, s.duration, s.behaelter, s.sorten, s.ernteart, s.lage, s.anmerkungen, s.nc_sent, s.buchbar_ab, s.buchbar_bis FROM tl_vr_wa_slot s WHERE s.pid = ? AND s.nc_sent < s.tstamp AND s.published='1' AND (buchbar_ab='' OR buchbar_ab<='$time') AND (buchbar_bis='' OR buchbar_bis>'" . ($time + 60) . "')",[$Location->id]);

                // Load groups and notification models if we have news to share
                if ($Members !== null && $Slots->rowCount() && ($Notification = Notification::findByPk($Location->nc_notification_slots)) !== null)
                {
                    foreach ($Slots->iterateAssociative() as $Slot)
                    {
                        $arrSortenAvailable = [];
                        $arrErnteartAvailable = [];
                        $arrLageAvailable = [];
                        $arrSortenBooked = [];
                        $arrErnteartBooked = [];
                        $arrLageBooked = [];

                        $SlotModel = WeinanlieferungSlotsModel::findByPk($Slot['id']);

                        if (isset($Slot['slot_sorten']))
                        {
                            $SortenLeseart = StringUtil::deserialize($Slot['sorten'],true);
                            foreach($SortenLeseart as $sorteLeseart)
                            {
                                $objSorte = WeinanlieferungRebsorteModel::findByPk($sorteLeseart['sorte']);
                                $objLeseart = WeinanlieferungLeseartModel::findByPk($sorteLeseart['leseart']);
                                $arrSortenAvailable[$objSorte->id.','.$objLeseart->id] = ($objSorte !== null  ? $objSorte->title : '') . ' ' . ($objLeseart !== null  ? $objLeseart->title : '');
                            }
                        }
                        if (isset($Slot['ernteart']))
                        {
                            foreach (explode(',', $Slot['ernteart']) as $ernteart)
                            {
                                $arrErnteartAvailable[$ernteart] = $GLOBALS['TL_LANG']['REF']['wa_ernteart'][$ernteart] ?? $ernteart;
                            }
                        }
                        if (isset($Slot['lage']))
                        {
                            foreach (explode(',', $Slot['lage']) as $lage)
                            {
                                if (($Lage = WeinanlieferungLageModel::findByPk($lage)) !== null)
                                {
                                    $arrLageAvailable[$Lage->id] = $Lage->title;
                                }
                            }
                        }

                        // Send notification to member
                        foreach ($Members as $Member)
                        {
                            $Notification->send(array
                            (
                                '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(),$Slot['date']),
                                'slot_time'             => Date::parse(Date::getNumericTimeFormat(),$Slot['time']),
                                'slot_standort'         => $Location->title,
                                'slot_behaelter'        => $Slot['behaelter'],
                                'slot_behaelterBuchbar' => $SlotModel !== null ? $SlotModel->getAvailableBehaelter() : '',
                                'slot_sorten'           => implode(', ',$arrSortenAvailable),
                                'slot_ernteart'         => implode(', ',$arrErnteartAvailable),
                                'slot_lage'             => implode(', ',$arrLageAvailable),
                                'slot_anmerkungen'      => $Slot['anmerkungen'],
                                'slot_ncsent'           => $Slot['nc_sent'],
                                'slot_buchbar_ab'       => Date::parse(Date::getNumericDatimFormat(),$Slot['buchbar_ab']),
                                'slot_buchbar_bis'      => Date::parse(Date::getNumericDatimFormat(),$Slot['buchbar_bis']),
                                'admin_email'           => $admin_email,
                            ),
                                $GLOBALS['TL_LANGUAGE']);

                            $intNotificationsCount++;
                        }

                        $this->db->executeStatement("UPDATE tl_vr_wa_slot SET nc_sent = ? WHERE id = ?",[$time,$Slot['id']]);
                    }
                }
            }

            // Flag news as sent
            if ($intNotificationsCount)
            {
                $this->logger->log(LogLevel::INFO, sprintf('WA notifications(%s) has been sent',$intNotificationsCount), array('contao' => new ContaoContext(__METHOD__, 'CRON')));
            }
        }
    }
}