"""One heavy analysis at a time (AV-054, decision D1): the reference TMB
Journey's Explorer analysis (~30 s of one core), an ad-hoc Explorer
analysis, the 3D view's light. On a 2-vCPU server one of them must never
hold every request up: each waits at most HEAVY_ANALYSIS_WAIT_S for its turn
and otherwise answers "busy, try again" (HTTP 503) -- a running analysis
itself is not interrupted (a Python thread cannot be stopped safely)."""

from __future__ import annotations

import os
import threading
from typing import Callable, TypeVar

T = TypeVar("T")
DEFAULT_WAIT_S = 60.0


class HeavyBusy(RuntimeError):
    """The heavy-analysis slot stayed taken for the whole wait."""


class HeavyQueue:
    def __init__(self, slots: int = 1, wait_s: float | None = None):
        self._slots = threading.BoundedSemaphore(slots)
        if wait_s is None:
            try:
                wait_s = float(os.environ.get("HEAVY_ANALYSIS_WAIT_S") or DEFAULT_WAIT_S)
            except ValueError:
                wait_s = DEFAULT_WAIT_S
        self.wait_s = wait_s

    def run(self, work: Callable[[], T]) -> T:
        if not self._slots.acquire(timeout=self.wait_s):
            raise HeavyBusy("HEAVY_ANALYSIS_BUSY")
        try:
            return work()
        finally:
            self._slots.release()


BUSY_DOCUMENT = {
    "error": "HEAVY_ANALYSIS_BUSY",
    "message": "Serwer liczy teraz inną dużą analizę — spróbuj ponownie za chwilę.",
}
