<?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 to leave
 * a feedback some days after the check-out of the take-away order.
 * 
 * @since 1.10
 */
class OrderFeedbackMailReminder 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
            {
                /**
                 * Skip orders in case they don't have a configured email address. Otherwise the system will
                 * attempt to notify them at every execution of the cron job.
                 * 
                 * This way we can register a warning under the logs and flag the order as tracked.
                 * 
                 * @since 1.11.2
                 */
                if ($order->purchaser_mail)
                {
                    /**
                     * 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);

                    // register successful log
                    $status->appendContent("The order #{$order->id} has been notified at {$order->purchaser_mail}.");
                }
                else
                {
                    // register warning
                    $status->appendContent(sprintf(
                        "<span style=\"color: #f60;\">It was not possible to send a notification to the order #%s because the email recipient is empty.</span>",
                        $order->id
                    ));
                }

                /**
                 * Set the order as notified.
                 * 
                 * @see ReminderInstallation
                 */
                $this->setNotified($this->getId(), $order->id);
            }
            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') . ' hours', \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, which was rebuilt into:
         * check-in <= NOW - threshold
         */
        $query->where($db->qn('r.checkin_ts') . ' <= ' . $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 hope you enjoyed your meal from our restaurant!</p>\n"
            . "<div>{custom_position_middle}</div>\n"
            . "<p>We'd love to hear your thoughts so we can continue improving and provide you with an even better experience. Please take a few moments to share your feedback with us. Your opinion is very important to us!</p>\n"
            . "<p>You can leave your feedback by clicking the link below:<br><a href=\"{order_link}\" target=\"_blank\">{order_link}</a></p>\n"
            . "<div>{custom_position_bottom}</div>\n"
            . "<p>Thank you so much for your time, and we look forward to serving you again soon!</p>\n"
            . "<p>Best regards,<br>{company_name}</p>\n"
            . "<div>{custom_position_footer}</div>";

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

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

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