<?php

namespace CleantalkSP\SpbctWP\Scanner\OSCron\Objects;

use CleantalkSP\SpbctWP\Scanner\OSCron\View\OSCronLocale;

class OSCronTask
{
    /**
     * @var string The unique identifier for the task.
     */
    public $id;
    /**
     * @var string The whole line of the task.
     */
    public $whole_line;
    /**
     * @var string The cron pattern for task repetition.
     */
    public $status;
    /**
     * @var string The cron pattern for task repetition.
     * @psalm-suppress PossiblyUnusedProperty
     */
    public $repeats;
    /**
     * @var string The command to be executed by the cron task.
     */
    public $command;
    /**
     * @var int The line number in the cron file.
     * @psalm-suppress PossiblyUnusedProperty
     */
    public $line_number;
    /**
     * @var string The hash of the task.
     */
    public $hash;
    /**
     * @var string
     */
    public $verdict;
    /**
     * @var array List of possible statuses for the task.
     */
    private $statuses_list = array(
        'enabled',
        'disabled',
        'critical',
    );
    /**
     * @var array List of possible verdicts for the task.
     */
    private $verdict_list = array(
        'checked',
        'critical',
        'unchecked'
    );

    /**
     * Signature matches found during analysis.
     * @psalm-suppress PossiblyUnusedProperty
     * @var array
     */
    public $signature_matches = array();

    /**
     * Constructor to initialize the task with an optional item.
     *
     * @param string $item Optional item to initialize the task.
     * @throws \Exception If the item is invalid.
     */
    public function __construct($item = '')
    {
        $this->setWholeLine($item);
        $this->setID();
        $this->setHash(md5($item));
        $this->setVerdict();
    }

    /**
     * Sets a unique identifier for the task.
     */
    private function setID()
    {
        $this->id = uniqid('', true);
    }

    /**
     * Sets the whole line for the task. Means the whole line of the task in current crontab state.
     *
     * @param string $whole_line The whole line to set.
     * @return OSCronTask
     * @throws \Exception If the command is invalid.
     */
    public function setWholeLine($whole_line)
    {
        if (!is_string($whole_line)) {
            throw new \Exception(__CLASS__ . '::' . __FUNCTION__ . ' ' . OSCronLocale::getInstance()->error__invalid_arg);
        }
        $this->whole_line = $whole_line;
        return $this;
    }

    /**
     * Sets the status of the task.
     *
     * @param string $status The status to set.
     * @return OSCronTask
     * @throws \Exception If the status is invalid.
     */
    public function setStatus($status)
    {
        if (!is_string($status) || !in_array($status, $this->statuses_list)) {
            throw new \Exception(__CLASS__ . '::' . __FUNCTION__ . ' ' . OSCronLocale::getInstance()->error__invalid_arg);
        }

        $this->status = $status;
        return $this;
    }

    /**
     * Sets the command for the task.
     *
     * @param string $command The command to set.
     * @return OSCronTask
     * @throws \Exception If the command is invalid.
     */
    public function setCommand($command)
    {
        if (!is_string($command)) {
            throw new \Exception(__CLASS__ . '::' . __FUNCTION__ . ' ' . OSCronLocale::getInstance()->error__invalid_arg);
        }
        $this->command = $command;
        return $this;
    }

    /**
     * Sets the cron pattern for task repetition.
     *
     * @param string $repeats The cron pattern to set.
     * @return OSCronTask
     * @throws \Exception If the pattern is invalid.
     */
    public function setRepeatsPattern($repeats)
    {
        if (!is_string($repeats)) {
            throw new \Exception(__CLASS__ . '::' . __FUNCTION__ . ' ' . OSCronLocale::getInstance()->error__invalid_arg);
        }
        $this->repeats = $repeats;
        return $this;
    }

    /**
     * Sets the line number in the cron file.
     *
     * @param int $line_number The line number to set.
     * @return OSCronTask
     * @throws \Exception If the line number is invalid.
     */
    public function setLineNumber($line_number)
    {
        if (!is_int($line_number)) {
            throw new \Exception(__CLASS__ . '::' . __FUNCTION__ . ' ' . OSCronLocale::getInstance()->error__invalid_arg);
        }
        $this->line_number = $line_number;
        return $this;
    }

    /**
     * Sets the hash for the task.
     *
     * @param string $hash The hash to set.
     */
    private function setHash($hash)
    {
        if (!is_string($hash)) {
            $hash = '';
        }
        $this->hash = $hash;
    }

    /**
     * Sets the vulnerability verdict for the task.
     *
     * @param string $verdict The vulnerability to set.
     */
    public function setVerdict($verdict = 'unchecked')
    {
        if ( !is_string($verdict) || !in_array($verdict, $this->verdict_list)) {
            $verdict = 'unchecked';
        }
        $this->verdict = $verdict;
    }

    /**
     * Validates the task properties.
     *
     * @return OSCronTask
     * @throws \Exception If any property is missing.
     */
    public function validate()
    {
        foreach (get_object_vars($this) as $property => $value) {
            if (is_null($value)) {
                throw new \Exception(__CLASS__ . '::' . __FUNCTION__ . ' - ' . $property . ' ' . OSCronLocale::getInstance()->error__missing_property);
            }
        }
        return $this;
    }


    /**
     * Returns the task properties as an array.
     *
     * @return array The task properties.
     */
    public function getArray()
    {
        $result = array();
        foreach (get_object_vars($this) as $property => $value) {
            $result[$property] = $value;
        }
        unset($result['statuses_list']);
        return $result;
    }
}
