import {
  kickoffEnvironmentSetup
} from "./chunk-35RWSC6V.js";
import {
  assertResourceTenant,
  resolveCreateTenant,
  tenantFilter
} from "./chunk-K7DLILHK.js";
import {
  decodeCursor,
  jsonOk,
  paginatedOk,
  routeWrap
} from "./chunk-ZMMFMEXX.js";
import {
  forwardToAnthropic
} from "./chunk-VFSHH6I2.js";
import {
  getProxiedTenantId,
  isProxied,
  markProxied,
  unmarkProxied
} from "./chunk-DZIKCTP6.js";
import {
  resolveContainerProvider
} from "./chunk-ZKZME3DE.js";
import {
  archiveEnvironment,
  createEnvironment,
  deleteEnvironment,
  getEnvironment,
  hasSessionsAttached,
  listEnvironments,
  updateEnvironment
} from "./chunk-GTYDSYTR.js";
import {
  getDb,
  init_client
} from "./chunk-TLEKKGH7.js";
import {
  badRequest,
  conflict,
  notFound
} from "./chunk-EZYKRG4W.js";

// src/handlers/anthropic-compat/environments.ts
import { z } from "zod";
init_client();
function getEnvironmentTenantId(id) {
  const row = getDb().prepare(`SELECT tenant_id FROM environments WHERE id = ?`).get(id);
  return row?.tenant_id;
}
function loadEnvForCaller(auth, id) {
  const tenantId = getEnvironmentTenantId(id);
  if (tenantId === void 0) throw notFound(`environment ${id} not found`);
  assertResourceTenant(auth, tenantId, `environment ${id} not found`);
  const env = getEnvironment(id);
  if (!env) throw notFound(`environment ${id} not found`);
  return env;
}
function assertProxiedEnvTenant(auth, id) {
  const proxied = getProxiedTenantId(id);
  if (proxied === void 0) return;
  assertResourceTenant(auth, proxied, `environment ${id} not found`);
}
var PackagesSchema = z.object({
  apt: z.array(z.string()).optional(),
  cargo: z.array(z.string()).optional(),
  gem: z.array(z.string()).optional(),
  go: z.array(z.string()).optional(),
  npm: z.array(z.string()).optional(),
  pip: z.array(z.string()).optional()
}).optional();
var NetworkingSchema = z.union([
  z.object({ type: z.literal("unrestricted") }),
  z.object({
    type: z.literal("limited"),
    allowed_hosts: z.array(z.string()).optional(),
    allow_mcp_servers: z.boolean().optional(),
    allow_package_managers: z.boolean().optional()
  })
]);
var ConfigSchema = z.object({
  type: z.enum(["cloud", "self_hosted"]),
  provider: z.enum(["sprites", "docker", "apple-container", "apple-firecracker", "podman", "e2b", "vercel", "daytona", "fly", "modal", "mvm", "anthropic"]).optional(),
  packages: PackagesSchema,
  networking: NetworkingSchema.optional(),
  warm_pool_size: z.number().int().min(0).optional()
});
var CreateSchema = z.object({
  name: z.string().min(1),
  config: ConfigSchema,
  description: z.string().optional().nullable(),
  metadata: z.record(z.string()).optional(),
  backend: z.enum(["anthropic"]).optional(),
  /** v0.5: required for global admin, ignored for tenant users. */
  tenant_id: z.string().optional()
});
var UpdateSchema = z.object({
  name: z.string().min(1).optional(),
  description: z.string().optional().nullable(),
  metadata: z.record(z.string()).optional(),
  config: ConfigSchema.optional()
});
function handleCreateEnvironment(request) {
  return routeWrap(request, async ({ auth }) => {
    const rawBody = await request.text();
    const body = rawBody ? JSON.parse(rawBody) : null;
    const parsed = CreateSchema.safeParse(body);
    if (!parsed.success) throw badRequest(parsed.error.message);
    let configData = parsed.data.config;
    if (configData.type === "cloud" && configData.provider && configData.provider !== "anthropic") {
      console.warn(`[compat] type: "cloud" with provider "${configData.provider}" is deprecated \u2014 use type: "self_hosted"`);
      configData = { ...configData, type: "self_hosted" };
    }
    const createTenantId = resolveCreateTenant(auth, parsed.data.tenant_id);
    if (parsed.data.backend === "anthropic") {
      const { backend: _, ...rest } = body;
      const forwardBody = JSON.stringify(rest);
      const proxyRes = await forwardToAnthropic(request, "/v1/environments", { body: forwardBody });
      if (proxyRes.ok) {
        try {
          const data = await proxyRes.clone().json();
          markProxied(data.id, "environment", createTenantId);
        } catch {
        }
      }
      return proxyRes;
    }
    const existingEnvs = listEnvironments({ limit: 1e3, tenantFilter: tenantFilter(auth) });
    if (existingEnvs.some((e) => e.name === parsed.data.name)) {
      throw conflict(`Environment with name "${parsed.data.name}" already exists`);
    }
    const configType = configData.type;
    const providerName = configData.provider;
    if (configType === "cloud") {
    } else {
      if (providerName) {
        const CLOUD_PROVIDERS = /* @__PURE__ */ new Set(["sprites", "e2b", "vercel", "daytona", "fly", "modal", "anthropic"]);
        if (!CLOUD_PROVIDERS.has(providerName)) {
          const provider = await resolveContainerProvider(providerName);
          if (provider.checkAvailability) {
            const result = await provider.checkAvailability();
            if (!result.available) {
              throw badRequest(`Provider "${providerName}" is not available: ${result.message}`);
            }
          }
        }
      }
    }
    const env = createEnvironment({
      name: parsed.data.name,
      config: configData,
      description: parsed.data.description ?? null,
      metadata: parsed.data.metadata,
      tenant_id: createTenantId
    });
    kickoffEnvironmentSetup(env.id);
    return jsonOk(env, 201);
  });
}
function handleListEnvironments(request) {
  return routeWrap(request, async ({ auth, request: req }) => {
    const url = new URL(req.url);
    const limit = url.searchParams.get("limit");
    const order = url.searchParams.get("order");
    const includeArchived = url.searchParams.get("include_archived") === "true";
    const cursor = decodeCursor(url.searchParams.get("after_id") ?? url.searchParams.get("page"));
    const requestedLimit = limit ? Number(limit) : 20;
    const data = listEnvironments({
      limit: requestedLimit,
      order: order ?? void 0,
      includeArchived,
      cursor,
      tenantFilter: tenantFilter(auth)
    });
    return paginatedOk(data, requestedLimit);
  });
}
function handleGetEnvironment(request, id) {
  return routeWrap(request, async ({ auth }) => {
    if (isProxied(id)) {
      assertProxiedEnvTenant(auth, id);
      return forwardToAnthropic(request, `/v1/environments/${id}`);
    }
    return jsonOk(loadEnvForCaller(auth, id));
  });
}
function handleDeleteEnvironment(request, id) {
  return routeWrap(request, async ({ auth }) => {
    if (isProxied(id)) {
      assertProxiedEnvTenant(auth, id);
      const res = await forwardToAnthropic(request, `/v1/environments/${id}`);
      if (res.ok) unmarkProxied(id);
      return res;
    }
    loadEnvForCaller(auth, id);
    if (hasSessionsAttached(id)) {
      throw conflict(`Cannot delete: environment has active sessions. Archive or delete sessions first.`);
    }
    deleteEnvironment(id);
    return jsonOk({ id, type: "environment_deleted" });
  });
}
function handleArchiveEnvironment(request, id) {
  return routeWrap(request, async ({ auth }) => {
    if (isProxied(id)) {
      assertProxiedEnvTenant(auth, id);
      const res = await forwardToAnthropic(request, `/v1/environments/${id}/archive`);
      if (res.ok) unmarkProxied(id);
      return res;
    }
    loadEnvForCaller(auth, id);
    if (hasSessionsAttached(id)) {
      throw conflict(`environment ${id} still has active sessions attached`);
    }
    archiveEnvironment(id);
    const env = getEnvironment(id);
    return jsonOk(env);
  });
}
function handleUpdateEnvironment(request, id) {
  return routeWrap(request, async ({ auth }) => {
    if (isProxied(id)) {
      assertProxiedEnvTenant(auth, id);
      return forwardToAnthropic(request, `/v1/environments/${id}`, {
        body: await request.text()
      });
    }
    loadEnvForCaller(auth, id);
    const rawBody = await request.text();
    const body = rawBody ? JSON.parse(rawBody) : null;
    const parsed = UpdateSchema.safeParse(body);
    if (!parsed.success) throw badRequest(parsed.error.message);
    const updated = updateEnvironment(id, {
      name: parsed.data.name,
      description: parsed.data.description,
      metadata: parsed.data.metadata,
      config: parsed.data.config
    });
    return jsonOk(updated);
  });
}

export {
  handleCreateEnvironment,
  handleListEnvironments,
  handleGetEnvironment,
  handleDeleteEnvironment,
  handleArchiveEnvironment,
  handleUpdateEnvironment
};
