import { dynamicTool } from "ai";
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
import { loadAgentRegistry } from "./agent-registry.js";
import {
  checkAgentPolicy,
  resolveEffectiveMutationPolicy
} from "./agent-policy.js";
import { toolRegistry } from "./tool-registry.js";
import { toSafeZodSchema } from "./schema-utils.js";
import { prepareMutation } from "./prepare-mutation.js";
class AgentPolicyError extends Error {
  constructor(code, message) {
    super(message);
    this.name = "AgentPolicyError";
    this.code = code;
  }
}
function createAiUiPartQueue() {
  const buffer = [];
  return {
    enqueue: (part) => {
      buffer.push(part);
    },
    drain: () => {
      const snapshot = buffer.slice();
      buffer.length = 0;
      return snapshot;
    },
    size: () => buffer.length
  };
}
function toPolicyAuthContext(ctx) {
  return {
    userFeatures: ctx.features,
    isSuperAdmin: ctx.isSuperAdmin
  };
}
function sanitizeToolNameForModel(name) {
  return name.replace(/\./g, "__");
}
function desanitizeToolNameForDisplay(name) {
  return name.replace(/__/g, ".");
}
function formatToolResult(result) {
  if (result === null || result === void 0) return "No result returned";
  if (typeof result === "string") return result;
  if (typeof result === "number" || typeof result === "boolean") return String(result);
  try {
    return JSON.stringify(result, null, 2);
  } catch {
    return String(result);
  }
}
function buildToolHandlerContext(ctx, container, tool) {
  return {
    tenantId: ctx.tenantId,
    organizationId: ctx.organizationId,
    userId: ctx.userId,
    container: container ?? void 0,
    userFeatures: ctx.features,
    isSuperAdmin: ctx.isSuperAdmin,
    ...tool ? { tool } : {}
  };
}
function formatPendingActionToolResult(agent, tool, pendingActionId, expiresAt) {
  return formatToolResult({
    status: "pending-confirmation",
    agentId: agent.id,
    toolName: tool.name,
    pendingActionId,
    expiresAt: expiresAt.toISOString(),
    message: `Awaiting user confirmation for mutation "${tool.name}". The action will NOT run until the user approves it.`
  });
}
function resolveIsDestructive(isDestructive, args) {
  if (typeof isDestructive === "function") {
    try {
      return isDestructive(args) === true;
    } catch {
      return true;
    }
  }
  return isDestructive === true;
}
function adaptToolToAiSdk(tool, ctx, mutation, container, effectiveMutationPolicy) {
  const safeSchema = toSafeZodSchema(tool.inputSchema);
  const handlerContext = buildToolHandlerContext(ctx, container, tool);
  return dynamicTool({
    description: tool.description,
    inputSchema: safeSchema,
    execute: async (args) => {
      const requiresApprovalNow = (() => {
        if (!mutation) return false;
        if (effectiveMutationPolicy === "confirm-required") return true;
        if (effectiveMutationPolicy === "destructive-confirm-required") {
          return resolveIsDestructive(mutation.tool.isDestructive, args);
        }
        return false;
      })();
      if (mutation && requiresApprovalNow) {
        try {
          const toolCallArgs = args && typeof args === "object" && !Array.isArray(args) ? { ...args } : {};
          const { uiPart, pendingAction } = await prepareMutation(
            {
              agent: mutation.agent,
              tool: mutation.tool,
              toolCallArgs,
              conversationId: mutation.conversationId,
              mutationPolicyOverride: mutation.mutationPolicyOverride
            },
            {
              tenantId: mutation.ctx.tenantId,
              organizationId: mutation.ctx.organizationId,
              userId: mutation.ctx.userId,
              features: mutation.ctx.features,
              isSuperAdmin: mutation.ctx.isSuperAdmin,
              container: mutation.container
            }
          );
          mutation.uiPartQueue.enqueue(uiPart);
          return formatPendingActionToolResult(
            mutation.agent,
            mutation.tool,
            pendingAction.id,
            pendingAction.expiresAt
          );
        } catch (error) {
          const message = error instanceof Error ? error.message : String(error);
          throw new Error(
            `Tool "${tool.name}" could not be prepared for confirmation: ${message}`
          );
        }
      }
      try {
        const freshContainer = await createRequestContainer();
        const freshContext = {
          ...handlerContext,
          container: freshContainer
        };
        const { executeTool } = await import("./tool-executor.js");
        const execResult = await executeTool(tool.name, args, freshContext);
        if (!execResult.success) {
          throw new Error(execResult.error || "Tool execution failed");
        }
        return formatToolResult(execResult.result);
      } catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        throw new Error(`Tool "${tool.name}" failed: ${message}`);
      }
    }
  });
}
async function resolveAiAgentTools(input) {
  await loadAgentRegistry();
  const policyAuth = toPolicyAuthContext(input.authContext);
  const mutationPolicyOverride = input.mutationPolicyOverride ?? null;
  const agentDecision = checkAgentPolicy({
    agentId: input.agentId,
    authContext: policyAuth,
    requestedExecutionMode: input.requestedExecutionMode ?? "chat",
    mutationPolicyOverride
  });
  if (!agentDecision.ok) {
    throw new AgentPolicyError(agentDecision.code, agentDecision.message);
  }
  const { agent } = agentDecision;
  const tools = {};
  const uiPartQueue = createAiUiPartQueue();
  const effectiveMutationPolicy = resolveEffectiveMutationPolicy(
    agent.mutationPolicy,
    mutationPolicyOverride,
    agent.id
  );
  const canInterceptMutations = effectiveMutationPolicy !== "read-only" && typeof input.container !== "undefined";
  for (const toolName of agent.allowedTools) {
    const toolDecision = checkAgentPolicy({
      agentId: input.agentId,
      authContext: policyAuth,
      toolName,
      mutationPolicyOverride
    });
    if (!toolDecision.ok) {
      console.warn(
        `[AI Agents] Skipping tool "${toolName}" for agent "${agent.id}": ${toolDecision.message}`
      );
      continue;
    }
    const record = toolDecision.tool ?? toolRegistry.getTool(toolName);
    if (!record) {
      console.warn(
        `[AI Agents] Tool "${toolName}" vanished from registry between policy checks; skipping.`
      );
      continue;
    }
    try {
      const mutationOptions = record.isMutation === true && canInterceptMutations && input.container ? {
        agent,
        tool: record,
        container: input.container,
        ctx: input.authContext,
        mutationPolicyOverride,
        conversationId: input.conversationId ?? null,
        uiPartQueue
      } : null;
      const modelSafeToolName = sanitizeToolNameForModel(toolName);
      tools[modelSafeToolName] = adaptToolToAiSdk(
        record,
        input.authContext,
        mutationOptions,
        input.container,
        effectiveMutationPolicy
      );
    } catch (error) {
      console.error(
        `[AI Agents] Failed to adapt tool "${toolName}" for agent "${agent.id}":`,
        error
      );
    }
  }
  return { agent, tools, uiPartQueue };
}
export {
  AgentPolicyError,
  desanitizeToolNameForDisplay,
  resolveAiAgentTools,
  sanitizeToolNameForModel
};
//# sourceMappingURL=agent-tools.js.map
