export type ClientToolResult =
  | { ok: true; result: unknown }
  | { ok: false; error: string };

type PendingClientTool = {
  userId: string;
  createdAt: number;
  timeoutId: ReturnType<typeof setTimeout>;
  resolve: (v: ClientToolResult) => void;
};

const nowMs = () => Date.now();

// 说明：这是一个“进程内”桥接（仅用于本地/单实例）。
// 若未来部署到多实例/Serverless，需要替换为 Redis / Realtime / WebSocket 等可共享通道。
const pendingCalls: Map<string, PendingClientTool> =
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  ((globalThis as any).__mnote_pending_client_tool_calls as Map<string, PendingClientTool> | undefined) ??
  new Map<string, PendingClientTool>();

// eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any).__mnote_pending_client_tool_calls = pendingCalls;

export const buildClientToolKey = (requestId: string, callId: string) =>
  `${String(requestId)}:${String(callId)}`;

export const registerClientToolCall = ({
  key,
  userId,
  timeoutMs = 60_000,
}: {
  key: string;
  userId: string;
  timeoutMs?: number;
}): Promise<ClientToolResult> => {
  const existing = pendingCalls.get(key);
  if (existing) {
    // 同一个 call 只能注册一次，避免重复等待导致难以清理。
    return Promise.resolve({ ok: false, error: "客户端工具调用已注册（重复注册）" });
  }

  return new Promise<ClientToolResult>((resolve) => {
    const timeoutId = setTimeout(() => {
      pendingCalls.delete(key);
      resolve({ ok: false, error: "客户端工具执行超时（未收到回调）" });
    }, Math.max(1_000, timeoutMs));

    pendingCalls.set(key, {
      userId,
      createdAt: nowMs(),
      timeoutId,
      resolve,
    });
  });
};

export const resolveClientToolCall = ({
  key,
  userId,
  result,
}: {
  key: string;
  userId: string;
  result: ClientToolResult;
}): { ok: true } | { ok: false; error: string } => {
  const pending = pendingCalls.get(key);
  if (!pending) return { ok: false, error: "未找到待回调的客户端工具调用（可能已超时）" };
  if (pending.userId !== userId) return { ok: false, error: "无权限回调该工具调用" };

  clearTimeout(pending.timeoutId);
  pendingCalls.delete(key);
  pending.resolve(result);
  return { ok: true };
};
