<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\MainBundle\Service\RollingDate;

use Doctrine\Instantiator\Exception\UnexpectedValueException;

class RollingDate
{
    final public const ALL_T = [
        self::T_YEAR_PREVIOUS_START,
        self::T_QUARTER_PREVIOUS_START,
        self::T_MONTH_PREVIOUS_START,
        self::T_WEEK_PREVIOUS_START,
        self::T_YEAR_CURRENT_START,
        self::T_QUARTER_CURRENT_START,
        self::T_MONTH_CURRENT_START,
        self::T_WEEK_CURRENT_START,
        self::T_TODAY,
        self::T_WEEK_NEXT_START,
        self::T_MONTH_NEXT_START,
        self::T_QUARTER_NEXT_START,
        self::T_YEAR_NEXT_START,
        self::T_FIXED_DATE,
    ];

    /**
     * A given fixed date.
     */
    final public const T_FIXED_DATE = 'fixed_date';

    final public const T_MONTH_CURRENT_START = 'month_current_start';

    final public const T_MONTH_NEXT_START = 'month_next_start';

    final public const T_MONTH_PREVIOUS_START = 'month_previous_start';

    final public const T_QUARTER_CURRENT_START = 'quarter_current_start';

    final public const T_QUARTER_NEXT_START = 'quarter_next_start';

    final public const T_QUARTER_PREVIOUS_START = 'quarter_previous_start';

    final public const T_TODAY = 'today';

    final public const T_WEEK_CURRENT_START = 'week_current_start';

    final public const T_WEEK_NEXT_START = 'week_next_start';

    final public const T_WEEK_PREVIOUS_START = 'week_previous_start';

    final public const T_YEAR_CURRENT_START = 'year_current_start';

    final public const T_YEAR_NEXT_START = 'year_next_start';

    final public const T_YEAR_PREVIOUS_START = 'year_previous_start';

    private const NORMALIZATION_FORMAT = 'Y-m-d-H:i:s.u e';

    /**
     * @param string|self::T_*        $roll
     * @param \DateTimeImmutable|null $fixedDate Only to insert if $roll equals @see{self::T_FIXED_DATE}
     */
    public function __construct(
        private readonly string $roll,
        private readonly ?\DateTimeImmutable $fixedDate = null,
        private readonly ?\DateTimeImmutable $pivotDate = null,
    ) {}

    public function getFixedDate(): ?\DateTimeImmutable
    {
        return $this->fixedDate;
    }

    public function getPivotDate(): ?\DateTimeImmutable
    {
        return $this->pivotDate;
    }

    public function getRoll(): string
    {
        return $this->roll;
    }

    public function normalize(): array
    {
        return [
            'roll' => $this->getRoll(),
            'fixed_date' => $this->getFixedDate()?->format(self::NORMALIZATION_FORMAT),
            'pivot_date' => $this->getPivotDate()?->format(self::NORMALIZATION_FORMAT),
            'v' => 1,
        ];
    }

    public static function fromNormalized(?array $data): ?self
    {
        if (null === $data) {
            return null;
        }

        if (1 === $data['v']) {
            return new self(
                $data['roll'],
                null !== $data['fixed_date'] ? \DateTimeImmutable::createFromFormat(self::NORMALIZATION_FORMAT, (string) $data['fixed_date']) : null,
                null !== $data['pivot_date'] ? \DateTimeImmutable::createFromFormat(self::NORMALIZATION_FORMAT, (string) $data['pivot_date']) : null,
            );
        }

        throw new UnexpectedValueException('Format of the rolling date unknow, no version information');
    }
}
