<?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
 */

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

/**
 * VikRestaurants cron job log model.
 *
 * @since 1.10
 */
class VikRestaurantsModelCronjoblog extends JModelVRE
{
    /**
     * Basic item loading implementation.
     *
     * @param   mixed  $pk   An optional primary key value to load the row by, or an array of fields to match.
     *                       If not set the instance property value is used.
     * @param   bool   $new  True to return an empty object if missing.
     *
     * @return  mixed  The record object on success, null otherwise.
     */
    public function getItem($pk, $new = false)
    {
        // load item through parent
        $item = parent::getItem($pk, $new);

        if ($item)
        {
            // unserialize metadata array
            $metadata = (array) ($item->metadata ? unserialize($item->metadata) : []);

            $item->metadata = [];
            
            foreach ($metadata as $obj)
            {
                if ($obj instanceof \E4J\VikRestaurants\Metadata\Metadata)
                {
                    $item->metadata[] = $obj;
                }
            }
        }

        return $item;
    }

    /**
     * Basic save implementation.
     *
     * @param   mixed  $data  Either an array or an object of data to save.
     *
     * @return  mixed  The ID of the record on success, false otherwise.
     */
    public function save($data)
    {
        $data = (array) $data;

        // fetch cron logging mode:
        // - [0] never
        // - [1] only with errors
        // - [2] always
        $loggingMode = VREFactory::getConfig()->getUint('cron_log_mode');

        // auto-flush existing logs first
        $this->flush($data['id_cronjob'] ?? null);
        
        if ($loggingMode == 0 || ($loggingMode == 1 && !empty($data['status'])))
        {
            // get last log registered for the given cron job
            $seek = [
                'id_cronjob' => $data['id_cronjob'] ?? 0
            ];

            if ($loggingMode == 1)
            {
                // get last successful log
                $seek['status'] = 1;
            }

            if ($last = $this->getItem($seek))
            {
                // delete log found
                $this->delete($last->id);
            }
        }

        // attempt to save the cron job log
        return parent::save($data);
    }

    /**
     * Method to truncate the table.
     *
     * @param   int   $cronId  An optional ID to delete all the logs assigned to the
     *                         specified cron job.
     *
     * @return  bool  True on success, false otherwise.
     */
    public function truncate(?int $cronId = null)
    {
        $db = JFactory::getDbo();

        if ($cronId)
        {
            // delete only the logs assigned to the specified cron job
            $query = $db->getQuery(true)
                ->delete($db->qn('#__vikrestaurants_cronjob_log'))
                ->where($db->qn('id_cronjob') . ' = ' . $cronId);
        }
        else
        {
            // truncate all the logs registered by any cron jobs
            $query = "TRUNCATE TABLE " . $db->qn('#__vikrestaurants_cronjob_log');
        }

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

    /**
     * Flushes all the cron logs that are at least N days in the past, where
     * N is equals to the passed argument.
     * 
     * @param   int|null  $cronId  An optional cron ID to flush only the logs
     *                             assigned to the latter.
     * @param   int|null  $days    The threshold in days. Use the defaul system
     *                             setting when not specified.
     *
     * @return  void
     */
    public function flush(?int $cronId = null, ?int $days = null)
    {
        if (is_null($days))
        {
            // use global setting
            $days = VREFactory::getConfig()->getUint('cron_log_flush', 0);
        }

        if ($days > 0)
        {
            $db = JFactory::getDbo();

            $now = JFactory::getDate();
            $now->modify('-' . $days . ' days');

            $query = $db->getQuery(true)
                ->delete($db->qn('#__vikrestaurants_cronjob_log'))
                ->where($db->qn('createdon') . ' < ' . $db->q($now->toSql()));

            if ($cronId)
            {
                // filter logs by cron job
                $query->where($db->qn('id_cronjob') . ' = ' . (int) $cronId);
            }
            
            $db->setQuery($query);
            $db->execute();
        }
    }
}
