import {
  init_cjs_shims
} from "./chunk-7GH3YGSC.js";

// src/designer/commandQueue.ts
init_cjs_shims();
import { randomUUID } from "node:crypto";

// ../../libs/designer-mcp-protocol/index.ts
init_cjs_shims();
var DESIGNER_BRIDGE_VERSION = 5;
var DESIGNER_POLL_TIMEOUT_MS = 25e3;
var DESIGNER_COMMAND_TIMEOUT_MS = 3e4;

// src/designer/commandQueue.ts
var DEFAULT_COMMAND_TIMEOUT_MS = DESIGNER_COMMAND_TIMEOUT_MS;
var DEFAULT_POLL_TIMEOUT_MS = DESIGNER_POLL_TIMEOUT_MS;
var REDELIVERY_GRACE_MS = 5e3;
var createCommandQueue = () => {
  const pending = /* @__PURE__ */ new Map();
  const waiters = [];
  let dashboardLastSeenMs = 0;
  let closed = false;
  const markDashboardSeen = () => {
    dashboardLastSeenMs = Date.now();
  };
  const isRedeliverable = (entry, now) => entry.deliveredAtMs === void 0 || now - entry.deliveredAtMs >= REDELIVERY_GRACE_MS;
  const takeDeliverable = (now) => {
    const batch = [];
    pending.forEach((entry) => {
      if (isRedeliverable(entry, now)) {
        entry.deliveredAtMs = now;
        batch.push(entry.command);
      }
    });
    return batch;
  };
  const nextRedeliveryDelay = (now) => {
    let soonest;
    pending.forEach((entry) => {
      if (entry.deliveredAtMs === void 0)
        return;
      const readyIn = entry.deliveredAtMs + REDELIVERY_GRACE_MS - now;
      if (readyIn > 0 && (soonest === void 0 || readyIn < soonest)) {
        soonest = readyIn;
      }
    });
    return soonest;
  };
  const failPending = (id, error) => {
    const entry = pending.get(id);
    if (!entry) {
      return;
    }
    clearTimeout(entry.timer);
    pending.delete(id);
    entry.resolve({ id, ok: false, error });
  };
  const deliverPendingToWaiter = () => {
    if (waiters.length === 0) {
      return;
    }
    const batch = takeDeliverable(Date.now());
    if (batch.length === 0) {
      return;
    }
    const waiter = waiters.shift();
    if (!waiter) {
      return;
    }
    clearTimeout(waiter.timer);
    waiter.resolve(batch);
  };
  const enqueue = (name, args, timeoutMs = DEFAULT_COMMAND_TIMEOUT_MS) => new Promise((resolve) => {
    if (closed) {
      const id = randomUUID();
      resolve({
        id,
        ok: false,
        error: "Designer MCP server shutting down"
      });
      return;
    }
    const command = {
      id: randomUUID(),
      name,
      args,
      issuedAtMs: Date.now()
    };
    const timer = setTimeout(() => {
      failPending(
        command.id,
        "Dashboard did not respond in time. Is the schema designer open?"
      );
    }, timeoutMs);
    timer.unref?.();
    pending.set(command.id, { command, resolve, timer });
    deliverPendingToWaiter();
  });
  const drainForPoll = (timeoutMs = DEFAULT_POLL_TIMEOUT_MS) => new Promise((resolve) => {
    markDashboardSeen();
    const batch = takeDeliverable(Date.now());
    if (batch.length > 0) {
      resolve(batch);
      return;
    }
    const redeliveryDelay = nextRedeliveryDelay(Date.now());
    const waitMs = redeliveryDelay === void 0 ? timeoutMs : Math.min(timeoutMs, redeliveryDelay);
    const timer = setTimeout(() => {
      const idx = waiters.indexOf(waiter);
      if (idx !== -1) {
        waiters.splice(idx, 1);
      }
      resolve(takeDeliverable(Date.now()));
    }, waitMs);
    timer.unref?.();
    const waiter = { resolve, timer };
    waiters.push(waiter);
  });
  const resolveCommand = (response) => {
    const entry = pending.get(response.id);
    if (!entry) {
      return false;
    }
    clearTimeout(entry.timer);
    pending.delete(response.id);
    entry.resolve(response);
    return true;
  };
  const getDashboardLastSeenMs = () => dashboardLastSeenMs;
  const isDashboardConnected = (staleThresholdMs = DEFAULT_COMMAND_TIMEOUT_MS) => {
    if (dashboardLastSeenMs === 0)
      return false;
    return Date.now() - dashboardLastSeenMs < staleThresholdMs;
  };
  const shutdown = () => {
    closed = true;
    pending.forEach((entry, id) => {
      clearTimeout(entry.timer);
      entry.resolve({
        id,
        ok: false,
        error: "Designer MCP server shutting down"
      });
    });
    pending.clear();
    waiters.forEach((waiter) => {
      clearTimeout(waiter.timer);
      waiter.resolve([]);
    });
    waiters.length = 0;
  };
  return {
    enqueue,
    drainForPoll,
    resolveCommand,
    markDashboardSeen,
    getDashboardLastSeenMs,
    isDashboardConnected,
    shutdown
  };
};

export {
  DESIGNER_BRIDGE_VERSION,
  DESIGNER_POLL_TIMEOUT_MS,
  createCommandQueue
};
