<?php
/** 
 * @package     VikRestaurants
 * @subpackage  core
 * @author      E4J s.r.l.
 * @copyright   Copyright (C) 2023 E4J s.r.l. All Rights Reserved.
 * @license     http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
 * @link        https://vikwp.com
 */

namespace E4J\VikRestaurants\Cron\Jobs\TakeAway;

// No direct access
defined('ABSPATH') or die('No script kiddies please!');

use E4J\VikRestaurants\Cron\CronJob;
use E4J\VikRestaurants\Cron\Installable;
use E4J\VikRestaurants\Cron\Status;
use E4J\VikRestaurants\Cron\Traits\NotificationMailBuilder;
use E4J\VikRestaurants\Cron\Traits\NotificationMailDispatcher;
use E4J\VikRestaurants\Cron\Traits\NotificationMailForm;
use E4J\VikRestaurants\Cron\Traits\ReminderInstallation;
use E4J\VikRestaurants\Cron\Traits\OrderNotificationTaggableBuilder;

/**
 * This cron job can be used to send a notification e-mail to remind the customers of the
 * upcoming check-in of their order.
 * 
 * @since 1.10
 */
class OrderCheckinMailReminder extends CronJob implements Installable
{
    use NotificationMailBuilder;
    use NotificationMailDispatcher;
    use NotificationMailForm;
    use ReminderInstallation;
    use OrderNotificationTaggableBuilder;

    /**
     * @inheritDoc
     * 
     * @see CronJob
     */
    protected function execute(\JRegistry $args, Status $status)
    {
        // load all the orders that should be notified
        $orders = $this->loadOrders($args);

        if (!$orders)
        {
            // no orders retrieved : stop process [OK]
            return $status->appendContent('Process terminated correctly! No orders to notify.');
        }

        // iterate the orders one by one
        foreach ($orders as $orderId)
        {
            // load order details
            $order = \VREOrderFactory::getOrder($orderId);

            // register log metadata
            $status->addMetadata(new \E4J\VikRestaurants\Metadata\Addon\TakeAwayOrderDetails($orderId));

            try
            {
                /**
                 * Construct a default e-mail template.
                 * 
                 * @see NotificationMailBuilder
                 */
                $mailTemplate = $this->createMailTemplate($order->langtag, $args, $this->getId());

                /**
                 * Configures the provided template with the current take-away order details.
                 * 
                 * @see OrderNotificationTaggableBuilder
                 */
                $this->setupTemplate($mailTemplate, $order);

                /**
                 * Attempt to send the notification.
                 * 
                 * @see NotificationMailDispatcher
                 */
                $this->sendNotification($order->purchaser_mail, $mailTemplate);

                /**
                 * Set the order as notified.
                 * 
                 * @see ReminderInstallation
                 */
                $this->setNotified($this->getId(), $order->id);

                // register successful log
                $status->appendContent("The order #{$order->id} has been notified at {$order->purchaser_mail}.");
            }
            catch (\Exception $error)
            {
                // register error log
                $status->setStatus(false)->appendContent(sprintf(
                    "<span style=\"color: #900;\">It was not possible to send a notification to the order #%s for the following reason. %s</span>",
                    $order->id,
                    $error->getMessage()
                ));
            }
        }
    }

    /**
     * Load all the take-away orders that should receive a notification.
     * 
     * @param   \JRegistry  $args
     * 
     * @return  int[]  A list of matching order IDs.
     */
    protected function loadOrders(\JRegistry $args)
    {
        $db = \JFactory::getDbo();

        $threshold = strtotime('+' . (int) $args->get('threshold') . ' minutes', \VikRestaurants::now());

        // get any approved codes
        $approved = \JHtml::fetch('vrehtml.status.find', 'code', ['takeaway' => 1, 'approved' => 1]); 

        // retrieve orders to notify
        $query = $db->getQuery(true)
            ->select($db->qn('r.id'))
            ->from($db->qn('#__vikrestaurants_takeaway_reservation', 'r'))
            ->order($db->qn('r.checkin_ts') . ' ASC');

        /**
         * Extend the query to exclude the orders that have been already notified.
         * 
         * @see ReminderInstallation
         */
        $this->filterQuery($this->getId(), $query, $db);

        if ($approved)
        {
            // filter by approved status
            $query->where($db->qn('r.status') . ' IN (' . implode(',', array_map(array($db, 'q'), $approved)) . ')');
        }

        /**
         * Take the orders only when the following condition is verified:
         * (check-in - threshold) <= NOW <= (check-in - threshold + margin)
         * Where [threshold] is equals to the specified setting and [margin]
         * is fixed to 15 minutes.
         */
        $query->where($db->qn('r.checkin_ts') . ' <= ' . $threshold);
        $query->where($db->qn('r.checkin_ts') . ' >= ' . strtotime('-15 minutes', $threshold));

        $db->setQuery($query);
        return $db->loadColumn();
    }

    /**
     * @inheritDoc
     * 
     * Supported only in case the take-away section has been enabled.
     * 
     * @see Runnable
     */
    public function isSupported()
    {
        return \VikRestaurants::isTakeAwayEnabled();
    }

    /**
     * @inheritDoc
     * 
     * @see Configurable
     */
    public function getForm()
    {
        // create the default mail template
        $template = "<div>{custom_position_top}</div>\n"
            . "<p>Dear {customer_first_name},</p>\n"
            . "<p>We wanted to remind you that your food order at our restaurant is scheduled for {checkin_date}, at {checkin_time}.</p>\n"
            . "<div>{custom_position_middle}</div>\n"
            . "<ul>\n"
            . "<li>Service: {order_delivery_service}</li>\n"
            . "<li>Order Number: {order_number}</li>\n"
            . "<li>Address: {service_address}</li>\n"
            . "</ul>\n"
            . "<p>If you need to make any changes to your order or have any special requests, please feel free to reply to this email or call us at our phone number.</p>\n"
            . "<div>{custom_position_bottom}</div>\n"
            . "<p>Looking forward to serving you!</p>\n"
            . "<p>Best regards,<br>{company_name}</p>\n"
            . "<div>{custom_position_footer}</div>";

        $options = [
            'id' => $this->getId(),
            'subject' => \VREFactory::getConfig()->get('restname') . ' - Take-Away Order Reminder',
            'body' => $template,
            'tags' => [
                'logo',
                'company_name',
                'order_number',
                'order_key',
                'checkin_date',
                'checkin_time',
                'service_address',
                'order_delivery_service',
                'order_total_cost',
                'order_total_due',
                'order_link',
                'customer_full_name',
                'customer_first_name',
            ],
        ];

        return array_merge(
            // custom fields
            [
                'threshold' => [
                    'type' => 'number',
                    'label' => \JText::translate('VRE_CRONJOB_SETTING_SEND_ADVANCE_MIN'),
                    'description' => \JText::translate('VRE_CRONJOB_SETTING_SEND_ADVANCE_MIN_HELP'),
                    'required' => true,
                    'default' => 60,
                    'min' => 1,
                    'step' => 1,
                ],
            ],
            /**
             * Mail notification default fields.
             * 
             * @see NotificationMailForm
             */
            $this->getFields($options)
        );
    }

    /**
     * @inheritDoc
     * 
     * @see ReminderInstallation
     */
    final protected function getDatabaseTable()
    {
        return '#__vikrestaurants_takeaway_reservation';
    }
}
