<?php

declare(strict_types=1);

namespace PhpWA\Runtime;

use InvalidArgumentException;
use PhpWA\Exception\TimeoutException;

final class Deadline
{
    /** @var float */ private $at;

    private function __construct(float $at)
    {
        $this->at = $at;
    }

    public static function after(float $seconds): self
    {
        if (!is_finite($seconds) || $seconds <= 0.0) {
            throw new InvalidArgumentException('Deadline duration must be a positive finite value.');
        }
        return new self(microtime(true) + $seconds);
    }

    public static function at(float $unixMicrotime): self
    {
        if (!is_finite($unixMicrotime) || $unixMicrotime <= 0.0) {
            throw new InvalidArgumentException('Deadline timestamp must be positive and finite.');
        }
        return new self($unixMicrotime);
    }

    public function remaining(string $operation = 'operation'): float
    {
        $remaining = $this->at - microtime(true);
        if ($remaining <= 0.0) {
            throw new TimeoutException('Timed out during ' . $operation . '.');
        }
        return max(0.000001, $remaining);
    }

    public function isExpired(): bool { return microtime(true) >= $this->at; }
    public function timestamp(): float { return $this->at; }
}
