<?php
/**
 * How a refund deadline stands right now.
 *
 * @package SkyServers\Retragere
 */

declare(strict_types=1);

namespace SkyServers\Retragere\Core;

use DateTimeImmutable;

/**
 * Settlement decides everything: once the money is back, the only question left
 * is whether it made the deadline. Until then the clock keeps running, and the
 * shop deserves warning before it runs out rather than after.
 */
final class RefundStatus
{
    public const ON_TIME      = 'on_time';
    public const DUE_SOON     = 'due_soon';
    public const OVERDUE      = 'overdue';
    public const SETTLED      = 'settled';
    public const SETTLED_LATE = 'settled_late';

    /** @var int */
    private $warnDays;

    public function __construct(int $warnDays = 3)
    {
        $this->warnDays = max(1, $warnDays);
    }

    public function classify(
        DateTimeImmutable $dueAt,
        DateTimeImmutable $now,
        ?DateTimeImmutable $settledAt = null
    ): string {
        if (null !== $settledAt) {
            return $settledAt > $dueAt ? self::SETTLED_LATE : self::SETTLED;
        }

        if ($now > $dueAt) {
            return self::OVERDUE;
        }

        if ($this->daysLeft($dueAt, $now) <= $this->warnDays) {
            return self::DUE_SOON;
        }

        return self::ON_TIME;
    }

    /**
     * Whole calendar days between now and the deadline. Negative once passed.
     */
    public function daysLeft(DateTimeImmutable $dueAt, DateTimeImmutable $now): int
    {
        $from = $now->setTime(0, 0, 0);
        $to   = $dueAt->setTime(0, 0, 0);
        $diff = $from->diff($to);

        return (int) $diff->days * (1 === $diff->invert ? -1 : 1);
    }
}
