import { createHash } from "node:crypto";
const DAEMON_MAX_ACTIVE_SUMMARIES_DEFAULT = 4;
const DAEMON_MAX_ACTIVE_SUMMARIES_LIMIT = 32;
export function buildActiveSummarizeKey(request) {
    const textHash = request.textContent
        ? createHash("sha256").update(request.textContent).digest("hex")
        : "";
    return createHash("sha256")
        .update(JSON.stringify({
        pageUrl: request.pageUrl,
        title: request.title,
        textHash,
        truncated: request.truncated,
        modelOverride: request.modelOverride,
        lengthRaw: request.lengthRaw,
        languageRaw: request.languageRaw,
        promptOverride: request.promptOverride,
        noCache: request.noCache,
        mode: request.mode,
        maxCharacters: request.maxCharacters,
        format: request.format,
        overrides: request.overrides,
        slidesSettings: request.slidesSettings,
    }))
        .digest("hex");
}
export function resolveDaemonMaxActiveSummaries(env) {
    const raw = env.SUMMARIZE_DAEMON_MAX_ACTIVE_SUMMARIES?.trim();
    if (!raw)
        return DAEMON_MAX_ACTIVE_SUMMARIES_DEFAULT;
    const parsed = Number(raw);
    if (!Number.isFinite(parsed))
        return DAEMON_MAX_ACTIVE_SUMMARIES_DEFAULT;
    return Math.min(DAEMON_MAX_ACTIVE_SUMMARIES_LIMIT, Math.max(1, Math.floor(parsed)));
}
async function drainActiveTasks(activeTasks) {
    while (activeTasks.size > 0) {
        const tasks = [...activeTasks];
        await Promise.allSettled(tasks);
        for (const task of tasks) {
            activeTasks.delete(task);
        }
    }
}
export async function closeAfterActiveTasks({ activeTasks, timeoutMs, close, }) {
    const drainPromise = drainActiveTasks(activeTasks);
    let timer = null;
    let drained = false;
    try {
        drained = await Promise.race([
            drainPromise.then(() => true),
            new Promise((resolve) => {
                timer = setTimeout(() => resolve(false), timeoutMs);
                timer.unref?.();
            }),
        ]);
    }
    finally {
        if (timer)
            clearTimeout(timer);
    }
    if (drained) {
        close();
    }
    else {
        void drainPromise.then(close).catch(() => { });
    }
    return drained;
}
export class DaemonRuntime {
    sessions = new Map();
    refreshSessions = new Map();
    maxActiveSummaries;
    activeTasks = new Set();
    activeSummarizeRequests = new Map();
    activeSummarizeCount = 0;
    currentRefreshSessionId = null;
    constructor(options) {
        this.maxActiveSummaries = options.maxActiveSummaries;
    }
    get activeRefreshSessionId() {
        return this.currentRefreshSessionId;
    }
    registerRefreshSession(session) {
        this.refreshSessions.set(session.id, session);
        this.currentRefreshSessionId = session.id;
    }
    finishRefreshSession(sessionId) {
        if (this.currentRefreshSessionId === sessionId) {
            this.currentRefreshSessionId = null;
        }
    }
    findActiveSummarizeSession(key) {
        const sessionId = this.activeSummarizeRequests.get(key);
        const session = sessionId ? this.sessions.get(sessionId) : null;
        if (sessionId && session && !session.summaryEvents.done)
            return session;
        if (sessionId && !session) {
            this.activeSummarizeRequests.delete(key);
        }
        return null;
    }
    registerActiveSummarizeRequest(key, sessionId) {
        this.activeSummarizeRequests.set(key, sessionId);
    }
    clearActiveSummarizeRequest(key, sessionId) {
        if (this.activeSummarizeRequests.get(key) === sessionId) {
            this.activeSummarizeRequests.delete(key);
        }
    }
    reserveSummarizeSlot() {
        if (this.activeSummarizeCount >= this.maxActiveSummaries)
            return null;
        this.activeSummarizeCount += 1;
        let released = false;
        return () => {
            if (released)
                return;
            released = true;
            this.activeSummarizeCount = Math.max(0, this.activeSummarizeCount - 1);
        };
    }
    trackSummarizeTask(task, releaseSlot) {
        const tracked = task.then(() => undefined, () => undefined);
        this.activeTasks.add(tracked);
        void tracked.finally(() => {
            this.activeTasks.delete(tracked);
            releaseSlot();
        });
    }
    trackRequestTask(task) {
        this.activeTasks.add(task);
        void task.finally(() => this.activeTasks.delete(task));
    }
    closeAfterActiveTasks(options) {
        return closeAfterActiveTasks({ activeTasks: this.activeTasks, ...options });
    }
}
//# sourceMappingURL=server-runtime.js.map