import {
  jsonOk,
  routeWrap
} from "./chunk-QSHK4MUE.js";
import {
  init_ids,
  newId
} from "./chunk-F4WUVOLE.js";
import {
  getDb,
  init_client
} from "./chunk-TLEKKGH7.js";
import {
  badRequest,
  notFound
} from "./chunk-EZYKRG4W.js";

// src/handlers/google-compat/interactions.ts
import { z } from "zod";
init_client();
init_ids();
function ensureTable() {
  const db = getDb();
  db.exec(`
    CREATE TABLE IF NOT EXISTS google_interactions (
      id TEXT PRIMARY KEY,
      session_id TEXT NOT NULL,
      seq INTEGER NOT NULL DEFAULT 1,
      status TEXT NOT NULL DEFAULT 'completed',
      environment_id TEXT,
      created_at TEXT NOT NULL
    )
  `);
}
var CreateSchema = z.object({
  model: z.string().optional(),
  agent: z.string().optional(),
  input: z.union([z.string(), z.array(z.unknown())]),
  system_instruction: z.string().optional(),
  tools: z.array(z.unknown()).optional(),
  generation_config: z.record(z.unknown()).optional(),
  previous_interaction_id: z.string().optional(),
  environment: z.union([z.string(), z.object({ type: z.string() }).passthrough()]).optional(),
  stream: z.boolean().optional()
});
function handleCreateInteraction(request) {
  return routeWrap(request, async ({ auth }) => {
    ensureTable();
    const body = await request.json().catch(() => null);
    const parsed = CreateSchema.safeParse(body);
    if (!parsed.success) {
      throw badRequest(`invalid body: ${parsed.error.issues.map((i) => i.message).join("; ")}`);
    }
    const data = parsed.data;
    if (!data.model && !data.agent) {
      throw badRequest("either 'model' or 'agent' is required");
    }
    const inputText = typeof data.input === "string" ? data.input : JSON.stringify(data.input);
    const { handleCreateAgent, handleListAgents } = await import("./handlers/anthropic-compat/agents.js");
    const { handleCreateSession } = await import("./handlers/anthropic-compat/sessions.js");
    const { handlePostEvents } = await import("./handlers/anthropic-compat/events.js");
    let agentId;
    let environmentId;
    if (data.previous_interaction_id) {
      const db2 = getDb();
      const prev = db2.prepare(
        `SELECT session_id, environment_id FROM google_interactions WHERE id = ?`
      ).get(data.previous_interaction_id);
      if (!prev) throw notFound(`interaction not found: ${data.previous_interaction_id}`);
      agentId = "";
      environmentId = prev.environment_id ?? void 0;
      const sessionId2 = prev.session_id;
      const { listEvents: listEventsForSeq } = await import("./db/events.js");
      const lastEvents = listEventsForSeq(sessionId2, { limit: 1, order: "desc" });
      const afterSeq = lastEvents.length > 0 ? lastEvents[0].seq : 0;
      const functionResultEvents = buildFunctionResultEvents(data.input);
      const eventsReq2 = new Request(request.url.replace(/\/google\/v1beta\/interactions.*/, `/v1/sessions/${sessionId2}/events`), {
        method: "POST",
        headers: request.headers,
        body: JSON.stringify({
          events: functionResultEvents.length > 0 ? functionResultEvents : [{ type: "user.message", content: [{ type: "text", text: inputText }] }]
        })
      });
      const eventsRes2 = await handlePostEvents(eventsReq2, sessionId2);
      if (!eventsRes2.ok) {
        const err = await eventsRes2.json().catch(() => ({}));
        throw badRequest(err.error?.message || `failed to send message: ${eventsRes2.status}`);
      }
      const result2 = await waitForCompletion(sessionId2, afterSeq);
      const interactionId2 = `int_${newId("sesn").slice(5)}`;
      const prevSeq = db2.prepare(
        `SELECT MAX(seq) as maxSeq FROM google_interactions WHERE session_id = ?`
      ).get(sessionId2);
      const seq = (prevSeq?.maxSeq ?? 0) + 1;
      db2.prepare(
        `INSERT INTO google_interactions (id, session_id, seq, status, environment_id, created_at) VALUES (?, ?, ?, ?, ?, ?)`
      ).run(interactionId2, sessionId2, seq, result2.status, environmentId ?? null, (/* @__PURE__ */ new Date()).toISOString());
      return jsonOk(buildResponse(interactionId2, result2, environmentId));
    }
    const modelId = data.model || "gemini-2.5-flash";
    const agentName = data.agent || `auto-${modelId.replace(/[^a-z0-9-]/g, "-")}`;
    const listReq = new Request(request.url.replace(/\/google\/v1beta\/interactions.*/, `/v1/agents?limit=1000`), {
      headers: request.headers
    });
    const listRes = await handleListAgents(listReq);
    const listBody = await listRes.json();
    const { listVaults } = await import("./db/vaults.js");
    const { tenantFilter: getTenantFilter } = await import("./auth/scope.js");
    const allVaults = listVaults({ tenantFilter: getTenantFilter(auth) }).filter((v) => !v.archived_at);
    let existing;
    if (data.agent) {
      existing = listBody.data?.find((a) => a.name === agentName);
    } else {
      const modelMatches = listBody.data?.filter((a) => a.model?.id === modelId) ?? [];
      const withVaults = modelMatches.filter(
        (a) => allVaults.some((v) => v.agent_id === a.id || !v.agent_id)
      );
      existing = modelMatches.find((a) => allVaults.some((v) => v.agent_id === a.id)) ?? withVaults[0] ?? modelMatches[0];
    }
    if (existing) {
      agentId = existing.id;
    } else {
      const createReq = new Request(request.url.replace(/\/google\/v1beta\/interactions.*/, `/v1/agents`), {
        method: "POST",
        headers: request.headers,
        body: JSON.stringify({
          name: agentName,
          model: { id: modelId },
          system: data.system_instruction ?? null
        })
      });
      const createRes = await handleCreateAgent(createReq);
      if (!createRes.ok) {
        const err = await createRes.json().catch(() => ({}));
        throw badRequest(err.error?.message || `failed to create agent: ${createRes.status}`);
      }
      const created = await createRes.json();
      agentId = created.id;
    }
    const { listEnvironments } = await import("./db/environments.js");
    const envs = listEnvironments({ includeArchived: false, limit: 10 });
    const readyEnv = envs.find((e) => e.state === "ready");
    if (readyEnv) {
      environmentId = readyEnv.id;
    } else {
      const { handleCreateEnvironment } = await import("./handlers/anthropic-compat/environments.js");
      const envReq = new Request(request.url.replace(/\/google\/v1beta\/interactions.*/, `/v1/environments`), {
        method: "POST",
        headers: request.headers,
        body: JSON.stringify({ name: `google-compat-${Date.now()}` })
      });
      const envRes = await handleCreateEnvironment(envReq);
      if (envRes.ok) {
        const envBody = await envRes.json();
        environmentId = envBody.id;
      }
    }
    if (!environmentId) throw badRequest("no environment available");
    const vaultIds = allVaults.filter((v) => v.agent_id === agentId || !v.agent_id).map((v) => v.id);
    const sessReq = new Request(request.url.replace(/\/google\/v1beta\/interactions.*/, `/v1/sessions`), {
      method: "POST",
      headers: request.headers,
      body: JSON.stringify({
        agent: agentId,
        environment_id: environmentId,
        ...vaultIds.length > 0 ? { vault_ids: vaultIds } : {}
      })
    });
    const sessRes = await handleCreateSession(sessReq);
    if (!sessRes.ok) {
      const err = await sessRes.json().catch(() => ({}));
      throw badRequest(err.error?.message || `failed to create session: ${sessRes.status}`);
    }
    const sessBody = await sessRes.json();
    const sessionId = sessBody.id;
    const eventsReq = new Request(request.url.replace(/\/google\/v1beta\/interactions.*/, `/v1/sessions/${sessionId}/events`), {
      method: "POST",
      headers: request.headers,
      body: JSON.stringify({
        events: [{ type: "user.message", content: [{ type: "text", text: inputText }] }]
      })
    });
    const eventsRes = await handlePostEvents(eventsReq, sessionId);
    if (!eventsRes.ok) {
      const err = await eventsRes.json().catch(() => ({}));
      throw badRequest(err.error?.message || `failed to send message: ${eventsRes.status}`);
    }
    const result = await waitForCompletion(sessionId);
    const interactionId = `int_${newId("sesn").slice(5)}`;
    const db = getDb();
    db.prepare(
      `INSERT INTO google_interactions (id, session_id, seq, status, environment_id, created_at) VALUES (?, ?, ?, ?, ?, ?)`
    ).run(interactionId, sessionId, 1, result.status, environmentId ?? null, (/* @__PURE__ */ new Date()).toISOString());
    return jsonOk(buildResponse(interactionId, result, environmentId));
  });
}
function handleGetInteraction(request, id) {
  return routeWrap(request, async () => {
    ensureTable();
    const db = getDb();
    const row = db.prepare(
      `SELECT id, session_id, seq, status, environment_id, created_at FROM google_interactions WHERE id = ?`
    ).get(id);
    if (!row) throw notFound(`interaction not found: ${id}`);
    const { listEvents } = await import("./db/events.js");
    const { rowToManagedEvent } = await import("./db/events.js");
    const eventRows = listEvents(row.session_id, { limit: 500, order: "asc" });
    const steps = [];
    let inputTokens = 0;
    let outputTokens = 0;
    for (const eventRow of eventRows) {
      const event = rowToManagedEvent(eventRow);
      if (event.type === "agent.message") {
        const content = event.content;
        const text = content?.filter((c) => c.type === "text").map((c) => c.text).join("") ?? "";
        if (text) {
          steps.push({ type: "model_output", content: [{ type: "text", text }] });
        }
      } else if (event.type === "agent.tool_use") {
        steps.push({
          type: "function_call",
          id: event.tool_use_id ?? "",
          name: event.name ?? "",
          arguments: event.input ?? {}
        });
      } else if (event.type === "agent.tool_result") {
        steps.push({
          type: "code_execution_result",
          call_id: event.tool_use_id ?? "",
          result: JSON.stringify(event.content ?? "")
        });
      } else if (event.type === "agent.custom_tool_use") {
        steps.push({
          type: "function_call",
          id: event.tool_use_id ?? "",
          name: event.name ?? "",
          arguments: event.input ?? {}
        });
      } else if (event.type === "span.model_request_end") {
        const mu = event.model_usage;
        inputTokens += mu?.input_tokens ?? 0;
        outputTokens += mu?.output_tokens ?? 0;
      }
    }
    const response = {
      id: row.id,
      created: row.created_at,
      updated: row.created_at,
      status: row.status,
      steps,
      usage: { total_input_tokens: inputTokens, total_output_tokens: outputTokens, total_tokens: inputTokens + outputTokens },
      environment_id: row.environment_id ?? void 0
    };
    return jsonOk(response);
  });
}
function handleDeleteInteraction(request, id) {
  return routeWrap(request, async () => {
    ensureTable();
    const db = getDb();
    const row = db.prepare(
      `SELECT id, session_id FROM google_interactions WHERE id = ?`
    ).get(id);
    if (!row) throw notFound(`interaction not found: ${id}`);
    db.prepare(`DELETE FROM google_interactions WHERE id = ?`).run(id);
    const { handleDeleteSession } = await import("./handlers/anthropic-compat/sessions.js");
    const sessReq = new Request(request.url.replace(/\/google\/v1beta\/interactions.*/, `/v1/sessions/${row.session_id}`), {
      method: "DELETE",
      headers: request.headers
    });
    await handleDeleteSession(sessReq, row.session_id).catch(() => {
    });
    return jsonOk({ id, deleted: true });
  });
}
function handleCancelInteraction(request, id) {
  return routeWrap(request, async () => {
    ensureTable();
    const db = getDb();
    const row = db.prepare(
      `SELECT id, session_id, seq, status, environment_id, created_at FROM google_interactions WHERE id = ?`
    ).get(id);
    if (!row) throw notFound(`interaction not found: ${id}`);
    const { handlePostEvents } = await import("./handlers/anthropic-compat/events.js");
    const eventsReq = new Request(request.url.replace(/\/google\/v1beta\/interactions.*/, `/v1/sessions/${row.session_id}/events`), {
      method: "POST",
      headers: request.headers,
      body: JSON.stringify({
        events: [{ type: "user.interrupt" }]
      })
    });
    await handlePostEvents(eventsReq, row.session_id).catch(() => {
    });
    db.prepare(`UPDATE google_interactions SET status = 'cancelled' WHERE id = ?`).run(id);
    const response = {
      id: row.id,
      created: row.created_at,
      updated: (/* @__PURE__ */ new Date()).toISOString(),
      status: "cancelled",
      steps: [],
      usage: { total_input_tokens: 0, total_output_tokens: 0, total_tokens: 0 },
      environment_id: row.environment_id ?? void 0
    };
    return jsonOk(response);
  });
}
function buildFunctionResultEvents(input) {
  if (typeof input === "string") return [];
  if (!Array.isArray(input)) return [];
  const results = [];
  for (const item of input) {
    if (item && typeof item === "object" && item.type === "function_result") {
      const callId = item.call_id ?? item.id ?? "";
      const resultText = item.result ?? item.output ?? "";
      results.push({
        type: "user.custom_tool_result",
        custom_tool_use_id: callId,
        content: [{ type: "text", text: typeof resultText === "string" ? resultText : JSON.stringify(resultText) }]
      });
    }
  }
  return results;
}
async function waitForCompletion(sessionId, afterSeq = 0) {
  const { subscribe } = await import("./sessions/bus.js");
  return new Promise((resolve) => {
    const steps = [];
    let outputText = "";
    let inputTokens = 0;
    let outputTokens = 0;
    let status = "completed";
    let resolved = false;
    let subscription = null;
    const timeout = setTimeout(() => {
      if (resolved) return;
      resolved = true;
      subscription?.unsubscribe();
      resolve({
        status: "failed",
        steps,
        usage: { total_input_tokens: inputTokens, total_output_tokens: outputTokens, total_tokens: inputTokens + outputTokens },
        outputText
      });
    }, 5 * 6e4);
    function finish() {
      if (resolved) return;
      resolved = true;
      clearTimeout(timeout);
      subscription?.unsubscribe();
      resolve({
        status,
        steps,
        usage: { total_input_tokens: inputTokens, total_output_tokens: outputTokens, total_tokens: inputTokens + outputTokens },
        outputText
      });
    }
    function handleEvent(event) {
      if (resolved) return;
      if (event.type === "agent.message") {
        const content = event.content;
        const text = content?.filter((c) => c.type === "text").map((c) => c.text).join("") ?? "";
        if (text) {
          outputText += text;
          steps.push({ type: "model_output", content: [{ type: "text", text }] });
        }
      } else if (event.type === "agent.tool_use") {
        steps.push({
          type: "function_call",
          id: event.tool_use_id ?? "",
          name: event.name ?? "",
          arguments: event.input ?? {}
        });
      } else if (event.type === "agent.tool_result") {
        steps.push({
          type: "code_execution_result",
          call_id: event.tool_use_id ?? "",
          result: JSON.stringify(event.content ?? "")
        });
      } else if (event.type === "agent.custom_tool_use") {
        status = "requires_action";
        steps.push({
          type: "function_call",
          id: event.tool_use_id ?? "",
          name: event.name ?? "",
          arguments: event.input ?? {}
        });
      } else if (event.type === "span.model_request_end") {
        const mu = event.model_usage;
        inputTokens += mu?.input_tokens ?? 0;
        outputTokens += mu?.output_tokens ?? 0;
      } else if (event.type === "session.status_idle") {
        const stopReason = event.stop_reason;
        if (stopReason === "error") status = "failed";
        else if (status !== "requires_action") status = "completed";
        finish();
      } else if (event.type === "session.error") {
        status = "failed";
      }
    }
    const sub = subscribe(sessionId, afterSeq, handleEvent);
    subscription = sub;
    if (resolved) {
      clearTimeout(timeout);
      sub.unsubscribe();
    }
  });
}
function buildResponse(id, result, environmentId) {
  const now = (/* @__PURE__ */ new Date()).toISOString();
  return {
    id,
    created: now,
    updated: now,
    status: result.status,
    steps: result.steps,
    usage: result.usage,
    environment_id: environmentId
  };
}

export {
  handleCreateInteraction,
  handleGetInteraction,
  handleDeleteInteraction,
  handleCancelInteraction
};
