<?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;

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

use E4J\VikRestaurants\Metadata\Metadata;

/** 
 * Class used to manage the response of an executable job.
 *
 * @since 1.10
 */
class Status
{
    /**
     * The log of the response of the cron execution.
     *
     * @var string
     */
    private $content;

    /**
     * The status of the response of the cron job execution.
     *
     * @var bool
     */
    private $status;

    /**
     * When this parameter is true, the administrator should be notified via e-mail with the content.
     * The administrator should be notified only whether the content is not empty.
     *
     * @var bool
     */
    private $notify;

    /**
     * An associative array containing custom meta data.
     * 
     * @var Metadata
     */
    private $metadata = [];

    /**
     * The last update of the response.
     *
     * @var \DateTime
     */
    private $lastUpdate = null;

    /**
     * Class constructor.
     *
     * @param  string  $content  The response content.
     * @param  bool    $status   The response status.
     * @param  bool    $notify   If the response should be notified.
     */
    public function __construct(string $content = '', bool $status = true, bool $notify = false)
    {
        $this->content = $this->prepareContent($content);
        $this->status = $status;
        $this->notify = $notify;

        // last update done during the initialization of the object
        $this->triggerUpdate();
    }

    /**
     * Check if the response contents are not empty.
     *
     * @return  bool  True if the contents are set, otherwise false.
     */
    public function hasContent()
    {
        return !empty($this->content);
    }

    /**
     * Returns the content of the response.
     *
     * @return  string  The content of the response.
     */
    public function getContent()
    {
        return trim($this->content);
    }

    /**
     * Overwrites the content of the response.
     *
     * @param   mixed  $content  The content of the response.
     *
     * @return  self   Returns this object to support chaining.
     */
    public function setContent($content)
    {
        $this->content = $this->prepareContent($content);

        return $this->triggerUpdate();
    }

    /**
     * Appends the content of the response to the existing one.
     *
     * @param   mixed   $content    The content of the response to append.
     * @param   string  $separator  The separator to include before the new contents.
     *
     * @return  self    Returns this object to support chaining.
     */
    public function appendContent($content, string $separator = "\n")
    {
        if (!$this->content)
        {
            return $this->setContent($content);
        }

        $this->content .= $separator . $this->prepareContent($content);

        return $this->triggerUpdate();
    }

    /**
     * Prepends the content of the response before the existing one.
     *
     * @param   mixed   $content    The content of the response to prepend.
     * @param   string  $separator  The separator to include after the new contents.
     *
     * @return  self    Returns this object to support chaining.
     */
    public function prependContent($content, string $separator = "\n")
    {
        if (!$this->content)
        {
            return $this->setContent($content);
        }

        $this->content = $this->prepareContent($content) . $separator . $this->content;

        return $this->triggerUpdate();
    }

    /**
     * Sanitizes the contents before the registration.
     * 
     * @param   mixed   $content  The content to store.
     * 
     * @return  string  $content  The
     */
    protected function prepareContent($content)
    {
        if (is_array($content) || is_object($content))
        {
            $content = json_encode($content, JSON_PRETTY_PRINT);
        }

        return  $content;
    }

    /**
     * Returns true if the status of the response is equal to true.
     *
     * @return  bool  The verified status of the response.
     */
    public function isSuccess()
    {
        return $this->status;
    }

    /**
     * Returns true if the status of the response is equal to false.
     *
     * @return  bool  The error status of the response.
     */
    public function isError()
    {
        return !$this->status;
    }

    /**
     * Sets the status of the response.
     *
     * @param   bool  $status  The status of the response.
     *
     * @return  self  Returns this object to support chaining.
     */
    public function setStatus(bool $status)
    {
        $this->status = $status;

        return $this->triggerUpdate();
    }

    /**
     * Whether a notification should be sent.
     *
     * @return  bool  The notify status of the response.
     */
    public function isNotify()
    {
        return $this->notify;
    }

    /**
     * Sets the notify setting of the response.
     *
     * @param   bool  $notify  Whether the cron requires a notification to be sent.
     *
     * @return  self  Returns this object to support chaining.
     */
    public function setNotify(bool $notify)
    {
        $this->notify = $notify;

        return $this->triggerUpdate();
    }

    /**
     * Returns all the attached meta data.
     *
     * @return  Metadata[]
     */
    public function getMetadata()
    {
        return $this->metadata;
    }

    /**
     * Attaches new metadata to the status response object.
     *
     * @param   Metadata  $data  The extra data.
     *
     * @return  self      Returns this object to support chaining.
     */
    public function addMetadata(Metadata $data)
    {
        $this->metadata[] = $data;

        return $this->triggerUpdate();
    }

    /**
     * Returns the last update of the response.
     *
     * @return  \DateTime  The last update military date string.
     */
    public function getLastUpdate()
    {
        return $this->lastUpdate;
    }

    /**
     * Refreshes the last update time of the response.
     *
     * @return  self  Returns this object to support chaining.
     */
    protected function triggerUpdate()
    {
        $this->lastUpdate = \JFactory::getDate('now');

        return $this;
    }
}
