<?php

namespace Velis\Bpm\CronJob;

use Velis\CronJob;
use Velis\CronParameter;
use Velis\Notification;
use Velis\Notification\Queue;
use Velis\Mutex\Exception as MutexException;
use Velis\Output;
use Exception;

/**
 * Notification queue model
 *
 * Klasa crona do wysyłania kolejkowanych maili
 *
 * @author Robert Jamróz <robert.jamroz@velis.pl>
 * @author Olek Procki <olo@velis.pl>
 */
class NotificationQueue extends CronJob
{
    /**
     * Send scheduled messages
     * @var string
     */
    const MODE_SEND = 'send';


    /**
     * Clean sent messages' attachments
     * @var string
     */
    const MODE_CLEAR = 'clear';

    /**
     * Sent items count
     * @var int
     */
    protected $_itemsSent = 0;


    /**
     * Cleaned items count
     * @var int
     */
    protected $_itemsCleaned = 0;


    /**
     * Notification queue instance
     * @var \Velis\Notification\Queue
     */
    protected $_queue;



    /**
     * Constructor
     * @param array|ArrayObject $params
     */
    public function __construct($params = null)
    {
        parent::__construct($params);
        $this->_queue = new Queue();
    }


    /**
     * Uruchomienie crona produkcyjnie
     *
     * @return \Velis\Bpm\CronJob\NotificationQueue
     */
    protected function _run()
    {
        if ($this->getParameterValue('mode') == self::MODE_SEND) {
            $this->_itemsSent = $this->_queue->sendScheduled(Notification::QUEUE_CRON);
        } elseif ($this->getParameterValue('mode') == self::MODE_CLEAR) {
            $this->_itemsCleaned = $this->_queue->clearSentAttachments();
        }

        return $this;
    }


    /**
     * Info do loga|konsoli
     *
     * @return string
     */
    protected function _getMsg()
    {
        if ($this->getParameterValue('mode') == self::MODE_SEND) {
            $msg .= 'Udanych prób: ' . $this->_itemsSent;

            if ($this->_queue->hasErrors()) {
                $msg .= "\n" . 'Nieudanych prób: ' . $this->_queue->getErrorCount() . "\n\n";
                $msg .= "ERRORS: \t" . implode("\n", $this->_queue->getErrors());
            }
        } elseif ($this->getParameterValue('mode') == self::MODE_CLEAR) {
            $msg .= 'Usunięto: ' . $this->_itemsCleaned;
        }

        $msg = Output::convertEncoding($msg);

        return $msg;
    }


    /**
     * Metoda do testowego uruchomiernia krona
     *
     * @return string podusmowanie testowego wykonania metody
     */
    public function test()
    {
        $this->_queue->setTestMode();
        if ($this->getParameterValue('mode') == self::MODE_SEND) {
            $this->_itemsSent = $this->_queue->sendScheduled(Notification::QUEUE_CRON);
        } elseif ($this->getParameterValue('mode') == self::MODE_CLEAR) {
            $this->_itemsCleaned = $this->_queue->clearSentAttachments();
        }

        return $this->_getMsg();
    }


    /**
     * Executes cron job
     */
    public function run()
    {
        try {
            $this->_initMutex();
            $this->_run();

            $this->_log(self::STATUS_SUCCESS, $this->_getMsg());
        } catch (MutexException $me) {
            $this->_log(self::STATUS_WARNING, (string) $me);
        } catch (Exception $e) {
            $this->_log(self::STATUS_FAILED, (string) $e);
        }
    }

    /**
     * Method for adding info about additional cron parameters
     * @return void
     */
    public function configure()
    {
        $this->registerParameter(
            'mode',
            new CronParameter('mode', true, CronJob::TYPE_ENUM, [self::MODE_SEND, self::MODE_CLEAR])
        );
    }

    /**
     * Get cron description
     * @return string
     */
    public function getDescription(): string
    {
        return <<<EOT
        The job can be used to send messages from the notification queue.
        Depending on the 'mode' parameter it can also clear the attachments of messages that were already sent
        EOT;
    }
}
