<?php declare(strict_types = 1);

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

use DateTimeImmutable;
use idoit\Module\SyneticsFlows\Serialization\Discriminator;
use idoit\Module\SyneticsFlows\Validation\PositiveInteger;

/**
 * Definition of trigger
 */
#[Discriminator(
    [
        'day' => DayRepetition::class,
        'week' => WeekRepetition::class,
        'month' => MonthRepetition::class,
        'year' => YearRepetition::class,
    ]
)]
abstract class Repetition
{
    /**
     * @param int|null $period
     */
    public function __construct(
        #[PositiveInteger]
        protected ?int $period = 1,
    )
    {
    }

    /**
     * @return int
     */
    public function getPeriod(): int
    {
        return $this->period ?? 1;
    }

    /**
     * @param DateTimeImmutable $start
     * @param DateTimeImmutable $offset
     *
     * @return int
     */
    protected abstract function getIterationNumber(DateTimeImmutable $start, DateTimeImmutable $offset): int;

    /**
     * @param DateTimeImmutable $start
     * @param int $iteration
     *
     * @return array
     */
    protected abstract function getNextIterationDates(DateTimeImmutable $start, int $iteration): array;

    /**
     * @param DateTimeImmutable $date
     * @param DateTimeImmutable $offset
     *
     * @return DateTimeImmutable[]
     */
    public function getNextDate(DateTimeImmutable $date, DateTimeImmutable $offset): array
    {
        $startIteration = $this->getIterationNumber($date, $offset);

        for ($i = $startIteration; $i < $startIteration + 10; ++$i) {
            $dates = $this->getNextIterationDates($date, $i);
            $values = array_values(array_filter($dates, fn (DateTimeImmutable $current) => $date <= $current && $offset <= $current));
            if (!empty($values)) {
                return $values;
            }
        }
        return [];
    }
}
