<?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\NotificationSmsBuilder;
use E4J\VikRestaurants\Cron\Traits\NotificationSmsDispatcher;
use E4J\VikRestaurants\Cron\Traits\NotificationSmsForm;
use E4J\VikRestaurants\Cron\Traits\ReminderInstallation;
use E4J\VikRestaurants\Cron\Traits\OrderNotificationTaggableBuilder;

/**
 * This cron job can be used to send a notification SMS to remind the customers of the
 * upcoming check-in of their order.
 * 
 * @since 1.10
 */
class OrderCheckinSmsReminder extends CronJob implements Installable
{
    use NotificationSmsBuilder;
    use NotificationSmsDispatcher;
    use NotificationSmsForm;
    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 SMS template.
                 * 
                 * @see NotificationSmsBuilder
                 */
                $template = $this->createSmsTemplate($order->langtag, $args);

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

                /**
                 * Attempt to send the notification.
                 * 
                 * @see NotificationSmsDispatcher
                 */
                $this->sendNotification($order->purchaser_phone, $template->getTemplate());

                /**
                 * 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_phone}.");
            }
            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()
    {
        $options = [
            'body' => "Dear {customer_first_name}, we'd like to remind you of your take-away order scheduled at {checkin_time} at {company_name}.",
            'tags' => [
                'company_name',
                'order_number',
                'order_key',
                'checkin_date',
                'checkin_time',
                'service_address',
                'order_delivery_service',
                'order_total_cost',
                'order_total_due',
                '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,
                ],
            ],
            /**
             * SMS notification default fields.
             * 
             * @see NotificationSmsForm
             */
            $this->getFields($options)
        );
    }

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