<?php declare(strict_types = 1);

namespace idoit\Module\SyneticsFlows\Automation\Trigger\TriggerType;

use DateTimeImmutable;
use idoit\Module\SyneticsFlows\Automation\Trigger\TriggerType\ExecutionEnd\DateExecutionEnd;
use idoit\Module\SyneticsFlows\Automation\Trigger\TriggerType\ExecutionEnd\ExecutionEnd;
use idoit\Module\SyneticsFlows\Automation\Trigger\TriggerType\Repetition\Repetition;
use idoit\Module\SyneticsFlows\Validation\Required;
use idoit\Module\SyneticsFlows\Validation\ValidationCallback;
use idoit\Module\SyneticsFlows\Validation\ValidationMessage;
use Throwable;

class ScheduleTriggerType extends TriggerType
{
    public function __construct(
        #[Required]
        private ?string $startDate = null,
        private ?ExecutionEnd $end = null,
        #[Required]
        private ?string $time = null,
        private ?Repetition $repetition = null,
    )
    {
    }

    #[ValidationCallback]
    public function validate(array $path): array
    {
        $results = [];
        if ($this->startDate
            && $this->end instanceof DateExecutionEnd
            && $this->end->getValue()
            && $this->startDate > $this->end->getValue()
        ) {
            $results[] = new ValidationMessage([...$path, 'startDate'], 'LC__MODULE__SYNETICS_FLOWS__START_BEFORE_END_DATE');
            $results[] = new ValidationMessage([...$path, 'end', 'value'], 'LC__MODULE__SYNETICS_FLOWS__END_AFTER_START_DATE');
        }

        return $results;
    }

    public function getStartDate(): ?string
    {
        return $this->startDate;
    }

    public function getTime(): ?string
    {
        return $this->time;
    }

    public function getRepetition(): ?Repetition
    {
        return $this->repetition;
    }

    public function getEnd(): ?ExecutionEnd
    {
        return $this->end;
    }

    /**
     * @return DateTimeImmutable|null
     */
    private function getStartDateTime(): ?DateTimeImmutable
    {
        if ($this->time === null || $this->startDate === null) {
            return null;
        }

        [$hour, $minutes] = explode(':', $this->time);

        if (!is_numeric($hour) || !is_numeric($minutes)) {
            return null;
        }

        try {
            $dt = new DateTimeImmutable($this->startDate);
            return $dt->setTime((int)$hour, (int)$minutes);
        } catch (Throwable) {
            return null;
        }
    }

    /**
     * @return DateTimeImmutable|null
     */
    public function getNextStartDate(): ?DateTimeImmutable
    {
        $now = new DateTimeImmutable("now");
        if ($this->repetition === null) {
            if ($now >= $this->getStartDateTime()) {
                return null;
            }
            return $this->getStartDateTime();
        }

        $dates = $this->getRepetition()?->getNextDate(
            $this->getStartDateTime(),
            $now
        );

        if (empty($dates)) {
            return null;
        }
        return $dates[0];
    }
}
