<?php

namespace App\Modules\HtlCampSchedule\Domain;

use App\Modules\Shared\Domain\DateTimeEnd;
use App\Modules\Shared\Domain\DateTimeStart;

class Calendar
{
    /** @var array<CalendarDay> $days */
    private array $days = [];

    /**
     * Object that contains the calendar as a list of CalendarDay objects.
     *
     * @param DateTimeStart $dateStart Initial date of the calendar.
     * @param DateTimeEnd $dateEnd Last date of the calendar.
     */
    public function __construct(
        private DateTimeStart $dateStart,
        private DateTimeEnd $dateEnd,
    ) {
    }

    /**
     * Generate the calendar.
     *
     * @param callable $generateDay Callback function that will be called for each day of the calendar.
     */
    public function generate(callable $generateDay)
    {
        $dateStart = strtotime(date('Y-m-d', strtotime($this->dateStart)));
        $dateEnd = strtotime(date('Y-m-d', strtotime($this->dateEnd)));
        $secondsInADay = 86400;
        $array = $this->createDateArray($dateStart, $dateEnd, $secondsInADay);
        $this->days = $this->createDayList($array, $generateDay);
    }

    /**
     * Get the list of CalendarDay as objects.
     *
     * @return array The list of CalendarDay as objects.
     */
    public function getDaysAsArray()
    {
        $arr = [];
        foreach ($this->days as $day) {
            $arr[] = $day->toObject();
        }
        return $arr;
    }

    /**
     * Create an array of date strings based on the given initial date and sumatory.
     *
     * @param int $initial Initial date of the array.
     * @param int $to Last date of the array.
     * @param int $sumatory Sumatory between date strings.
     * @return array The array of date strings.
     */
    private function createDateArray(int $initial, int $to, int $sumatory)
    {
        $arr = [];
        while ($initial <= $to) {
            $arr[] = date('Y-m-d', $initial);
            $initial += $sumatory;
        }
        return $arr;
    }

    /**
     * Create the list of CalendarDay objects
     * @param array $array The array of date strings.
     * @param callable $generateDay Callback function that will be called for each day of the calendar.
     * @return array The list of CalendarDay objects.
     */
    private function createDayList(array $array, callable $generateDay)
    {
        return array_map(
            fn ($date) => new CalendarDay($date, $generateDay($date)),
            $array
        );
    }
}
