<?php
namespace EasyChat\Library\Messenger;










final class MaxPollingRunBudget {

    private const EXTRA_RUNTIME_SECONDS = 10;
    private const MIN_TOTAL_SECONDS = 15;
    private const MAX_TOTAL_SECONDS = 50;
    private const BACKLOG_SECONDS = 10;
    private const IDENTITY_REPAIR_SECONDS = 3;
    private const LISTENER_RESERVE_SECONDS = 3;
    private const FINALIZE_RESERVE_SECONDS = 2;

    private $requested_listener_seconds;
    private $started_at;
    private $hard_deadline;
    private $backlog_deadline;
    private $identity_repair_deadline;

    public function __construct(int $requested_listener_seconds, ?float $started_at = null) {
        $this->requested_listener_seconds = max(1, min(45, $requested_listener_seconds));
        $this->started_at = $started_at !== null ? $started_at : microtime(true);

        $total_seconds = max(
            self::MIN_TOTAL_SECONDS,
            min(self::MAX_TOTAL_SECONDS, $this->requested_listener_seconds + self::EXTRA_RUNTIME_SECONDS)
        );
        $this->hard_deadline = $this->started_at + $total_seconds;
        $this->backlog_deadline = min(
            $this->started_at + self::BACKLOG_SECONDS,
            $this->hard_deadline - self::LISTENER_RESERVE_SECONDS - self::FINALIZE_RESERVE_SECONDS
        );
         
        $this->identity_repair_deadline = min(
            $this->started_at + self::IDENTITY_REPAIR_SECONDS,
            $this->backlog_deadline
        );
    }

    public function canProcessIdentityRepair(?float $now = null): bool {
        return ($now !== null ? $now : microtime(true)) < $this->identity_repair_deadline;
    }

    public function canProcessBacklog(?float $now = null): bool {
        return ($now !== null ? $now : microtime(true)) < $this->backlog_deadline;
    }

    public function remainingListenerSeconds(?float $now = null): int {
        $now = $now !== null ? $now : microtime(true);
        $available = (int)floor($this->hard_deadline - $now - self::FINALIZE_RESERVE_SECONDS);
        if ($available <= 0) {
            return 0;
        }

        return min($this->requested_listener_seconds, $available);
    }

    public function elapsedMilliseconds(?float $now = null): int {
        $now = $now !== null ? $now : microtime(true);
        return max(0, (int)round(($now - $this->started_at) * 1000));
    }

    public function totalLimitSeconds(): int {
        return (int)round($this->hard_deadline - $this->started_at);
    }

    public function backlogLimitSeconds(): int {
        return (int)round($this->backlog_deadline - $this->started_at);
    }
}
