import { constants as fsConstants, createReadStream, createWriteStream } from "node:fs";
import { lstat, mkdir, open, readFile, readdir, rename, stat, writeFile } from "node:fs/promises";
import { createServer, request as httpRequest } from "node:http";
import { request as httpsRequest } from "node:https";
import { createHash, createHmac, randomUUID } from "node:crypto";
import { basename, extname, join, normalize, resolve } from "node:path";
import { Readable, Transform } from "node:stream";
import { pipeline } from "node:stream/promises";
import { fileURLToPath } from "node:url";
import {
  FOUNDRY_BINDING_CATALOG_PATH,
  FOUNDRY_BINDING_UPSERT_PATH,
  handleFoundryBindingApiRequest,
} from "./foundry-binding-api.mjs";
import { createFoundryAgentGateway } from "./foundry-agent-gateway.mjs";
import { createFoundryAgentStore } from "./foundry-agent-store.mjs";
import { createFoundryDataProductConsumerManager } from "./foundry-data-product-consumer.mjs";
import { createFoundryReaderGrantProvisioner } from "./foundry-reader-grant-provisioner.mjs";
import { handleFoundryEntitlementRequest, handleFoundryMcpRequest } from "./foundry-mcp.mjs";
import { isMapLiveDataSlot } from "./map-live-data-slot.mjs";
import { normalizeMapPresentationProfile, normalizeMapPresentationProfiles } from "./map-presentation-profile.mjs";
import { normalizeMapSubjectDetailProfile, normalizeMapSubjectDetailProfiles } from "./map-subject-detail-profile.mjs";
import { createFoundryAuth } from "./nodedc-auth.mjs";

const root = fileURLToPath(new URL("..", import.meta.url));
const distDir = join(root, "apps", "catalog", "dist");
const runtimeDir = process.env.FOUNDRY_RUNTIME_DIR
  ? resolve(root, process.env.FOUNDRY_RUNTIME_DIR)
  : join(root, "runtime-data");
const uploadDir = join(runtimeDir, "uploads");
const applicationsDir = join(runtimeDir, "applications");
const designProfilesDir = join(runtimeDir, "design-profiles");
const designProfileReleasesDir = join(runtimeDir, "design-profile-releases");
const pageLayoutsDir = join(runtimeDir, "page-layouts");
const foundryMcpOperationsDir = join(runtimeDir, "foundry-mcp-operations");
const foundryDataProductConsumersDir = join(runtimeDir, "data-product-consumers");
const foundryManagedReaderGrantsDir = join(runtimeDir, "runtime-secrets", "external-data-plane-reader-grants");
const foundryAgentDataDir = join(runtimeDir, "foundry-agent-gateway");
const layoutPath = join(runtimeDir, "layout.json");
const pageRegistryPath = join(root, "registry", "pages.json");
const port = Number(process.env.PORT || 3333);
const host = process.env.HOST || "127.0.0.1";
await mkdir(uploadDir, { recursive: true });
await mkdir(applicationsDir, { recursive: true });
await mkdir(designProfilesDir, { recursive: true });
await mkdir(designProfileReleasesDir, { recursive: true });
await mkdir(pageLayoutsDir, { recursive: true });
await mkdir(foundryMcpOperationsDir, { recursive: true });
await mkdir(foundryDataProductConsumersDir, { recursive: true });
await mkdir(foundryAgentDataDir, { recursive: true });
const pageRegistry = JSON.parse(await readFile(pageRegistryPath, "utf8"));
const dataProductConsumerPolicyRegistry = JSON.parse(await readFile(join(root, "registry", "data-product-consumer-policies.json"), "utf8"));
const mapPresentationProfileRegistry = JSON.parse(await readFile(join(root, "registry", "map-presentation-profiles.json"), "utf8"));
if (mapPresentationProfileRegistry?.schemaVersion !== "nodedc.map-presentation-profiles/v1") {
  throw new Error("map_presentation_profile_registry_invalid");
}
const canonicalMapPresentationProfiles = normalizeMapPresentationProfiles(mapPresentationProfileRegistry.profiles);
const canonicalMapReferencePresentationProfiles = canonicalMapPresentationProfiles.filter((profile) => (
  profile.id.startsWith("map.reference.transport.")
));
const canonicalMapReferenceLayers = Object.freeze([
  Object.freeze({
    id: "reference.transport.metro",
    referenceProfileId: "transport-stations.v1",
    category: "metro",
    presentationProfileId: "map.reference.transport.metro.v1",
    visible: true,
  }),
  Object.freeze({
    id: "reference.transport.railway_terminal",
    referenceProfileId: "transport-stations.v1",
    category: "railway_terminal",
    presentationProfileId: "map.reference.transport.terminal.v1",
    visible: true,
  }),
  Object.freeze({
    id: "reference.transport.railway_station",
    referenceProfileId: "transport-stations.v1",
    category: "railway_station",
    presentationProfileId: "map.reference.transport.railway-station.v1",
    visible: true,
  }),
]);
const mapSubjectDetailProfileRegistry = JSON.parse(await readFile(join(root, "registry", "map-subject-detail-profiles.json"), "utf8"));
if (mapSubjectDetailProfileRegistry?.schemaVersion !== "nodedc.map-subject-detail-profiles/v1") {
  throw new Error("map_subject_detail_profile_registry_invalid");
}
const canonicalMapSubjectDetailProfiles = normalizeMapSubjectDetailProfiles(mapSubjectDetailProfileRegistry.profiles);
const foundryAuth = createFoundryAuth();
const mapGatewayHeadersTimeoutMs = boundedMapGatewayTimeout(
  process.env.NODEDC_MAP_GATEWAY_HEADERS_TIMEOUT_MS,
  15_000,
);
const mapGatewayBodyIdleTimeoutMs = boundedMapGatewayTimeout(
  process.env.NODEDC_MAP_GATEWAY_BODY_IDLE_TIMEOUT_MS,
  30_000,
);
const mapGatewayInternalUrl = String(
  process.env.NODEDC_MAP_GATEWAY_INTERNAL_URL
    || process.env.NODEDC_MAP_GATEWAY_URL
    || (process.env.NODE_ENV === "production" ? "" : "http://127.0.0.1:18103"),
).trim().replace(/\/$/, "");
// External Data Plane remains private to Platform. A browser can only address
// a persisted application/page/binding target through the same-origin BFF.
const externalDataPlaneInternalUrl = String(process.env.NODEDC_EXTERNAL_DATA_PLANE_INTERNAL_URL || "").trim().replace(/\/$/, "");
const externalDataPlaneReaderGrantsDir = String(process.env.NODEDC_EXTERNAL_DATA_PLANE_READER_GRANTS_DIR || "").trim();
const foundryReaderGrantProvisioner = createFoundryReaderGrantProvisioner({
  dataPlaneUrl: externalDataPlaneInternalUrl,
  privateKeyFile: process.env.NODEDC_EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_PRIVATE_KEY_FILE,
  grantsDir: foundryManagedReaderGrantsDir,
  serviceId: process.env.NODEDC_EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_SERVICE_ID || "nodedc-module-foundry",
  keyId: process.env.NODEDC_EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_KEY_ID || "foundry-edp-managed-provisioner-v1",
  audience: process.env.NODEDC_EXTERNAL_DATA_PLANE_FOUNDRY_PROVISIONER_AUDIENCE || "nodedc-external-data-plane.managed-provisioning.v1",
});
const foundryBindingGrantsDir = String(process.env.NODEDC_FOUNDRY_BINDING_GRANTS_DIR || "").trim();
const activeRuntimeStreams = new Set();
// A dedicated server-only signing value shared with Map Gateway. In production
// the runner supplies it as a read-only file, never an env value or browser API.
const mapGatewayAdminSecret = await readMapGatewayAdminSecret();
const foundryPublicUrl = normalizeFoundryPublicUrl(process.env.FOUNDRY_PUBLIC_URL);
const foundryAgentStore = createFoundryAgentStore({ dataRoot: foundryAgentDataDir });
const foundryAgentGateway = createFoundryAgentGateway({
  store: foundryAgentStore,
  configuredPublicOrigin: foundryPublicUrl?.origin || "",
  installerPackagePath: join(root, "server", "assets", "nodedc-foundry-codex-agent-0.1.0.tgz"),
  ontologyCoreUrl: process.env.NODEDC_ONTOLOGY_CORE_URL,
  ontologyCoreAccessToken: process.env.NODEDC_INTERNAL_ACCESS_TOKEN,
});

function boundedMapGatewayTimeout(value, fallback) {
  const parsed = Number.parseInt(String(value || ""), 10);
  if (!Number.isFinite(parsed)) return fallback;
  return Math.min(120_000, Math.max(50, parsed));
}

async function readMapGatewayAdminSecret() {
  const secretFile = String(process.env.NODEDC_MAP_GATEWAY_ADMIN_SECRET_FILE || "").trim();
  if (secretFile) {
    let secret;
    try {
      secret = (await readFile(secretFile, "utf8")).trim();
    } catch {
      throw new Error("map_gateway_admin_secret_file_unreadable");
    }
    if (!/^[A-Za-z0-9_-]{48,256}$/.test(secret)) throw new Error("map_gateway_admin_secret_file_invalid");
    return secret;
  }
  if (process.env.NODE_ENV === "production") throw new Error("map_gateway_admin_secret_file_required");
  return String(process.env.NODEDC_MAP_GATEWAY_ADMIN_SECRET || "").trim();
}

function normalizeFoundryPublicUrl(value) {
  const raw = String(value || "").trim();
  if (!raw) return null;
  let url;
  try { url = new URL(raw); } catch { throw new Error("invalid_foundry_public_url"); }
  if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.search || url.hash) {
    throw new Error("invalid_foundry_public_url");
  }
  url.pathname = url.pathname.replace(/\/+$/, "") || "/";
  return url;
}

function normalizeFoundryReferer(value) {
  const raw = String(value || "").trim();
  if (!raw || raw.length > 2048) return null;
  let url;
  try { url = new URL(raw); } catch { return null; }
  if (!["http:", "https:"].includes(url.protocol) || url.username || url.password) return null;
  url.search = "";
  url.hash = "";
  return url;
}

function foundryRequestIonReferer(request) {
  const browserReferer = normalizeFoundryReferer(request.headers.referer);
  if (foundryPublicUrl) {
    // Do not turn an arbitrary browser-provided Referer into Cesium provider
    // authorization. Only the configured public Foundry origin is delegated.
    if (browserReferer && browserReferer.origin === foundryPublicUrl.origin) return browserReferer.toString();
    return foundryPublicUrl.toString();
  }
  return browserReferer?.toString() || "";
}

function findPageTemplate(id, version) {
  return pageRegistry.templates.find((template) => template.id === id && (!version || template.version === version));
}

const mimeTypes = {
  ".css": "text/css; charset=utf-8",
  ".gif": "image/gif",
  ".html": "text/html; charset=utf-8",
  ".ico": "image/x-icon",
  ".jpg": "image/jpeg",
  ".jpeg": "image/jpeg",
  ".js": "text/javascript; charset=utf-8",
  ".json": "application/json; charset=utf-8",
  ".map": "application/json; charset=utf-8",
  ".mp4": "video/mp4",
  ".png": "image/png",
  ".svg": "image/svg+xml",
  ".webm": "video/webm",
  ".webp": "image/webp",
  ".mov": "video/quicktime",
};

function json(response, statusCode, value) {
  // A downstream stream can fail after its status and headers have already
  // reached the browser. Never attempt a second response in that case: Node
  // would throw ERR_HTTP_HEADERS_SENT and a normal Cesium request cancellation
  // could terminate the complete Foundry process.
  if (response.headersSent || response.writableEnded || response.destroyed) {
    if (!response.writableEnded && !response.destroyed) response.destroy();
    return;
  }
  response.writeHead(statusCode, { "content-type": "application/json; charset=utf-8", "cache-control": "no-store" });
  response.end(JSON.stringify(value));
}

function applicationError(code, statusCode = 400) {
  const error = new Error(code);
  error.statusCode = statusCode;
  return error;
}

function normalizeSlug(value) {
  return String(value || "")
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9-]+/g, "-")
    .replace(/-{2,}/g, "-")
    .replace(/^-+|-+$/g, "")
    .slice(0, 64);
}

function applicationPath(id) {
  const safeId = String(id || "");
  if (!/^[0-9a-f-]{36}$/i.test(safeId)) throw applicationError("invalid_application_id");
  return join(applicationsDir, `${safeId}.json`);
}

function designProfilePath(id) {
  const safeId = String(id || "");
  if (safeId !== "default" && !/^[0-9a-f-]{36}$/i.test(safeId)) throw applicationError("invalid_design_profile_id");
  return join(designProfilesDir, `${safeId}.json`);
}

function designProfileReleaseDir(id) {
  const safeId = String(id || "");
  if (safeId !== "default" && !/^[0-9a-f-]{36}$/i.test(safeId)) throw applicationError("invalid_design_profile_id");
  return join(designProfileReleasesDir, safeId);
}

function designProfileReleasePath(id, version) {
  const safeVersion = String(version || "");
  if (!/^\d+\.\d+\.\d+$/.test(safeVersion)) throw applicationError("invalid_design_profile_version");
  return join(designProfileReleaseDir(id), `${safeVersion}.json`);
}

function pageLayoutPath(pageId) {
  const safePageId = String(pageId || "");
  if (!/^[a-z0-9-]+$/i.test(safePageId) || !findPageTemplate(safePageId)) {
    throw applicationError("unknown_page_template");
  }
  return join(pageLayoutsDir, `${safePageId}.json`);
}

const isObject = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
const requireHex = (value, code) => {
  const normalized = String(value || "");
  if (!/^#[0-9a-f]{6}$/i.test(normalized)) throw applicationError(code);
  return normalized.toLowerCase();
};
const requireNumber = (value, min, max, code) => {
  if (typeof value !== "number" || !Number.isFinite(value) || value < min || value > max) throw applicationError(code);
  return value;
};
const requireInteger = (value, min, max, code) => {
  const normalized = requireNumber(value, min, max, code);
  if (!Number.isInteger(normalized)) throw applicationError(code);
  return normalized;
};
const requireString = (value, code, max = 4096) => {
  if (typeof value !== "string" || value.length > max) throw applicationError(code);
  return value;
};
const requireNonEmptyString = (value, code, max = 4096) => {
  const normalized = requireString(value, code, max);
  if (!normalized) throw applicationError(code);
  return normalized;
};
const requireBoolean = (value, code) => {
  if (typeof value !== "boolean") throw applicationError(code);
  return value;
};

function validateMapPinBinding(value) {
  if (!isObject(value)) throw applicationError("invalid_map_pin_binding");
  const id = requireNonEmptyString(value.id, "invalid_map_pin_id", 128);
  const subjectId = requireNonEmptyString(value.subjectId, "invalid_map_pin_subject_id", 256);
  if (!/^[A-Za-z0-9._:-]+$/.test(id)) throw applicationError("invalid_map_pin_id");
  if (!isObject(value.coordinates)) throw applicationError("invalid_map_pin_coordinates");
  if (!isObject(value.source)) throw applicationError("invalid_map_pin_source");
  const attributes = value.attributes === undefined ? {} : value.attributes;
  if (!isObject(attributes) || Object.keys(attributes).length > 30) throw applicationError("invalid_map_pin_attributes");
  const normalizedAttributes = {};
  for (const [key, raw] of Object.entries(attributes)) {
    if (!/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(key)) throw applicationError("invalid_map_pin_attribute_key");
    if (!["string", "number", "boolean"].includes(typeof raw) || (typeof raw === "string" && raw.length > 500)) {
      throw applicationError("invalid_map_pin_attribute_value");
    }
    normalizedAttributes[key] = raw;
  }
  const displayFields = value.source.displayFields === undefined ? [] : value.source.displayFields;
  if (!Array.isArray(displayFields) || displayFields.length > 24 || displayFields.some((field) => typeof field !== "string" || field.length > 128)) {
    throw applicationError("invalid_map_pin_display_fields");
  }
  return {
    id,
    subjectId,
    kind: "elevated-spike",
    label: String(value.label || "").slice(0, 240),
    status: String(value.status || "").slice(0, 80),
    coordinates: {
      longitude: requireNumber(value.coordinates.longitude, -180, 180, "invalid_map_pin_longitude"),
      latitude: requireNumber(value.coordinates.latitude, -90, 90, "invalid_map_pin_latitude"),
      heightMeters: value.coordinates.heightMeters === undefined
        ? 0
        : requireNumber(value.coordinates.heightMeters, -10000, 10000000, "invalid_map_pin_height"),
    },
    source: {
      entityId: requireNonEmptyString(value.source.entityId, "invalid_map_pin_source_entity", 240),
      streamId: String(value.source.streamId || "").slice(0, 240),
      displayFields: [...displayFields],
    },
    attributes: normalizedAttributes,
  };
}

function validateMapPinBindings(value) {
  if (!Array.isArray(value) || value.length > 10000) throw applicationError("invalid_map_pin_bindings");
  const ids = new Set();
  return value.map((item) => {
    const binding = validateMapPinBinding(item);
    if (ids.has(binding.id)) throw applicationError("duplicate_map_pin_id");
    ids.add(binding.id);
    return binding;
  });
}

function validateMapDataProductBinding(value) {
  if (!isObject(value)) throw applicationError("invalid_map_data_product_binding");
  const id = requireNonEmptyString(value.id, "invalid_map_data_product_binding_id", 128);
  const dataProductId = requireNonEmptyString(value.dataProductId, "invalid_map_data_product_id", 160);
  const slotId = requireNonEmptyString(value.slotId, "invalid_map_data_product_slot", 80);
  const displayName = value.displayName === undefined
    ? null
    : requireNonEmptyString(value.displayName, "invalid_map_data_product_display_name", 120).trim();
  const order = value.order === undefined
    ? null
    : requireInteger(value.order, 0, 10_000, "invalid_map_data_product_order");
  const semanticTypes = value.semanticTypes === undefined ? [] : value.semanticTypes;
  const fieldProjection = value.fieldProjection === undefined ? [] : value.fieldProjection;
  const presentationProfileId = value.presentationProfileId === undefined
    ? null
    : requireNonEmptyString(value.presentationProfileId, "invalid_map_data_product_presentation_profile_id", 160);
  const subjectDetailProfileId = value.subjectDetailProfileId === undefined
    ? null
    : requireNonEmptyString(value.subjectDetailProfileId, "invalid_map_data_product_subject_detail_profile_id", 160);
  const aspectId = value.aspectId === undefined
    ? "primary"
    : requireNonEmptyString(value.aspectId, "invalid_map_data_product_aspect_id", 160);
  const joinToBindingId = value.joinToBindingId === undefined
    ? null
    : requireNonEmptyString(value.joinToBindingId, "invalid_map_data_product_join_binding_id", 128);
  const dataClass = value.dataClass === undefined
    ? "operational"
    : requireNonEmptyString(value.dataClass, "invalid_map_data_product_data_class", 32);
  if (!/^[A-Za-z0-9._:-]+$/.test(id)) throw applicationError("invalid_map_data_product_binding_id");
  if (!/^[A-Za-z0-9._:-]+$/.test(dataProductId)) throw applicationError("invalid_map_data_product_id");
  if (!/^[A-Za-z0-9-]+$/.test(slotId)) throw applicationError("invalid_map_data_product_slot");
  if (!Array.isArray(semanticTypes) || semanticTypes.length === 0 || semanticTypes.length > 8 || semanticTypes.some((item) => typeof item !== "string" || !/^[A-Za-z0-9._:-]+$/.test(item))) {
    throw applicationError("invalid_map_data_product_semantic_types");
  }
  if (!Array.isArray(fieldProjection) || fieldProjection.length > 32 || fieldProjection.some((item) => typeof item !== "string" || !/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(item))) {
    throw applicationError("invalid_map_data_product_field_projection");
  }
  if (presentationProfileId && !/^[a-z][a-z0-9._:-]{1,159}$/.test(presentationProfileId)) {
    throw applicationError("invalid_map_data_product_presentation_profile_id");
  }
  if (subjectDetailProfileId && !/^[a-z][a-z0-9._:-]{1,159}$/.test(subjectDetailProfileId)) {
    throw applicationError("invalid_map_data_product_subject_detail_profile_id");
  }
  if (!/^[a-z][a-z0-9._:-]{1,159}$/.test(aspectId)) throw applicationError("invalid_map_data_product_aspect_id");
  if (joinToBindingId && !/^[A-Za-z0-9._:-]+$/.test(joinToBindingId)) {
    throw applicationError("invalid_map_data_product_join_binding_id");
  }
  if (!new Set(["operational", "restricted"]).has(dataClass)) {
    throw applicationError("invalid_map_data_product_data_class");
  }
  if (Object.keys(value).some((key) => /(provider|tenant|connection|endpoint|url|credential|token|secret|payload)/i.test(key))) {
    throw applicationError("map_data_product_binding_contains_transport");
  }
  return {
    id,
    dataProductId,
    slotId,
    delivery: "snapshot+patch",
    semanticTypes: [...semanticTypes],
    fieldProjection: [...fieldProjection],
    ...(displayName ? { displayName } : {}),
    ...(order !== null ? { order } : {}),
    ...(presentationProfileId ? { presentationProfileId } : {}),
    ...(subjectDetailProfileId ? { subjectDetailProfileId } : {}),
    aspectId,
    ...(joinToBindingId ? { joinToBindingId } : {}),
    dataClass,
  };
}

function validateMapDataProductBindings(value) {
  if (!Array.isArray(value) || value.length > 64) throw applicationError("invalid_map_data_product_bindings");
  const ids = new Set();
  return value.map((item) => {
    const binding = validateMapDataProductBinding(item);
    if (ids.has(binding.id)) throw applicationError("duplicate_map_data_product_binding_id");
    ids.add(binding.id);
    return binding;
  });
}

function defaultMapSubjectState(bindingId, index) {
  return {
    bindingId,
    visible: true,
    filters: {},
    window: {
      open: false,
      rect: { x: 24 + (index % 5) * 28, y: 56 + (index % 5) * 28, width: 280, height: 260 },
      maximized: false,
      zIndex: 20 + index,
    },
  };
}

function validateMapSubjectStates(value, dataProductBindings) {
  if (!Array.isArray(value) || value.length > 64) throw applicationError("invalid_map_subject_states");
  const bindingIds = new Set(dataProductBindings.map((binding) => binding.id));
  const states = new Map();
  for (const raw of value) {
    if (!isObject(raw)) throw applicationError("invalid_map_subject_state");
    const bindingId = requireNonEmptyString(raw.bindingId, "invalid_map_subject_state_binding_id", 128);
    if (!bindingIds.has(bindingId)) continue;
    if (states.has(bindingId)) throw applicationError("duplicate_map_subject_state_binding_id");
    const filters = raw.filters === undefined ? {} : raw.filters;
    if (!isObject(filters) || Object.keys(filters).length > 32) throw applicationError("invalid_map_subject_filters");
    const normalizedFilters = {};
    for (const [field, selected] of Object.entries(filters)) {
      if (!/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(field)) throw applicationError("invalid_map_subject_filter_field");
      if (!Array.isArray(selected) || selected.length > 64 || selected.some((item) => typeof item !== "string" || item.length > 160)) {
        throw applicationError("invalid_map_subject_filter_values");
      }
      normalizedFilters[field] = [...new Set(selected)];
    }
    if (!isObject(raw.window) || !isObject(raw.window.rect)) throw applicationError("invalid_map_subject_window");
    states.set(bindingId, {
      bindingId,
      visible: requireBoolean(raw.visible, "invalid_map_subject_visibility"),
      filters: normalizedFilters,
      window: {
        open: requireBoolean(raw.window.open, "invalid_map_subject_window_open"),
        rect: {
          x: requireNumber(raw.window.rect.x, -100_000, 100_000, "invalid_map_subject_window_x"),
          y: requireNumber(raw.window.rect.y, -100_000, 100_000, "invalid_map_subject_window_y"),
          width: requireNumber(raw.window.rect.width, 200, 10_000, "invalid_map_subject_window_width"),
          height: requireNumber(raw.window.rect.height, 160, 10_000, "invalid_map_subject_window_height"),
        },
        maximized: requireBoolean(raw.window.maximized, "invalid_map_subject_window_maximized"),
        zIndex: requireInteger(raw.window.zIndex, 1, 100_000, "invalid_map_subject_window_z_index"),
      },
    });
  }
  return dataProductBindings.map((binding, index) => states.get(binding.id) ?? defaultMapSubjectState(binding.id, index));
}

function validateMapReferenceLayers(value) {
  if (!Array.isArray(value) || value.length > canonicalMapReferenceLayers.length) {
    throw applicationError("invalid_map_reference_layers");
  }
  const canonicalById = new Map(canonicalMapReferenceLayers.map((layer) => [layer.id, layer]));
  const visibilityById = new Map();
  for (const raw of value) {
    if (!isObject(raw)) throw applicationError("invalid_map_reference_layer");
    if (Object.keys(raw).some((key) => !new Set([
      "id", "referenceProfileId", "category", "presentationProfileId", "visible",
    ]).has(key))) throw applicationError("invalid_map_reference_layer_field");
    const canonical = canonicalById.get(raw.id);
    if (!canonical
      || raw.referenceProfileId !== canonical.referenceProfileId
      || raw.category !== canonical.category
      || raw.presentationProfileId !== canonical.presentationProfileId) {
      throw applicationError("map_reference_layer_not_registered");
    }
    if (visibilityById.has(raw.id)) throw applicationError("duplicate_map_reference_layer_id");
    visibilityById.set(raw.id, requireBoolean(raw.visible, "invalid_map_reference_layer_visibility"));
  }
  return canonicalMapReferenceLayers.map((layer) => ({
    ...layer,
    visible: visibilityById.get(layer.id) ?? layer.visible,
  }));
}

const MAP_PAGE_SETTING_KEYS = new Set([
  "imagerySource", "imageryVisible", "cacheEnabled", "cacheNoOverwrite", "terrainEnabled",
  "terrainExaggeration", "monochrome", "monochromeColor", "imageryGamma", "imageryHue",
  "imageryAlpha", "globeColor", "backgroundColor", "atmosphereEnabled", "atmosphereHue",
  "atmosphereSaturation", "atmosphereBrightness", "fogEnabled", "fogDensity", "sunEnabled",
  "sunHour", "sunIntensity", "shadowsEnabled", "buildingsVisible", "buildingsColor",
  "buildingsOpacity", "buildingsDetail", "imageryBrightness", "imageryContrast",
  "imagerySaturation", "gridVisible", "gridLodEnabled", "gridHeightMeters",
  "gridLod1MaxHeightKm", "gridLod1StepKm", "gridLod2MaxHeightKm", "gridLod2StepKm",
  "gridLod3StepKm", "gridRadiusKm", "gridLineWidth", "gridColor", "gridOpacity",
  "gridDotsEnabled", "gridDotsSize", "gridDotsColor", "gridDotsOpacity",
]);

function validateMapPageSettingsPatch(value) {
  if (!isObject(value) || Object.keys(value).length === 0) throw applicationError("invalid_map_page_settings_patch");
  if (Object.keys(value).some((key) => !MAP_PAGE_SETTING_KEYS.has(key))) throw applicationError("invalid_map_page_settings_patch_field");
  return value;
}

function validateMapInspectorOpenSections(value) {
  if (!Array.isArray(value) || value.length > 1) {
    throw applicationError("invalid_map_inspector_open_sections");
  }
  const sections = value.map((section) => requireNonEmptyString(
    section,
    "invalid_map_inspector_open_section",
    256,
  ));
  if (new Set(sections).size !== sections.length) {
    throw applicationError("duplicate_map_inspector_open_section");
  }
  return sections;
}

function validateMapPageLayout(value) {
  if (!isObject(value)) throw applicationError("invalid_map_page_layout");
  if (value.schemaVersion !== 1 || value.pageId !== "map") throw applicationError("unsupported_map_page_layout");
  if (!isObject(value.settings)) throw applicationError("invalid_map_page_settings");
  if (!isObject(value.camera)) throw applicationError("invalid_map_page_camera");
  const settings = value.settings;
  if (Object.keys(settings).some((key) => !MAP_PAGE_SETTING_KEYS.has(key))) throw applicationError("invalid_map_page_setting_field");
  for (const key of ["imageryVisible", "cacheEnabled", "terrainEnabled", "monochrome", "atmosphereEnabled", "fogEnabled", "sunEnabled", "shadowsEnabled", "buildingsVisible", "gridVisible", "gridLodEnabled", "gridDotsEnabled"]) {
    requireBoolean(settings[key], `invalid_map_page_setting_${key}`);
  }
  // Layouts written before this field existed are safely upgraded to the
  // no-overwrite default during read/save; they are not rejected as damaged.
  if (settings.cacheNoOverwrite !== undefined) requireBoolean(settings.cacheNoOverwrite, "invalid_map_page_setting_cacheNoOverwrite");
  requireString(settings.imagerySource, "invalid_map_page_imagery_source", 64);
  for (const key of ["terrainExaggeration", "imageryGamma", "imageryHue", "imageryAlpha", "atmosphereHue", "atmosphereSaturation", "atmosphereBrightness", "fogDensity", "sunHour", "sunIntensity", "buildingsOpacity", "buildingsDetail", "imageryBrightness", "imageryContrast", "imagerySaturation", "gridHeightMeters", "gridLod1MaxHeightKm", "gridLod1StepKm", "gridLod2MaxHeightKm", "gridLod2StepKm", "gridLod3StepKm", "gridRadiusKm", "gridLineWidth", "gridOpacity", "gridDotsSize", "gridDotsOpacity"]) {
    requireNumber(settings[key], -100000, 100000, `invalid_map_page_setting_${key}`);
  }
  for (const key of ["monochromeColor", "globeColor", "backgroundColor", "buildingsColor", "gridColor", "gridDotsColor"]) {
    requireHex(settings[key], `invalid_map_page_setting_${key}`);
  }
  const camera = value.camera;
  for (const key of ["longitude", "latitude", "height", "heading", "pitch", "roll"]) {
    requireNumber(camera[key], -1_000_000_000, 1_000_000_000, `invalid_map_page_camera_${key}`);
  }
  const suppliedPresentationProfiles = normalizeMapPresentationProfiles(value.presentationProfiles === undefined ? [] : value.presentationProfiles);
  const suppliedPresentationProfileIds = new Set(suppliedPresentationProfiles.map((profile) => profile.id));
  const presentationProfiles = normalizeMapPresentationProfiles([
    ...suppliedPresentationProfiles,
    ...canonicalMapReferencePresentationProfiles.filter((profile) => !suppliedPresentationProfileIds.has(profile.id)),
  ]);
  const subjectDetailProfiles = normalizeMapSubjectDetailProfiles(
    value.subjectDetailProfiles === undefined
      ? structuredClone(canonicalMapSubjectDetailProfiles)
      : value.subjectDetailProfiles,
  );
  const dataProductBindings = validateMapDataProductBindings(value.dataProductBindings === undefined ? [] : value.dataProductBindings);
  const subjectStates = validateMapSubjectStates(value.subjectStates === undefined ? [] : value.subjectStates, dataProductBindings);
  const referenceLayers = validateMapReferenceLayers(value.referenceLayers === undefined ? [] : value.referenceLayers);
  const presentationProfileIds = new Set(presentationProfiles.map((profile) => profile.id));
  if (dataProductBindings.some((binding) => binding.presentationProfileId && !presentationProfileIds.has(binding.presentationProfileId))) {
    throw applicationError("map_data_product_presentation_profile_not_found");
  }
  const subjectDetailProfilesById = new Map(subjectDetailProfiles.map((profile) => [profile.id, profile]));
  const bindingsById = new Map(dataProductBindings.map((binding) => [binding.id, binding]));
  for (const binding of dataProductBindings) {
    const detailProfile = binding.subjectDetailProfileId
      ? subjectDetailProfilesById.get(binding.subjectDetailProfileId)
      : null;
    if (binding.subjectDetailProfileId && !detailProfile) throw applicationError("map_data_product_subject_detail_profile_not_found");
    if (detailProfile && !binding.semanticTypes.some((semanticType) => detailProfile.semanticTypes.includes(semanticType))) {
      throw applicationError("map_data_product_subject_detail_profile_semantic_type_mismatch");
    }
    if (binding.joinToBindingId) {
      if (binding.joinToBindingId === binding.id || !bindingsById.has(binding.joinToBindingId)) {
        throw applicationError("map_data_product_join_binding_not_found");
      }
      if (binding.subjectDetailProfileId) throw applicationError("map_data_product_joined_binding_owns_detail_profile");
    }
  }
  for (const primary of dataProductBindings.filter((binding) => !binding.joinToBindingId)) {
    const composition = [
      primary,
      ...dataProductBindings.filter((binding) => binding.joinToBindingId === primary.id),
    ];
    const aspectIds = composition.map((binding) => binding.aspectId);
    if (new Set(aspectIds).size !== aspectIds.length) throw applicationError("duplicate_map_data_product_aspect_id");
    const detailProfile = primary.subjectDetailProfileId
      ? subjectDetailProfilesById.get(primary.subjectDetailProfileId)
      : null;
    if (!detailProfile) continue;
    const aspectsById = new Map(composition.map((binding) => [binding.aspectId, binding]));
    const detailFields = detailProfile.tabs.flatMap(
      (tab) => tab.sections.flatMap((section) => section.fields),
    );
    for (const field of detailFields) {
      const aspect = aspectsById.get(field.aspectId);
      if (!aspect) throw applicationError("map_subject_detail_profile_aspect_not_found");
      if (field.dataClass !== aspect.dataClass) {
        throw applicationError("map_subject_detail_profile_data_class_mismatch");
      }
    }
  }
  return {
    schemaVersion: 1,
    pageId: "map",
    settings: { ...settings, cacheNoOverwrite: settings.cacheNoOverwrite ?? true },
    mapHeight: requireInteger(value.mapHeight, 360, 5000, "invalid_map_page_height"),
    camera: {
      longitude: camera.longitude,
      latitude: camera.latitude,
      height: camera.height,
      heading: camera.heading,
      pitch: camera.pitch,
      roll: camera.roll,
    },
    pinBindings: validateMapPinBindings(value.pinBindings === undefined ? [] : value.pinBindings),
    presentationProfiles,
    subjectDetailProfiles,
    dataProductBindings,
    subjectStates,
    referenceLayers,
    inspectorOpenSections: validateMapInspectorOpenSections(
      value.inspectorOpenSections === undefined ? ["map-base"] : value.inspectorOpenSections,
    ),
  };
}

function validateMapDesignOverrides(value) {
  if (!isObject(value)) throw applicationError("invalid_map_design_overrides");
  if (Object.keys(value).some((key) => !["settings", "presentationProfiles"].includes(key))) {
    throw applicationError("invalid_map_design_override_field");
  }
  const result = {};
  if (value.settings !== undefined) {
    if (!isObject(value.settings) || Object.keys(value.settings).some((key) => !MAP_PAGE_SETTING_KEYS.has(key))) {
      throw applicationError("invalid_map_design_override_settings");
    }
    const defaults = defaultMapPageLayout();
    const normalized = validateMapPageLayout({
      ...defaults,
      settings: { ...defaults.settings, ...value.settings },
    }).settings;
    result.settings = Object.fromEntries(Object.keys(value.settings).map((key) => [key, normalized[key]]));
  }
  if (value.presentationProfiles !== undefined) {
    result.presentationProfiles = normalizeMapPresentationProfiles(value.presentationProfiles);
  }
  return result;
}

function defaultMapPageLayout() {
  return {
    schemaVersion: 1,
    pageId: "map",
    settings: {
      imagerySource: "cesium-live",
      imageryVisible: true,
      cacheEnabled: true,
      cacheNoOverwrite: true,
      terrainEnabled: true,
      terrainExaggeration: 1,
      monochrome: false,
      monochromeColor: "#15151b",
      imageryGamma: 57,
      imageryHue: 13,
      imageryAlpha: 27,
      globeColor: "#15151b",
      backgroundColor: "#08090d",
      atmosphereEnabled: false,
      atmosphereHue: 0,
      atmosphereSaturation: 0,
      atmosphereBrightness: 0,
      fogEnabled: true,
      fogDensity: 2,
      sunEnabled: true,
      sunHour: 12,
      sunIntensity: 200,
      shadowsEnabled: true,
      buildingsVisible: true,
      buildingsColor: "#a27aff",
      buildingsOpacity: 1,
      buildingsDetail: 4,
      imageryBrightness: 118,
      imageryContrast: 102,
      imagerySaturation: 0,
      gridVisible: true,
      gridLodEnabled: true,
      gridHeightMeters: 500,
      gridLod1MaxHeightKm: 10,
      gridLod1StepKm: 1,
      gridLod2MaxHeightKm: 50,
      gridLod2StepKm: 5,
      gridLod3StepKm: 25,
      gridRadiusKm: 40,
      gridLineWidth: 4,
      gridColor: "#f5f5f5",
      gridOpacity: 12,
      gridDotsEnabled: true,
      gridDotsSize: 7,
      gridDotsColor: "#ffffff",
      gridDotsOpacity: 58,
    },
    mapHeight: 470,
    camera: {
      longitude: 37.618423,
      latitude: 55.751244,
      height: 40000,
      heading: 0,
      pitch: -0.9,
      roll: 0,
    },
    pinBindings: [],
    presentationProfiles: structuredClone(canonicalMapPresentationProfiles),
    subjectDetailProfiles: structuredClone(canonicalMapSubjectDetailProfiles),
    dataProductBindings: [],
    subjectStates: [],
    referenceLayers: structuredClone(canonicalMapReferenceLayers),
    inspectorOpenSections: ["map-base"],
  };
}

function validateMaterial(value, theme) {
  if (!isObject(value)) throw applicationError(`invalid_${theme}_material`);
  return {
    panelHex: requireHex(value.panelHex, `invalid_${theme}_panel_color`),
    panelOpacity: requireNumber(value.panelOpacity, 0, 100, `invalid_${theme}_panel_opacity`),
    fieldHex: requireHex(value.fieldHex, `invalid_${theme}_field_color`),
    fieldOpacity: requireNumber(value.fieldOpacity, 0, 100, `invalid_${theme}_field_opacity`),
    nestedHex: requireHex(value.nestedHex, `invalid_${theme}_nested_color`),
  };
}

function validateDesignProfileLayout(value) {
  if (!isObject(value)) throw applicationError("invalid_design_profile_layout");
  if (value.theme !== "dark" && value.theme !== "light") throw applicationError("invalid_design_profile_theme");
  if (!isObject(value.materialByTheme) || !isObject(value.environment) || !isObject(value.media) || !isObject(value.glass) || !isObject(value.toolbar)) {
    throw applicationError("incomplete_design_profile_layout");
  }
  const environment = value.environment;
  const media = value.media;
  const glass = value.glass;
  const toolbar = value.toolbar;
  if (media.source !== "file" && media.source !== "url") throw applicationError("invalid_design_profile_media_source");
  if (media.logoSource !== "file" && media.logoSource !== "url") throw applicationError("invalid_design_profile_logo_source");
  if (!isObject(media.faviconAssets)) throw applicationError("invalid_design_profile_favicon_assets");
  if (glass.version !== 4) throw applicationError("unsupported_glass_material_version");
  if (!["left", "right", "bottom"].includes(toolbar.placement)) throw applicationError("invalid_toolbar_placement");
  return {
    theme: value.theme,
    accentHex: requireHex(value.accentHex, "invalid_design_profile_accent"),
    materialByTheme: {
      dark: validateMaterial(value.materialByTheme.dark, "dark"),
      light: validateMaterial(value.materialByTheme.light, "light"),
    },
    environment: {
      lightColor: requireHex(environment.lightColor, "invalid_environment_light_color"),
      brightness: requireNumber(environment.brightness, 0, 100, "invalid_environment_brightness"),
      glowDistance: requireNumber(environment.glowDistance, 0, 500, "invalid_environment_glow_distance"),
      connectionType: requireString(environment.connectionType, "invalid_environment_connection_type", 64),
      connectionColor: requireHex(environment.connectionColor, "invalid_environment_connection_color"),
      usePortColors: requireBoolean(environment.usePortColors, "invalid_environment_use_port_colors"),
      fillColor: requireHex(environment.fillColor, "invalid_environment_fill_color"),
      fillOpacity: requireNumber(environment.fillOpacity, 0, 100, "invalid_environment_fill_opacity"),
      strokeColor: requireHex(environment.strokeColor, "invalid_environment_stroke_color"),
      strokeOpacity: requireNumber(environment.strokeOpacity, 0, 100, "invalid_environment_stroke_opacity"),
    },
    media: {
      source: media.source,
      url: requireString(media.url, "invalid_design_profile_media_url"),
      fileName: requireString(media.fileName, "invalid_design_profile_media_file_name", 255),
      fileSrc: requireString(media.fileSrc, "invalid_design_profile_media_file_src"),
      visible: requireBoolean(media.visible, "invalid_design_profile_media_visibility"),
      logoSource: media.logoSource,
      logoUrl: requireString(media.logoUrl, "invalid_design_profile_logo_url"),
      logoFileName: requireString(media.logoFileName, "invalid_design_profile_logo_file_name", 255),
      logoFileSrc: requireString(media.logoFileSrc, "invalid_design_profile_logo_file_src"),
      faviconFileName: requireString(media.faviconFileName, "invalid_design_profile_favicon_file_name", 255),
      faviconAssets: {
        ico: requireNonEmptyString(media.faviconAssets.ico, "invalid_design_profile_favicon_ico"),
        apple: requireNonEmptyString(media.faviconAssets.apple, "invalid_design_profile_favicon_apple"),
        icon192: requireNonEmptyString(media.faviconAssets.icon192, "invalid_design_profile_favicon_192"),
        icon512: requireNonEmptyString(media.faviconAssets.icon512, "invalid_design_profile_favicon_512"),
      },
    },
    glass: {
      version: 4,
      tintHex: requireHex(glass.tintHex, "invalid_glass_tint"),
      tintOpacity: requireNumber(glass.tintOpacity, 0, 100, "invalid_glass_tint_opacity"),
      blur: requireNumber(glass.blur, 0, 120, "invalid_glass_blur"),
      saturation: requireNumber(glass.saturation, 0, 300, "invalid_glass_saturation"),
      brightness: requireNumber(glass.brightness, 0, 200, "invalid_glass_brightness"),
      outlineOpacity: requireNumber(glass.outlineOpacity, 0, 100, "invalid_glass_outline_opacity"),
      shadowOpacity: requireNumber(glass.shadowOpacity, 0, 100, "invalid_glass_shadow_opacity"),
    },
    toolbar: {
      placement: toolbar.placement,
      background: requireHex(toolbar.background, "invalid_toolbar_background"),
      border: requireHex(toolbar.border, "invalid_toolbar_border"),
      outline: requireHex(toolbar.outline, "invalid_toolbar_outline"),
      minSize: requireNumber(toolbar.minSize, 16, 64, "invalid_toolbar_min_size"),
      maxSize: requireNumber(toolbar.maxSize, 32, 160, "invalid_toolbar_max_size"),
      lensCount: requireInteger(toolbar.lensCount, 1, 12, "invalid_toolbar_lens_count"),
      autoHide: requireBoolean(toolbar.autoHide, "invalid_toolbar_auto_hide"),
    },
    pageTypes: validateDesignProfilePageTypes(value.pageTypes),
  };
}

function validateDesignProfilePageTypes(value) {
  // Profiles and immutable releases created before page-type fragments were
  // introduced inherit the registered provider-neutral Map design default.
  if (value === undefined) return defaultDesignProfilePageTypes();
  if (!isObject(value) || Object.keys(value).length > 64) throw applicationError("invalid_design_profile_page_types");
  const pageTypes = {};
  for (const [key, fragment] of Object.entries(value)) {
    if (!isObject(fragment) || fragment.schemaVersion !== 1) throw applicationError("invalid_design_profile_page_fragment");
    if (Object.keys(fragment).some((field) => !["schemaVersion", "templateId", "templateVersion", "settings", "presentationProfiles"].includes(field))) {
      throw applicationError("design_profile_page_fragment_contains_runtime");
    }
    const templateId = requireNonEmptyString(fragment.templateId, "invalid_design_profile_page_template_id", 80);
    const templateVersion = requireNonEmptyString(fragment.templateVersion, "invalid_design_profile_page_template_version", 32);
    if (key !== `${templateId}@${templateVersion}`) throw applicationError("invalid_design_profile_page_fragment_key");
    const template = findPageTemplate(templateId, templateVersion);
    if (!template) throw applicationError("unknown_design_profile_page_template");
    if (templateId !== "map") throw applicationError("unsupported_design_profile_page_template");
    const defaults = defaultMapPageLayout();
    const normalized = validateMapPageLayout({
      ...defaults,
      settings: fragment.settings,
      presentationProfiles: fragment.presentationProfiles,
      pinBindings: [],
      dataProductBindings: [],
    });
    pageTypes[key] = {
      schemaVersion: 1,
      templateId: "map",
      templateVersion,
      settings: normalized.settings,
      presentationProfiles: normalized.presentationProfiles,
    };
  }
  return pageTypes;
}

function defaultDesignProfilePageTypes() {
  const mapLayout = defaultMapPageLayout();
  return {
    "map@0.1.0": {
      schemaVersion: 1,
      templateId: "map",
      templateVersion: "0.1.0",
      settings: mapLayout.settings,
      presentationProfiles: mapLayout.presentationProfiles,
    },
  };
}

function validateDesignProfile(value) {
  if (!value || typeof value !== "object" || Array.isArray(value)) throw applicationError("invalid_design_profile");
  if (value.schemaVersion !== "0.1.0") throw applicationError("unsupported_design_profile_schema");
  if (value.id !== "default" && !/^[0-9a-f-]{36}$/i.test(String(value.id || ""))) throw applicationError("invalid_design_profile_id");
  const name = String(value.name || "").trim();
  if (!name || name.length > 120) throw applicationError("invalid_design_profile_name");
  if (!/^\d+\.\d+\.\d+$/.test(String(value.version || ""))) throw applicationError("invalid_design_profile_version");
  if (value.status !== "draft" && value.status !== "published") throw applicationError("invalid_design_profile_status");
  if (!isObject(value.timestamps) || !value.timestamps.createdAt || !value.timestamps.updatedAt) throw applicationError("invalid_design_profile_timestamps");
  if (value.status === "published" && !value.timestamps.publishedAt) throw applicationError("missing_design_profile_published_at");
  return { ...value, name, layout: validateDesignProfileLayout(value.layout) };
}

function defaultDesignProfileLayout() {
  return {
    theme: "dark",
    accentHex: "#ff2f92",
    materialByTheme: {
      dark: { panelHex: "#151517", panelOpacity: 100, fieldHex: "#2a2a2c", fieldOpacity: 100, nestedHex: "#0b0b0d" },
      light: { panelHex: "#ffffff", panelOpacity: 100, fieldHex: "#ffffff", fieldOpacity: 100, nestedHex: "#f4f4f4" },
    },
    environment: {
      lightColor: "#ff2f92",
      brightness: 49,
      glowDistance: 105,
      connectionType: "spline",
      connectionColor: "#404040",
      usePortColors: false,
      fillColor: "#ff6caf",
      fillOpacity: 100,
      strokeColor: "#2b2b36",
      strokeOpacity: 100,
    },
    media: {
      source: "file",
      url: "",
      fileName: "possible shapes.mp4",
      fileSrc: "/uploads/1783715822132-possible-shapes.mp4",
      visible: true,
      logoSource: "file",
      logoUrl: "",
      logoFileName: "nodedc-mark.svg",
      logoFileSrc: "/nodedc-mark.svg",
      faviconFileName: "icon-adaptive.svg",
      faviconAssets: {
        ico: "/favicon/favicon.ico",
        apple: "/favicon/apple-touch-icon.png",
        icon192: "/favicon/icon-192.png",
        icon512: "/favicon/icon-512.png",
      },
    },
    glass: {
      version: 4,
      tintHex: "#0b0b0e",
      tintOpacity: 94,
      blur: 62,
      saturation: 170,
      brightness: 129,
      outlineOpacity: 11,
      shadowOpacity: 88,
    },
    toolbar: {
      placement: "bottom",
      background: "#111115",
      border: "#111117",
      outline: "#1c1c1c",
      minSize: 25,
      maxSize: 78,
      lensCount: 3,
      autoHide: true,
    },
    pageTypes: defaultDesignProfilePageTypes(),
  };
}

async function ensureDefaultDesignProfile() {
  try {
    await readFile(designProfilePath("default"), "utf8");
  } catch (error) {
    if (error?.code !== "ENOENT") throw error;
    let layout = defaultDesignProfileLayout();
    try { layout = JSON.parse(await readFile(layoutPath, "utf8")); } catch (layoutError) { if (layoutError?.code !== "ENOENT") throw layoutError; }
    const now = new Date().toISOString();
    await writeFile(designProfilePath("default"), `${JSON.stringify({
      schemaVersion: "0.1.0",
      id: "default",
      name: "NODE.DC Default",
      version: "0.6.0",
      status: "draft",
      layout,
      timestamps: { createdAt: now, updatedAt: now },
    }, null, 2)}\n`, "utf8");
  }
}

await ensureDefaultDesignProfile();

async function writeDesignProfile(profile) {
  const targetPath = designProfilePath(profile.id);
  const tempPath = `${targetPath}.${randomUUID()}.tmp`;
  await writeFile(tempPath, `${JSON.stringify(profile, null, 2)}\n`, "utf8");
  await rename(tempPath, targetPath);
}

async function writeDesignProfileRelease(profile) {
  const release = validateDesignProfile({
    ...profile,
    status: "published",
    timestamps: { ...profile.timestamps, publishedAt: new Date().toISOString() },
  });
  await mkdir(designProfileReleaseDir(release.id), { recursive: true });
  try {
    await writeFile(designProfileReleasePath(release.id, release.version), `${JSON.stringify(release, null, 2)}\n`, { encoding: "utf8", flag: "wx" });
  } catch (error) {
    if (error?.code === "EEXIST") throw applicationError("design_profile_version_already_published", 409);
    throw error;
  }
  return release;
}

async function readDesignProfileReleases(id) {
  const releases = [];
  try {
    for (const entry of await readdir(designProfileReleaseDir(id), { withFileTypes: true })) {
      if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
      try { releases.push(validateDesignProfile(JSON.parse(await readFile(join(designProfileReleaseDir(id), entry.name), "utf8")))); } catch { /* skip damaged immutable snapshot */ }
    }
  } catch (error) {
    if (error?.code !== "ENOENT") throw error;
  }
  return releases.sort((left, right) => String(right.version).localeCompare(String(left.version), undefined, { numeric: true }));
}

async function ensureDefaultDesignProfileRelease() {
  const profile = validateDesignProfile(JSON.parse(await readFile(designProfilePath("default"), "utf8")));
  try { await readFile(designProfileReleasePath(profile.id, profile.version), "utf8"); }
  catch (error) { if (error?.code === "ENOENT") await writeDesignProfileRelease(profile); else throw error; }
}

await ensureDefaultDesignProfileRelease();

function designProfileVersionSummary(profile) {
  return { version: profile.version, status: profile.status, theme: profile.layout.theme, publishedAt: profile.timestamps.publishedAt };
}

function designProfileSummary(profile, releases = []) {
  return {
    id: profile.id,
    name: profile.name,
    version: profile.version,
    status: profile.status,
    theme: profile.layout.theme,
    updatedAt: profile.timestamps.updatedAt,
    versions: releases.map(designProfileVersionSummary),
    latestPublishedVersion: releases[0]?.version ?? null,
  };
}

function nextPatchVersion(version) {
  const match = String(version || "0.1.0").match(/^(\d+)\.(\d+)\.(\d+)$/);
  return match ? `${match[1]}.${match[2]}.${Number(match[3]) + 1}` : "0.1.0";
}

function validateApplicationManifest(value) {
  if (!value || typeof value !== "object" || Array.isArray(value)) throw applicationError("invalid_application_manifest");
  if (value.schemaVersion !== "0.1.0") throw applicationError("unsupported_application_schema");
  if (!/^[0-9a-f-]{36}$/i.test(String(value.id || ""))) throw applicationError("invalid_application_id");
  if (value.status !== "draft") throw applicationError("invalid_application_status");
  if (!/^0\.\d+\.\d+$/.test(String(value.version || ""))) throw applicationError("invalid_application_version");
  if (!value.metadata || typeof value.metadata !== "object") throw applicationError("invalid_application_metadata");
  const name = String(value.metadata.name || "").trim();
  const slug = normalizeSlug(value.metadata.slug);
  if (!name || name.length > 120) throw applicationError("invalid_application_name");
  if (!slug) throw applicationError("invalid_application_slug");
  if (!value.designProfile || typeof value.designProfile !== "object") throw applicationError("invalid_design_profile");
  // Pre-versioning manifests already represented the stable default 0.6.0 snapshot.
  const designProfileStatus = value.designProfile.status === "draft" ? "draft" : "published";
  if (value.designProfile.theme !== "dark" && value.designProfile.theme !== "light") throw applicationError("invalid_application_theme");
  if (!Array.isArray(value.pages)) throw applicationError("invalid_application_pages");
  const pageIds = new Set();
  const normalizedPages = [];
  for (const page of value.pages) {
    if (!page || typeof page !== "object") throw applicationError("invalid_application_page");
    const pageId = String(page.id || "").trim();
    if (!/^[a-z0-9-]+$/.test(pageId) || pageIds.has(pageId)) throw applicationError("invalid_application_page_id");
    pageIds.add(pageId);
    if (!page.template || typeof page.template !== "object" || !String(page.template.id || "").trim()) {
      throw applicationError("invalid_application_page_template");
    }
    const template = findPageTemplate(String(page.template.id), String(page.template.version || ""));
    if (!template) throw applicationError("unknown_application_page_template");
    if (!page.navigation || typeof page.navigation.visible !== "boolean") throw applicationError("invalid_application_navigation");
    if (!page.features || typeof page.features !== "object" || Array.isArray(page.features)) throw applicationError("invalid_application_features");
    let normalizedPage = page;
    if (page.layout !== undefined) {
      if (!isObject(page.layout)) throw applicationError("invalid_application_page_layout");
      if (page.template.id === "map" && page.layout.map !== undefined) {
        normalizedPage = {
          ...page,
          layout: { ...page.layout, map: validateMapPageLayout(page.layout.map) },
        };
      }
    }
    if (page.designOverrides !== undefined) {
      if (!isObject(page.designOverrides) || Object.keys(page.designOverrides).some((key) => key !== "map")) {
        throw applicationError("invalid_application_page_design_overrides");
      }
      if (page.designOverrides.map !== undefined) {
        if (page.template.id !== "map") throw applicationError("unsupported_application_page_design_overrides");
        normalizedPage = {
          ...normalizedPage,
          designOverrides: { map: validateMapDesignOverrides(page.designOverrides.map) },
        };
      }
    }
    const allowedFeatures = new Set(template.features.map((feature) => feature.id));
    if (Object.keys(page.features).some((feature) => !allowedFeatures.has(feature))) throw applicationError("unsupported_application_feature");
    for (const feature of template.features) {
      if (feature.required && page.features[feature.id] !== true) throw applicationError("required_application_feature_disabled");
    }
    normalizedPages.push(normalizedPage);
  }
  return {
    ...value,
    pages: normalizedPages,
    designProfile: { ...value.designProfile, status: designProfileStatus },
    metadata: {
      ...value.metadata,
      name,
      slug,
      description: String(value.metadata.description || "").slice(0, 500),
    },
  };
}

function createApplicationManifest(input = {}) {
  const templateId = String(input?.templateId || "").trim();
  const templateVersion = String(input?.templateVersion || "").trim() || undefined;
  const template = templateId ? findPageTemplate(templateId, templateVersion) : null;
  if (templateId && !template) throw applicationError("unknown_page_template");
  const now = new Date().toISOString();
  const name = String(input?.name || (template ? `NODE.DC ${template.title} Demo` : "Новый модуль")).trim() || "Новый модуль";
  const slug = normalizeSlug(input?.slug || name) || "nodedc-map-demo";
  return {
    schemaVersion: "0.1.0",
    id: randomUUID(),
    status: "draft",
    version: "0.1.0",
    metadata: {
      name,
      slug,
      description: String(input?.description || "Черновик NDC Module Foundry."),
    },
    designProfile: {
      id: "default",
      version: "0.6.0",
      status: "published",
      theme: input?.theme === "light" ? "light" : "dark",
    },
    pages: template ? [{
      id: template.page.id,
      title: template.page.title,
      path: template.page.path,
      template: { id: template.id, version: template.version },
      navigation: { visible: true, label: template.page.navigationLabel, order: 0 },
      features: Object.fromEntries(template.features.map((feature) => [feature.id, feature.required ? true : feature.defaultVisible])),
    }] : [],
    favicon: {
      source: "design-profile",
    },
    timestamps: {
      createdAt: now,
      updatedAt: now,
    },
  };
}

async function writeApplicationManifest(manifest) {
  const targetPath = applicationPath(manifest.id);
  await writeJsonAtomically(targetPath, manifest);
}

async function writeJsonAtomically(targetPath, value) {
  const tempPath = `${targetPath}.${randomUUID()}.tmp`;
  await writeFile(tempPath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
  await rename(tempPath, targetPath);
}

async function readApplicationManifest(id) {
  try {
    return validateApplicationManifest(JSON.parse(await readFile(applicationPath(id), "utf8")));
  } catch (error) {
    if (error?.code === "ENOENT") throw applicationError("application_not_found", 404);
    throw error;
  }
}

function runtimeTargetGrantKey(applicationId, pageId, bindingId) {
  return createHash("sha256").update(`${applicationId}/${pageId}/${bindingId}`, "utf8").digest("hex");
}

function isRuntimeIdentifier(value) {
  return typeof value === "string" && /^[A-Za-z0-9._:-]{1,160}$/.test(value);
}

function isRuntimeCursor(value) {
  return typeof value === "string" && /^(?:0|[1-9]\d*)$/.test(value);
}

function isRuntimeTimestamp(value) {
  return typeof value === "string" && !Number.isNaN(Date.parse(value));
}

function isRuntimeVersion(value) {
  return typeof value === "string" && /^\d+\.\d+\.\d+(?:[-+][a-z0-9.-]+)?$/i.test(value);
}

async function resolveRuntimeMapDataProductBinding(applicationId, pageId, bindingId) {
  const application = await readApplicationManifest(applicationId);
  const page = application.pages.find((candidate) => candidate.id === pageId);
  if (!page) throw applicationError("application_page_not_found", 404);
  if (page.template?.id !== "map") throw applicationError("map_page_required", 404);
  const template = findPageTemplate(page.template.id, page.template.version);
  const layout = validateMapPageLayout(page.layout?.map || defaultMapPageLayout());
  const binding = layout.dataProductBindings.find((candidate) => candidate.id === bindingId);
  if (!binding) throw applicationError("data_product_binding_not_found", 404);
  const slot = template?.slots?.find((candidate) => candidate.id === binding.slotId);
  if (!isMapLiveDataSlot(slot)) throw applicationError("map_live_data_slot_required", 409);
  return { application, page, binding };
}

async function resolveRuntimeDataProductReaderToken(applicationId, pageId, bindingId, generation = 1) {
  if (!externalDataPlaneInternalUrl || (!externalDataPlaneReaderGrantsDir && !foundryReaderGrantProvisioner.configured)) {
    throw applicationError("data_product_runtime_not_configured", 503);
  }
  const managedToken = await foundryReaderGrantProvisioner.readToken(
    { applicationId, pageId, bindingId },
    { generation },
  );
  if (managedToken) return managedToken;
  if (generation !== 1) throw applicationError("data_product_reader_grant_not_found", 403);
  if (!externalDataPlaneReaderGrantsDir) throw applicationError("data_product_reader_grant_not_found", 403);
  // Compatibility fallback for grants issued before Foundry-owned managed
  // provisioning. There is no fallback to one shared Platform token.
  const grantPath = join(resolve(externalDataPlaneReaderGrantsDir), runtimeTargetGrantKey(applicationId, pageId, bindingId));
  let handle;
  try {
    handle = await open(grantPath, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW || 0));
  } catch (error) {
    if (error?.code === "ENOENT") throw applicationError("data_product_reader_grant_not_found", 403);
    if (error?.code === "ELOOP") throw applicationError("data_product_reader_grant_invalid", 503);
    throw applicationError("data_product_reader_grant_unavailable", 503);
  }
  try {
    const metadata = await handle.stat();
    if (!metadata.isFile() || metadata.size < 2 || metadata.size > 1024 || (metadata.mode & 0o222) !== 0) {
      throw applicationError("data_product_reader_grant_invalid", 503);
    }
    // The production artifact mounts a root-owned, read-only secret
    // directory. Open the inode with O_NOFOLLOW and validate that same handle
    // before reading so an atomic rotation cannot become a symlink race.
    if (process.env.NODE_ENV === "production" && metadata.uid !== 0) {
      throw applicationError("data_product_reader_grant_invalid", 503);
    }
    let token;
    try {
      token = (await handle.readFile("utf8")).trim();
    } catch {
      throw applicationError("data_product_reader_grant_unavailable", 503);
    }
    if (!/^ndc_edprb_[A-Za-z0-9_-]{32,512}$/.test(token)) {
      throw applicationError("data_product_reader_grant_invalid", 503);
    }
    return token;
  } finally {
    await handle.close();
  }
}

async function preflightFoundryBindingReaderGrant({ applicationId, pageId, bindingId, dataProductId }) {
  let readerToken;
  try {
    let generation = 1;
    try {
      const statePath = join(foundryDataProductConsumersDir, `${runtimeTargetGrantKey(applicationId, pageId, bindingId)}.json`);
      const state = JSON.parse(await readFile(statePath, "utf8"));
      if (Number.isSafeInteger(state?.readerGrantGeneration) && state.readerGrantGeneration > 0) {
        generation = state.readerGrantGeneration;
      }
    } catch (error) {
      if (error?.code !== "ENOENT") throw error;
    }
    readerToken = await resolveRuntimeDataProductReaderToken(applicationId, pageId, bindingId, generation);
  } catch (error) {
    if (["data_product_reader_grant_not_found", "data_product_reader_grant_invalid"].includes(error?.message)) return false;
    throw error;
  }
  try {
    return Boolean(await readRuntimeReaderProduct(readerToken, dataProductId));
  } catch (error) {
    if (error?.message === "data_product_access_denied") return false;
    throw error;
  }
}

async function readRuntimeReaderProduct(readerToken, dataProductId) {
  let upstream;
  try {
    upstream = await fetch(new URL("/internal/data-plane/v1/reader/data-products", `${externalDataPlaneInternalUrl}/`), {
      headers: { authorization: `Bearer ${readerToken}`, accept: "application/json" },
      signal: AbortSignal.timeout(10_000),
    });
  } catch {
    throw applicationError("data_product_reader_grant_preflight_unavailable", 503);
  }
  if (upstream.status === 401 || upstream.status === 403) throw applicationError("data_product_access_denied", 403);
  if (!upstream.ok) throw applicationError("data_product_reader_grant_preflight_unavailable", 503);
  const payload = await upstream.json().catch(() => null);
  const product = Array.isArray(payload?.dataProducts)
    ? payload.dataProducts.find((candidate) => candidate?.id === dataProductId)
    : null;
  return product && product.active !== false && product.deliveryMode === "snapshot+patch" ? product : null;
}

async function inspectFoundryConsumerReaderGrant(target, { generation = 1 } = {}) {
  try {
    const readerToken = await resolveRuntimeDataProductReaderToken(
      target.application.id,
      target.page.id,
      target.binding.id,
      generation,
    );
    const product = await readRuntimeReaderProduct(readerToken, target.binding.dataProductId);
    if (product) return { product, readerGrantAction: "reuse", readerGrantGeneration: generation };
  } catch (error) {
    if (!new Set(["data_product_reader_grant_not_found", "data_product_access_denied"]).has(error?.message)) throw error;
  }
  if (!foundryReaderGrantProvisioner.configured) {
    throw applicationError("data_product_reader_grant_not_found", 403);
  }
  const planned = await foundryReaderGrantProvisioner.plan(target);
  return { product: planned.product, readerGrantAction: "ensure", readerGrantGeneration: generation };
}

function runtimePosition(value) {
  if (!Array.isArray(value) || value.length !== 2) return null;
  const [longitude, latitude] = value;
  if (
    typeof longitude !== "number"
    || !Number.isFinite(longitude)
    || longitude < -180
    || longitude > 180
    || typeof latitude !== "number"
    || !Number.isFinite(latitude)
    || latitude < -90
    || latitude > 90
  ) return null;
  return [longitude, latitude];
}

function runtimeLinearRing(value) {
  if (!Array.isArray(value) || value.length < 4 || value.length > 10_000) return null;
  const positions = value.map(runtimePosition);
  if (positions.some((position) => !position)) return null;
  const first = positions[0];
  const last = positions.at(-1);
  if (!last || first[0] !== last[0] || first[1] !== last[1]) return null;
  return positions;
}

function runtimePolygonCoordinates(value) {
  if (!Array.isArray(value) || value.length < 1 || value.length > 256) return null;
  const rings = value.map(runtimeLinearRing);
  return rings.some((ring) => !ring) ? null : rings;
}

function runtimeGeometry(value) {
  if (!isObject(value) || JSON.stringify(value).length > 196_608) return null;
  if (value.type === "Point") {
    const coordinates = runtimePosition(value.coordinates);
    return coordinates ? { type: "Point", coordinates } : null;
  }
  if (value.type === "Polygon") {
    const coordinates = runtimePolygonCoordinates(value.coordinates);
    return coordinates ? { type: "Polygon", coordinates } : null;
  }
  if (value.type === "MultiPolygon" && Array.isArray(value.coordinates) && value.coordinates.length >= 1 && value.coordinates.length <= 256) {
    const coordinates = value.coordinates.map(runtimePolygonCoordinates);
    return coordinates.some((polygon) => !polygon) ? null : { type: "MultiPolygon", coordinates };
  }
  return null;
}

const RUNTIME_SECRET_LIKE_KEY = /(token|secret|password|authorization|access[_-]?token|refresh[_-]?token|api[_-]?key)/i;

function safeRuntimeAttributeValue(value, depth = 0) {
  if (value === null || typeof value === "string" || typeof value === "boolean") return value;
  if (typeof value === "number" && Number.isFinite(value)) return value;
  if (depth >= 4) return null;
  if (Array.isArray(value)) return value.map((item) => safeRuntimeAttributeValue(item, depth + 1));
  if (!isObject(value)) return null;
  return Object.fromEntries(Object.entries(value)
    .filter(([key]) => !RUNTIME_SECRET_LIKE_KEY.test(key))
    .map(([key, item]) => [key, safeRuntimeAttributeValue(item, depth + 1)]));
}

function sanitizeRuntimeFact(value, binding) {
  if (!isObject(value)) return null;
  const sourceId = value.sourceId;
  const semanticType = value.semanticType;
  if (!isRuntimeIdentifier(sourceId) || !isRuntimeIdentifier(semanticType) || !binding.semanticTypes.includes(semanticType)) return null;
  if (!isRuntimeTimestamp(value.observedAt) || !isRuntimeTimestamp(value.receivedAt)) return null;
  const sourceAttributes = isObject(value.attributes) ? value.attributes : {};
  const allowedFields = new Set(binding.fieldProjection);
  const attributes = Object.fromEntries(Object.entries(sourceAttributes)
    .filter(([key]) => allowedFields.has(key) && !RUNTIME_SECRET_LIKE_KEY.test(key))
    .map(([key, item]) => [key, safeRuntimeAttributeValue(item)]));
  return {
    sourceId,
    semanticType,
    observedAt: value.observedAt,
    receivedAt: value.receivedAt,
    attributes,
    geometry: runtimeGeometry(value.geometry),
  };
}

function sanitizeRuntimeSnapshot(value, binding) {
  if (!isObject(value) || value.schemaVersion !== "nodedc.data-product.snapshot/v1" || !isObject(value.dataProduct)) {
    throw applicationError("data_product_snapshot_contract_invalid", 502);
  }
  if (value.dataProduct.id !== binding.dataProductId || !isRuntimeVersion(value.dataProduct.version) || !isRuntimeCursor(value.cursor) || !isRuntimeTimestamp(value.generatedAt) || !Array.isArray(value.facts)) {
    throw applicationError("data_product_snapshot_contract_invalid", 502);
  }
  return {
    schemaVersion: "nodedc.data-product.snapshot/v1",
    dataProduct: { id: binding.dataProductId, version: String(value.dataProduct.version || "") },
    generatedAt: value.generatedAt,
    cursor: value.cursor,
    facts: value.facts.map((fact) => sanitizeRuntimeFact(fact, binding)).filter(Boolean),
  };
}

function sanitizeRuntimeHistory(value, binding) {
  if (!isObject(value) || value.schemaVersion !== "nodedc.data-product.history/v1" || !isObject(value.dataProduct) || !isObject(value.query)) {
    throw applicationError("data_product_history_contract_invalid", 502);
  }
  const query = value.query;
  if (
    value.dataProduct.id !== binding.dataProductId
    || !isRuntimeVersion(value.dataProduct.version)
    || !isRuntimeTimestamp(value.generatedAt)
    || !isRuntimeTimestamp(query.from)
    || !isRuntimeTimestamp(query.to)
    || Date.parse(query.from) >= Date.parse(query.to)
    || !Number.isInteger(query.resolutionMs)
    || query.resolutionMs < 1000
    || query.resolutionMs > 86_400_000
    || query.order !== "asc"
    || !Array.isArray(query.sourceIds)
    || query.sourceIds.some((sourceId) => !isRuntimeIdentifier(sourceId))
    || JSON.stringify(query.sourceIds) !== JSON.stringify([...new Set(query.sourceIds)].sort())
    || !Array.isArray(value.facts)
    || (value.nextCursor !== undefined && (typeof value.nextCursor !== "string" || !/^[A-Za-z0-9_-]{1,1024}$/.test(value.nextCursor)))
  ) throw applicationError("data_product_history_contract_invalid", 502);
  let previousOrderKey = null;
  const facts = value.facts.flatMap((valueFact) => {
    if (
      !isRuntimeTimestamp(valueFact?.bucketStart)
      || Date.parse(valueFact.bucketStart) < Date.parse(query.from)
      || Date.parse(valueFact.bucketStart) >= Date.parse(query.to)
    ) throw applicationError("data_product_history_contract_invalid", 502);
    const orderKey = `${valueFact.bucketStart}\u0000${valueFact.sourceId}\u0000${valueFact.semanticType}`;
    if (previousOrderKey !== null && orderKey <= previousOrderKey) {
      throw applicationError("data_product_history_contract_invalid", 502);
    }
    previousOrderKey = orderKey;
    const fact = sanitizeRuntimeFact(valueFact, binding);
    return fact ? [{ ...fact, bucketStart: valueFact.bucketStart }] : [];
  });
  return {
    schemaVersion: "nodedc.data-product.history/v1",
    dataProduct: { id: binding.dataProductId, version: value.dataProduct.version },
    generatedAt: value.generatedAt,
    query: {
      from: query.from,
      to: query.to,
      resolutionMs: query.resolutionMs,
      sourceIds: [...query.sourceIds],
      order: "asc",
    },
    facts,
    ...(value.nextCursor ? { nextCursor: value.nextCursor } : {}),
  };
}

function sanitizeRuntimePatch(value, binding) {
  if (!isObject(value) || value.schemaVersion !== "nodedc.data-product.patch/v1" || !isObject(value.dataProduct)) return null;
  if (value.dataProduct.id !== binding.dataProductId || !isRuntimeVersion(value.dataProduct.version) || !isRuntimeCursor(value.cursor) || !isRuntimeCursor(value.previousCursor) || !isRuntimeTimestamp(value.emittedAt) || !Array.isArray(value.operations)) return null;
  const operations = value.operations.flatMap((operation) => {
    if (!isObject(operation)) return [];
    if (operation.op === "upsert") {
      const fact = sanitizeRuntimeFact(operation.fact, binding);
      return fact ? [{ op: "upsert", fact }] : [];
    }
    if (
      operation.op === "remove"
      && isRuntimeIdentifier(operation.sourceId)
      && isRuntimeIdentifier(operation.semanticType)
      && binding.semanticTypes.includes(operation.semanticType)
    ) {
      return [{
        op: "remove",
        sourceId: operation.sourceId,
        semanticType: operation.semanticType,
      }];
    }
    return [];
  });
  return {
    schemaVersion: "nodedc.data-product.patch/v1",
    dataProduct: { id: binding.dataProductId, version: String(value.dataProduct.version || "") },
    cursor: value.cursor,
    previousCursor: value.previousCursor,
    emittedAt: value.emittedAt,
    operations,
  };
}

function resolveDataProductConsumerPolicy(product) {
  if (dataProductConsumerPolicyRegistry?.schemaVersion !== "nodedc.foundry.data-product-consumer-policies/v1") {
    throw applicationError("data_product_consumer_policy_registry_invalid", 500);
  }
  return dataProductConsumerPolicyRegistry.policies?.find((policy) => (
    policy?.dataProductId === product.id && policy?.productVersion === product.version
  )) || null;
}

function runtimeUpstreamUrl(dataProductId, resource, after) {
  const target = new URL(`/internal/data-plane/v1/data-products/${encodeURIComponent(dataProductId)}/${resource}`, `${externalDataPlaneInternalUrl}/`);
  if (after) target.searchParams.set("after", after);
  return target;
}

function runtimeUpstreamFailure(status) {
  if (status === 401 || status === 403) return applicationError("data_product_access_denied", 403);
  if (status === 404) return applicationError("data_product_not_found", 404);
  if (status === 409) return applicationError("resync_required", 409);
  return applicationError("data_product_runtime_unavailable", 503);
}

function waitForResponseDrain(response) {
  return new Promise((resolve, reject) => {
    let settled = false;
    const settle = (result, error) => {
      if (settled) return;
      settled = true;
      response.off("drain", onDrain);
      response.off("close", onClose);
      response.off("error", onError);
      if (error) reject(error);
      else resolve(result);
    };
    const onDrain = () => settle(true);
    const onClose = () => settle(false);
    const onError = (error) => settle(false, error);
    response.once("drain", onDrain);
    response.once("close", onClose);
    response.once("error", onError);
    if (response.destroyed || response.writableEnded) settle(false);
  });
}

async function writeRuntimeStreamChunk(response, chunk) {
  if (response.destroyed || response.writableEnded) return false;
  try {
    if (response.write(chunk)) return true;
    return await waitForResponseDrain(response);
  } catch (error) {
    if (response.destroyed || response.writableEnded) return false;
    throw error;
  }
}

async function writeSse(response, { event, data, id }) {
  const frame = `${id ? `id: ${id}\n` : ""}event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
  return writeRuntimeStreamChunk(response, frame);
}

function openRuntimeDataProductConsumerStream({ url, token, signal }) {
  return new Promise((resolveStream, rejectStream) => {
    const transport = url.protocol === "https:" ? httpsRequest : url.protocol === "http:" ? httpRequest : null;
    if (!transport) return rejectStream(applicationError("data_product_runtime_url_invalid", 500));
    let incoming = null;
    let settled = false;
    const request = transport(url, {
      method: "GET",
      headers: {
        authorization: `Bearer ${token}`,
        accept: "text/event-stream",
        connection: "close",
      },
    });
    const abort = () => {
      incoming?.destroy();
      request.destroy();
    };
    signal.addEventListener("abort", abort, { once: true });
    request.once("response", (response) => {
      incoming = response;
      settled = true;
      response.once("close", () => signal.removeEventListener("abort", abort));
      resolveStream({
        status: response.statusCode || 500,
        ok: (response.statusCode || 500) >= 200 && (response.statusCode || 500) < 300,
        headers: new Headers(response.headers),
        body: Readable.toWeb(response),
      });
    });
    request.once("error", (error) => {
      signal.removeEventListener("abort", abort);
      if (!settled) rejectStream(signal.aborted ? applicationError("data_product_stream_closed", 503) : error);
    });
    if (signal.aborted) abort();
    else request.end();
  });
}

const dataProductConsumerManager = createFoundryDataProductConsumerManager({
  stateDir: foundryDataProductConsumersDir,
  dataPlaneUrl: externalDataPlaneInternalUrl,
  resolveTarget: resolveRuntimeMapDataProductBinding,
  readReaderToken: resolveRuntimeDataProductReaderToken,
  inspectReaderGrant: inspectFoundryConsumerReaderGrant,
  ensureReaderGrant: (target, options) => foundryReaderGrantProvisioner.ensure(target, options),
  revokeReaderGrant: (target, options) => foundryReaderGrantProvisioner.revoke(target, options),
  resolvePolicy: resolveDataProductConsumerPolicy,
  sanitizeSnapshot: sanitizeRuntimeSnapshot,
  sanitizePatch: sanitizeRuntimePatch,
  openStream: openRuntimeDataProductConsumerStream,
});
await dataProductConsumerManager.resumePersisted();

async function proxyRuntimeDataProductSnapshot(response, target) {
  json(response, 200, await dataProductConsumerManager.snapshot(target));
}

async function readRuntimeJsonResponse(upstream, maxBytes = 64 * 1024 * 1024) {
  const contentLength = Number(upstream.headers.get("content-length") || 0);
  if (Number.isFinite(contentLength) && contentLength > maxBytes) {
    throw applicationError("data_product_runtime_response_too_large", 502);
  }
  if (!upstream.body) throw applicationError("data_product_runtime_invalid_response", 502);
  const reader = upstream.body.getReader();
  const chunks = [];
  let bytes = 0;
  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      bytes += value.byteLength;
      if (bytes > maxBytes) {
        await reader.cancel();
        throw applicationError("data_product_runtime_response_too_large", 502);
      }
      chunks.push(Buffer.from(value));
    }
    return JSON.parse(Buffer.concat(chunks, bytes).toString("utf8"));
  } catch (error) {
    if (error?.statusCode) throw error;
    throw applicationError("data_product_runtime_invalid_response", 502);
  }
}

function runtimeHistoryQuery(url) {
  const from = String(url.searchParams.get("from") || "");
  const to = String(url.searchParams.get("to") || "");
  const resolutionMs = Number(url.searchParams.get("resolutionMs") || 60_000);
  const limit = Number(url.searchParams.get("limit") || 1000);
  const sourceIds = [...new Set(String(url.searchParams.get("sourceIds") || "").split(",").map((value) => value.trim()).filter(Boolean))];
  const cursor = String(url.searchParams.get("cursor") || "");
  if (
    !isRuntimeTimestamp(from)
    || !isRuntimeTimestamp(to)
    || Date.parse(from) >= Date.parse(to)
    || !Number.isInteger(resolutionMs)
    || resolutionMs < 1000
    || resolutionMs > 86_400_000
    || !Number.isInteger(limit)
    || limit < 1
    || limit > 5000
    || sourceIds.length > 1000
    || sourceIds.some((sourceId) => !isRuntimeIdentifier(sourceId))
    || (cursor && !/^[A-Za-z0-9_-]{1,1024}$/.test(cursor))
  ) throw applicationError("data_product_history_query_invalid", 400);
  return { from, to, resolutionMs, limit, sourceIds, cursor };
}

async function proxyRuntimeDataProductHistory(response, url, target) {
  const readerToken = await resolveRuntimeDataProductReaderToken(target.application.id, target.page.id, target.binding.id);
  const query = runtimeHistoryQuery(url);
  const upstreamUrl = runtimeUpstreamUrl(target.binding.dataProductId, "history");
  upstreamUrl.searchParams.set("from", query.from);
  upstreamUrl.searchParams.set("to", query.to);
  upstreamUrl.searchParams.set("resolutionMs", String(query.resolutionMs));
  upstreamUrl.searchParams.set("limit", String(query.limit));
  if (query.sourceIds.length) upstreamUrl.searchParams.set("sourceIds", query.sourceIds.join(","));
  if (query.cursor) upstreamUrl.searchParams.set("cursor", query.cursor);
  let upstream;
  try {
    upstream = await fetch(upstreamUrl, {
      headers: { authorization: `Bearer ${readerToken}`, accept: "application/json" },
      signal: AbortSignal.timeout(10_000),
    });
  } catch {
    throw applicationError("data_product_runtime_unavailable", 503);
  }
  if (!upstream.ok) throw runtimeUpstreamFailure(upstream.status);
  const payload = await readRuntimeJsonResponse(upstream);
  json(response, 200, sanitizeRuntimeHistory(payload, target.binding));
}

async function proxyRuntimeDataProductStream(request, response, url, target) {
  const requestedAfter = String(url.searchParams.get("after") || "");
  const lastEventId = String(request.headers["last-event-id"] || "");
  if (requestedAfter && !isRuntimeCursor(requestedAfter)) throw applicationError("stream_cursor_invalid");
  if (lastEventId && !isRuntimeCursor(lastEventId)) throw applicationError("stream_cursor_invalid");
  // EventSource preserves the original URL on an automatic reconnect while
  // adding Last-Event-ID. The latter is the authoritative acknowledged
  // cursor; using it avoids replaying a stale query-string cursor forever.
  const after = lastEventId || requestedAfter;
  const controller = new AbortController();
  let lease = null;
  let heartbeat = null;
  let headersReady = false;
  const bufferedEvents = [];
  let pendingEventCount = 0;
  let writeChain = Promise.resolve(true);
  const enqueue = (event) => {
    if (!headersReady) {
      bufferedEvents.push(event);
      return;
    }
    pendingEventCount += 1;
    if (pendingEventCount > 256) {
      abort();
      response.destroy();
      return;
    }
    writeChain = writeChain
      .then((open) => open && writeSse(response, event))
      .catch(() => false)
      .finally(() => { pendingEventCount = Math.max(0, pendingEventCount - 1); });
  };
  const abort = () => {
    if (!controller.signal.aborted) controller.abort();
    lease?.release();
  };
  const activeStream = { controller, response };
  activeRuntimeStreams.add(activeStream);
  request.once("aborted", abort);
  response.once("close", abort);
  request.socket?.once("close", abort);
  try {
    lease = await dataProductConsumerManager.subscribe({ ...target, after }, enqueue);
    response.writeHead(200, {
      "content-type": "text/event-stream; charset=utf-8",
      "cache-control": "no-store, no-transform",
      connection: "keep-alive",
      "x-accel-buffering": "no",
      vary: "Cookie",
    });
    headersReady = true;
    if (lease.resyncRequired) {
      await writeSse(response, {
        event: "nodedc.data-product.resync-required.v1",
        data: { schemaVersion: "nodedc.data-product.resync-required/v1", dataProductId: target.binding.dataProductId },
      });
      response.end();
      return;
    }
    for (const event of bufferedEvents.splice(0)) enqueue(event);
    heartbeat = setInterval(() => {
      writeChain = writeChain.then((open) => open && writeRuntimeStreamChunk(response, ": keepalive\n\n")).catch(() => false);
    }, 15_000);
    heartbeat.unref?.();
    await new Promise((resolve) => {
      if (controller.signal.aborted || response.destroyed) return resolve();
      controller.signal.addEventListener("abort", resolve, { once: true });
    });
  } finally {
    if (heartbeat) clearInterval(heartbeat);
    abort();
    activeRuntimeStreams.delete(activeStream);
    request.off("aborted", abort);
    response.off("close", abort);
    request.socket?.off("close", abort);
    if (!response.writableEnded && !response.destroyed) response.end();
  }
}

async function listApplicationManifests() {
  const manifests = [];
  for (const entry of await readdir(applicationsDir, { withFileTypes: true })) {
    if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
    try {
      manifests.push(validateApplicationManifest(JSON.parse(await readFile(join(applicationsDir, entry.name), "utf8"))));
    } catch {
      // A damaged draft must not make the complete Foundry project list unavailable.
    }
  }
  return manifests.sort((left, right) => String(right.timestamps.updatedAt).localeCompare(String(left.timestamps.updatedAt)));
}

function applicationSummary(manifest) {
  return {
    id: manifest.id,
    name: manifest.metadata.name,
    slug: manifest.metadata.slug,
    status: manifest.status,
    version: manifest.version,
    theme: manifest.designProfile.theme,
    pageCount: manifest.pages.length,
    updatedAt: manifest.timestamps.updatedAt,
  };
}

async function assertDesignProfileReference(reference) {
  if (!reference || typeof reference !== "object") throw applicationError("invalid_design_profile_reference");
  const profileId = String(reference.id || "");
  const version = String(reference.version || "");
  let profile;
  try {
    const sourcePath = reference.status === "published"
      ? designProfileReleasePath(profileId, version)
      : designProfilePath(profileId);
    profile = validateDesignProfile(JSON.parse(await readFile(sourcePath, "utf8")));
  } catch (error) {
    if (error?.code === "ENOENT") throw applicationError("design_profile_reference_not_found", 409);
    throw error;
  }
  if (profile.version !== version || profile.layout.theme !== reference.theme) {
    throw applicationError("design_profile_reference_mismatch", 409);
  }
  if (reference.status === "published" && profile.status !== "published") {
    throw applicationError("design_profile_reference_not_published", 409);
  }
  return profile;
}

function stringListEnv(name) {
  return String(process.env[name] || "")
    .split(",")
    .map((value) => value.trim())
    .filter(Boolean);
}

function foundryMcpConfig() {
  const publicUrl = String(process.env.FOUNDRY_PUBLIC_URL || "").trim().replace(/\/$/, "");
  const mcpUrl = String(process.env.FOUNDRY_MCP_URL || (publicUrl ? `${publicUrl}/api/mcp` : "")).trim();
  const internalAccessToken = String(process.env.NODEDC_INTERNAL_ACCESS_TOKEN || process.env.NODEDC_PLATFORM_SERVICE_TOKEN || "").trim();
  const requestedCapabilityTtlMs = Number(process.env.FOUNDRY_MCP_CAPABILITY_TTL_MS || 600_000);
  return {
    // The shared platform service credential never leaves a server process. It is used
    // only to authenticate the AI Workspace entitlement request and to sign a short-lived
    // Foundry MCP capability bound to the resolved actor and owner key.
    internalAccessToken,
    capabilitySecret: internalAccessToken,
    mcpCapabilityTtlMs: Number.isFinite(requestedCapabilityTtlMs)
      ? Math.min(Math.max(Math.trunc(requestedCapabilityTtlMs), 60_000), 3_600_000)
      : 600_000,
    mcpUrl,
    mcpAllowedOrigins: stringListEnv("FOUNDRY_MCP_ALLOWED_ORIGINS"),
    allowAllAuthenticated: String(process.env.FOUNDRY_ALLOW_ALL_AUTHENTICATED || "").trim().toLowerCase() === "true",
    // dcctouch@gmail.com is the platform superadmin (user_root). The group is also
    // provisioned through Authentik/Launcher as the canonical service access rule.
    allowedOwnerIds: stringListEnv("FOUNDRY_ALLOWED_OWNER_IDS").concat("user_root"),
    allowedOwnerGroups: stringListEnv("FOUNDRY_ALLOWED_OWNER_GROUPS")
      .concat("nodedc:superadmin", "nodedc:module-foundry:admin", "nodedc:module-foundry:user", "nodedc:module-foundry:access")
      .map((value) => value.toLowerCase()),
  };
}

function requiredMcpIdempotencyKey(value) {
  const key = requireNonEmptyString(value, "idempotency_key_required", 160);
  if (!/^[A-Za-z0-9._:-]+$/.test(key)) throw applicationError("invalid_idempotency_key");
  return key;
}

const foundryMcpInFlightOperations = new Map();

async function executeFoundryMcpWrite({ tool, actor, input, action }) {
  const idempotencyKey = requiredMcpIdempotencyKey(input.idempotencyKey);
  const actorId = requireNonEmptyString(actor?.actorId, "mcp_actor_context_required", 256);
  const ownerKey = requireNonEmptyString(actor?.ownerKey, "mcp_actor_context_required", 256);
  const inputForHash = { ...input };
  delete inputForHash.idempotencyKey;
  const inputHash = createHash("sha256").update(JSON.stringify(inputForHash)).digest("hex");
  const operationHash = createHash("sha256").update(`${tool}\n${ownerKey}\n${idempotencyKey}`).digest("hex");
  const path = join(foundryMcpOperationsDir, `${operationHash}.json`);
  const inFlight = foundryMcpInFlightOperations.get(operationHash);
  if (inFlight) return inFlight;
  const pending = (async () => {
    try {
      const recorded = JSON.parse(await readFile(path, "utf8"));
      if (recorded.tool !== tool || recorded.ownerKey !== ownerKey || recorded.inputHash !== inputHash) {
        throw applicationError("idempotency_key_reused", 409);
      }
      return { ...recorded.result, idempotency: { replayed: true } };
    } catch (error) {
      if (error?.code !== "ENOENT") throw error;
    }
    const result = await action();
    await writeJsonAtomically(path, {
      schemaVersion: "nodedc.module-foundry.mcp-operation.v1",
      tool,
      ownerKey,
      actorId,
      inputHash,
      completedAt: new Date().toISOString(),
      result,
    });
    return { ...result, idempotency: { replayed: false } };
  })();
  foundryMcpInFlightOperations.set(operationHash, pending);
  try {
    return await pending;
  } finally {
    foundryMcpInFlightOperations.delete(operationHash);
  }
}

function normalizeMcpPageTitle(value, fallback, code) {
  if (value === undefined) return fallback;
  const title = requireNonEmptyString(value, code, 120).trim();
  return title || fallback;
}

function nextPageInstance(manifest, input) {
  const templateId = requireNonEmptyString(input.templateId, "invalid_application_page_template", 64);
  const templateVersion = input.templateVersion === undefined ? undefined : requireNonEmptyString(input.templateVersion, "invalid_application_page_template_version", 64);
  const template = findPageTemplate(templateId, templateVersion);
  if (!template) throw applicationError("unknown_application_page_template");
  const suffix = randomUUID().slice(0, 8);
  const id = `${template.page.id}-${suffix}`;
  const maxOrder = manifest.pages.reduce((max, page) => Math.max(max, Number(page.navigation?.order ?? -1)), -1);
  return {
    id,
    title: normalizeMcpPageTitle(input.title, template.page.title, "invalid_application_page_title"),
    path: `${template.page.path.replace(/\/$/, "") || "/"}-${suffix}`.replace(/^\/-/, "/"),
    template: { id: template.id, version: template.version },
    navigation: {
      visible: true,
      label: normalizeMcpPageTitle(input.navigationLabel, template.page.navigationLabel, "invalid_application_page_navigation_label"),
      order: maxOrder + 1,
    },
    features: Object.fromEntries(template.features.map((feature) => [feature.id, feature.required ? true : feature.defaultVisible])),
  };
}

async function writeFoundryApplicationUpdate(applicationId, update) {
  const current = await readApplicationManifest(applicationId);
  const nextCandidate = await update(current);
  const next = validateApplicationManifest({
    ...nextCandidate,
    id: current.id,
    schemaVersion: current.schemaVersion,
    status: current.status,
    timestamps: {
      createdAt: current.timestamps.createdAt,
      updatedAt: new Date().toISOString(),
    },
  });
  await assertDesignProfileReference(next.designProfile);
  await writeApplicationManifest(next);
  return next;
}

const foundryMcpOperations = {
  async status() {
    const config = foundryMcpConfig();
    return {
      module: "NDC Module Foundry",
      schemaVersion: "nodedc.module-foundry.mcp.v0.6",
      status: config.capabilitySecret && config.mcpUrl ? "ready" : "configuration_required",
      canonicalPageLibrary: "read-only",
      applicationInstances: "read-write",
      destructiveApplicationDelete: false,
      supportedPageTemplates: pageRegistry.templates.map((template) => ({ id: template.id, version: template.version, title: template.title })),
      supportedActions: [
        "application.create",
        "application.metadata.update",
        "page-instance.create",
        "map-pin.upsert",
        "map-pin.remove",
        "map-presentation-profile.upsert",
        "map-subject-detail-profile.upsert",
        "map-page-settings.update",
        "map-page-view-state.save",
        "map-data-product.upsert",
        "map-data-product-consumer.plan",
        "map-data-product-consumer.apply",
        "map-data-product-consumer.status",
        "map-data-product-consumer.accept",
        "map-data-product-consumer.rollback",
      ],
      persistence: { runtimeDir: "persistent runtime volume required", idempotentWrites: true, dataProductConsumerState: true },
    };
  },
  async listApplications() {
    const manifests = await listApplicationManifests();
    return { applications: manifests.map(applicationSummary) };
  },
  async getApplication(applicationId) {
    return { application: await readApplicationManifest(applicationId) };
  },
  async createApplication(input, actor) {
    return executeFoundryMcpWrite({
      tool: "foundry_create_application",
      actor,
      input,
      action: async () => {
        const name = normalizeMcpPageTitle(input.name, "Новый модуль", "invalid_application_name");
        const manifest = validateApplicationManifest(createApplicationManifest({
          ...input,
          name,
          templateId: input.templateId || "map",
          description: input.description === undefined ? "Черновик NDC Module Foundry." : input.description,
        }));
        const collision = (await listApplicationManifests()).some((item) => item.metadata.slug === manifest.metadata.slug);
        if (collision) throw applicationError("application_slug_conflict", 409);
        await assertDesignProfileReference(manifest.designProfile);
        await writeApplicationManifest(manifest);
        return { application: manifest };
      },
    });
  },
  async updateApplicationMetadata(input, actor) {
    return executeFoundryMcpWrite({
      tool: "foundry_update_application_metadata",
      actor,
      input,
      action: async () => {
        const application = await writeFoundryApplicationUpdate(input.applicationId, async (current) => ({
          ...current,
          metadata: {
            ...current.metadata,
            ...(Object.hasOwn(input, "name") ? { name: normalizeMcpPageTitle(input.name, current.metadata.name, "invalid_application_name") } : {}),
            ...(Object.hasOwn(input, "slug") ? (() => {
              const slug = normalizeSlug(input.slug);
              if (!slug) throw applicationError("invalid_application_slug");
              return { slug };
            })() : {}),
            ...(Object.hasOwn(input, "description") ? { description: String(input.description || "").slice(0, 500) } : {}),
          },
        }));
        return { application };
      },
    });
  },
  async addPageInstance(input, actor) {
    return executeFoundryMcpWrite({
      tool: "foundry_add_page_instance",
      actor,
      input,
      action: async () => {
        const application = await writeFoundryApplicationUpdate(input.applicationId, async (current) => ({
          ...current,
          pages: [...current.pages, nextPageInstance(current, input)],
        }));
        return { application, page: application.pages.at(-1) };
      },
    });
  },
  async upsertMapPinBinding(input, actor) {
    return executeFoundryMcpWrite({
      tool: "foundry_upsert_map_pin_binding",
      actor,
      input,
      action: async () => {
        const binding = validateMapPinBinding(input.binding);
        let updatedPage = null;
        const application = await writeFoundryApplicationUpdate(input.applicationId, async (current) => ({
          ...current,
          pages: current.pages.map((page) => {
            if (page.id !== input.pageId) return page;
            if (page.template?.id !== "map") throw applicationError("map_page_required");
            const layout = validateMapPageLayout(page.layout?.map || defaultMapPageLayout());
            const pinBindings = layout.pinBindings.filter((item) => item.id !== binding.id);
            pinBindings.push(binding);
            updatedPage = {
              ...page,
              layout: { ...page.layout, map: { ...layout, pinBindings, savedAt: new Date().toISOString() } },
            };
            return updatedPage;
          }),
        }));
        if (!updatedPage) throw applicationError("application_page_not_found", 404);
        return { application, page: updatedPage, binding };
      },
    });
  },
  async removeMapPinBinding(input, actor) {
    return executeFoundryMcpWrite({
      tool: "foundry_remove_map_pin_binding",
      actor,
      input,
      action: async () => {
        const bindingId = requireNonEmptyString(input.bindingId, "invalid_map_pin_id", 128);
        if (!/^[A-Za-z0-9._:-]+$/.test(bindingId)) throw applicationError("invalid_map_pin_id");
        let updatedPage = null;
        let removed = false;
        const application = await writeFoundryApplicationUpdate(input.applicationId, async (current) => ({
          ...current,
          pages: current.pages.map((page) => {
            if (page.id !== input.pageId) return page;
            if (page.template?.id !== "map") throw applicationError("map_page_required");
            const layout = validateMapPageLayout(page.layout?.map || defaultMapPageLayout());
            const pinBindings = layout.pinBindings.filter((item) => item.id !== bindingId);
            removed = pinBindings.length !== layout.pinBindings.length;
            updatedPage = {
              ...page,
              layout: { ...page.layout, map: { ...layout, pinBindings, savedAt: new Date().toISOString() } },
            };
            return updatedPage;
          }),
        }));
        if (!updatedPage) throw applicationError("application_page_not_found", 404);
        return { application, page: updatedPage, bindingId, removed };
      },
    });
  },
  async upsertMapPresentationProfile(input, actor) {
    return executeFoundryMcpWrite({
      tool: "foundry_upsert_map_presentation_profile",
      actor,
      input,
      action: async () => {
        const profile = normalizeMapPresentationProfile(input.profile);
        let updatedPage = null;
        const application = await writeFoundryApplicationUpdate(input.applicationId, async (current) => ({
          ...current,
          pages: current.pages.map((page) => {
            if (page.id !== input.pageId) return page;
            if (page.template?.id !== "map") throw applicationError("map_page_required");
            const layout = validateMapPageLayout(page.layout?.map || defaultMapPageLayout());
            const presentationProfiles = layout.presentationProfiles.filter((item) => item.id !== profile.id);
            presentationProfiles.push(profile);
            updatedPage = {
              ...page,
              layout: { ...page.layout, map: validateMapPageLayout({
                ...layout,
                presentationProfiles,
                savedAt: new Date().toISOString(),
              }) },
              designOverrides: {
                ...page.designOverrides,
                map: {
                  ...page.designOverrides?.map,
                  presentationProfiles,
                },
              },
            };
            return updatedPage;
          }),
        }));
        if (!updatedPage) throw applicationError("application_page_not_found", 404);
        return { application, page: updatedPage, profile };
      },
    });
  },
  async upsertMapSubjectDetailProfile(input, actor) {
    return executeFoundryMcpWrite({
      tool: "foundry_upsert_map_subject_detail_profile",
      actor,
      input,
      action: async () => {
        const profile = normalizeMapSubjectDetailProfile(input.profile);
        let updatedPage = null;
        const application = await writeFoundryApplicationUpdate(input.applicationId, async (current) => ({
          ...current,
          pages: current.pages.map((page) => {
            if (page.id !== input.pageId) return page;
            if (page.template?.id !== "map") throw applicationError("map_page_required");
            const layout = validateMapPageLayout(page.layout?.map || defaultMapPageLayout());
            const subjectDetailProfiles = layout.subjectDetailProfiles.filter((item) => item.id !== profile.id);
            subjectDetailProfiles.push(profile);
            updatedPage = {
              ...page,
              layout: { ...page.layout, map: validateMapPageLayout({
                ...layout,
                subjectDetailProfiles,
                savedAt: new Date().toISOString(),
              }) },
            };
            return updatedPage;
          }),
        }));
        if (!updatedPage) throw applicationError("application_page_not_found", 404);
        return { application, page: updatedPage, profile };
      },
    });
  },
  async updateMapPageSettings(input, actor) {
    return executeFoundryMcpWrite({
      tool: "foundry_update_map_page_settings",
      actor,
      input,
      action: async () => {
        const settingsPatch = validateMapPageSettingsPatch(input.settings);
        let updatedPage = null;
        const application = await writeFoundryApplicationUpdate(input.applicationId, async (current) => ({
          ...current,
          pages: current.pages.map((page) => {
            if (page.id !== input.pageId) return page;
            if (page.template?.id !== "map") throw applicationError("map_page_required");
            const layout = validateMapPageLayout(page.layout?.map || defaultMapPageLayout());
            updatedPage = {
              ...page,
              layout: { ...page.layout, map: validateMapPageLayout({
                ...layout,
                settings: { ...layout.settings, ...settingsPatch },
              }) },
            };
            return updatedPage;
          }),
        }));
        if (!updatedPage) throw applicationError("application_page_not_found", 404);
        return { application, page: updatedPage, settings: updatedPage.layout.map.settings };
      },
    });
  },
  async saveMapPageViewState(input, actor) {
    return executeFoundryMcpWrite({
      tool: "foundry_save_map_page_view_state",
      actor,
      input,
      action: async () => {
        if (!isObject(input.viewState)) throw applicationError("invalid_map_page_view_state");
        let updatedPage = null;
        const application = await writeFoundryApplicationUpdate(input.applicationId, async (current) => ({
          ...current,
          pages: current.pages.map((page) => {
            if (page.id !== input.pageId) return page;
            if (page.template?.id !== "map") throw applicationError("map_page_required");
            const layout = validateMapPageLayout(page.layout?.map || defaultMapPageLayout());
            const settings = input.viewState.settings === undefined
              ? layout.settings
              : { ...layout.settings, ...validateMapPageSettingsPatch(input.viewState.settings) };
            updatedPage = {
              ...page,
              layout: { ...page.layout, map: validateMapPageLayout({
                ...layout,
                settings,
                mapHeight: input.viewState.mapHeight,
                camera: input.viewState.camera,
                subjectStates: input.viewState.subjectStates,
                inspectorOpenSections: input.viewState.inspectorOpenSections === undefined
                  ? layout.inspectorOpenSections
                  : input.viewState.inspectorOpenSections,
              }) },
            };
            return updatedPage;
          }),
        }));
        if (!updatedPage) throw applicationError("application_page_not_found", 404);
        return { application, page: updatedPage, viewState: {
          settings: updatedPage.layout.map.settings,
          mapHeight: updatedPage.layout.map.mapHeight,
          camera: updatedPage.layout.map.camera,
          subjectStates: updatedPage.layout.map.subjectStates,
          inspectorOpenSections: updatedPage.layout.map.inspectorOpenSections,
        } };
      },
    });
  },
  async upsertMapDataProductBinding(input, actor) {
    return executeFoundryMcpWrite({
      tool: "foundry_upsert_map_data_product_binding",
      actor,
      input,
      action: async () => {
        const binding = validateMapDataProductBinding(input.binding);
        let updatedPage = null;
        const application = await writeFoundryApplicationUpdate(input.applicationId, async (current) => ({
          ...current,
          pages: current.pages.map((page) => {
            if (page.id !== input.pageId) return page;
            if (page.template?.id !== "map") throw applicationError("map_page_required");
            const template = findPageTemplate(page.template.id, page.template.version);
            const slot = template?.slots?.find((candidate) => candidate.id === binding.slotId);
            if (!isMapLiveDataSlot(slot)) throw applicationError("map_live_data_slot_required");
            const layout = validateMapPageLayout(page.layout?.map || defaultMapPageLayout());
            const existingBinding = layout.dataProductBindings.find((item) => item.id === binding.id);
            const resolvedBinding = {
              ...existingBinding,
              ...binding,
              ...(!binding.presentationProfileId && existingBinding?.presentationProfileId
                ? { presentationProfileId: existingBinding.presentationProfileId }
                : {}),
            };
            if (resolvedBinding.presentationProfileId && !layout.presentationProfiles.some((profile) => profile.id === resolvedBinding.presentationProfileId)) {
              throw applicationError("map_data_product_presentation_profile_not_found");
            }
            const dataProductBindings = layout.dataProductBindings.filter((item) => item.id !== binding.id);
            dataProductBindings.push(resolvedBinding);
            updatedPage = {
              ...page,
              layout: { ...page.layout, map: validateMapPageLayout({
                ...layout,
                dataProductBindings,
                savedAt: new Date().toISOString(),
              }) },
            };
            return updatedPage;
          }),
        }));
        if (!updatedPage) throw applicationError("application_page_not_found", 404);
        return {
          application,
          page: updatedPage,
          binding: updatedPage.layout.map.dataProductBindings.find((item) => item.id === binding.id),
        };
      },
    });
  },
  async planMapDataProductConsumer(input) {
    return dataProductConsumerManager.plan(input);
  },
  async applyMapDataProductConsumer(input, actor) {
    return executeFoundryMcpWrite({
      tool: "foundry_apply_map_data_product_consumer",
      actor,
      input,
      action: () => dataProductConsumerManager.apply(input),
    });
  },
  async getMapDataProductConsumerStatus(input) {
    return dataProductConsumerManager.status(input);
  },
  async acceptMapDataProductConsumer(input) {
    return dataProductConsumerManager.accept(input);
  },
  async rollbackMapDataProductConsumer(input, actor) {
    return executeFoundryMcpWrite({
      tool: "foundry_rollback_map_data_product_consumer",
      actor,
      input,
      action: () => dataProductConsumerManager.rollback(input),
    });
  },
};

async function readJsonBody(request, maxBytes = 2 * 1024 * 1024) {
  const chunks = [];
  let size = 0;
  for await (const chunk of request) {
    size += chunk.length;
    if (size > maxBytes) throw new Error("payload_too_large");
    chunks.push(chunk);
  }
  return JSON.parse(Buffer.concat(chunks).toString("utf8"));
}

function safeUploadName(name, contentType = "") {
  const allowed = new Set([".gif", ".ico", ".jpeg", ".jpg", ".m4v", ".mov", ".mp4", ".png", ".webm", ".webp"]);
  const contentTypeExtensions = {
    "image/gif": ".gif",
    "image/x-icon": ".ico",
    "image/jpeg": ".jpg",
    "image/png": ".png",
    "image/webp": ".webp",
    "video/mp4": ".mp4",
    "video/quicktime": ".mov",
    "video/webm": ".webm",
  };
  const requestedExtension = extname(name).toLowerCase();
  const extension = allowed.has(requestedExtension) ? requestedExtension : contentTypeExtensions[contentType] || ".bin";
  const stem = name.replace(/\.[^.]+$/, "").replace(/[^a-z0-9_-]+/gi, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "stage-video";
  return `${Date.now()}-${stem}${extension}`;
}

async function serveFile(request, response, filePath) {
  const info = await stat(filePath);
  const contentType = mimeTypes[extname(filePath).toLowerCase()] || "application/octet-stream";
  const range = request.headers.range?.match(/^bytes=(\d*)-(\d*)$/);
  if (range) {
    const start = range[1] ? Number(range[1]) : 0;
    const end = range[2] ? Math.min(Number(range[2]), info.size - 1) : info.size - 1;
    if (!Number.isFinite(start) || !Number.isFinite(end) || start > end || start >= info.size) {
      response.writeHead(416, { "content-range": `bytes */${info.size}` });
      response.end();
      return;
    }
    response.writeHead(206, {
      "content-type": contentType,
      "content-length": end - start + 1,
      "content-range": `bytes ${start}-${end}/${info.size}`,
      "accept-ranges": "bytes",
    });
    if (request.method === "HEAD") return response.end();
    createReadStream(filePath, { start, end }).pipe(response);
    return;
  }
  response.writeHead(200, {
    "content-type": contentType,
    "content-length": info.size,
    "accept-ranges": "bytes",
  });
  if (request.method === "HEAD") return response.end();
  createReadStream(filePath).pipe(response);
}

const browserCacheableMapStates = new Set([
  "live-cache-hit",
  "live-cache-stale",
  "legacy-cache-hit",
  "legacy-cache-stale",
  "live-offline-hit",
  "live-offline-stale",
  "offline-offline-hit",
  "offline-offline-stale",
  "live-stale-upstream-error",
]);

function mapGatewayRefreshRequested(incoming, pathname) {
  if (pathname !== "/api/map/cache") return false;
  const rawTarget = incoming.searchParams.get("url");
  if (!rawTarget) return false;
  try {
    return new URL(rawTarget).searchParams.get("nodedc_cache_refresh") === "1";
  } catch {
    return false;
  }
}

function weakEtagValue(value) {
  return String(value || "").trim().replace(/^W\//i, "");
}

function requestValidatorMatches(request, etag, lastModified) {
  const ifNoneMatch = String(request.headers["if-none-match"] || "").trim();
  if (ifNoneMatch && etag) {
    if (ifNoneMatch === "*") return true;
    const expected = weakEtagValue(etag);
    return ifNoneMatch.split(",").some((candidate) => weakEtagValue(candidate) === expected);
  }
  const ifModifiedSince = Date.parse(String(request.headers["if-modified-since"] || ""));
  const modifiedAt = Date.parse(String(lastModified || ""));
  return !ifNoneMatch && Number.isFinite(ifModifiedSince) && Number.isFinite(modifiedAt) && modifiedAt <= ifModifiedSince;
}

async function proxyMapGateway(request, response, pathname) {
  if (!mapGatewayInternalUrl) return json(response, 503, { error: "map_gateway_not_configured" });
  if (!pathname.startsWith("/healthz") && !pathname.startsWith("/api/map/")) {
    return json(response, 404, { error: "map_gateway_route_not_found" });
  }
  // Gateway administration is intentionally not a transparent browser proxy.
  // It is reachable only through the admin-only signed path below.
  if (pathname.startsWith("/api/map/admin/")) return json(response, 404, { error: "map_gateway_route_not_found" });
  const sessionUser = foundryAuth.currentUserProfile(request);
  // Local development deliberately runs without Hub handoff; production always
  // requires a validated session before this proxy is reachable.
  const subjectId = sessionUser?.id || (!foundryAuth.authRequired ? "local-dev" : "");
  if (!subjectId) return json(response, 401, { error: "module_foundry_auth_required" });
  const incoming = new URL(request.url || "/", "http://foundry.local");
  const target = new URL(`${pathname}${incoming.search}`, `${mapGatewayInternalUrl}/`);
  const ionReferer = foundryRequestIonReferer(request);
  const controller = new AbortController();
  let clientDisconnected = false;
  let headersTimedOut = false;
  let bodyIdleTimedOut = false;
  let bodyIdleTimeout = null;
  const abortClientRequest = () => {
    clientDisconnected = true;
    if (!controller.signal.aborted) controller.abort();
  };
  const abortClosedResponse = () => {
    if (!response.writableEnded) abortClientRequest();
  };
  const headersTimeout = setTimeout(() => {
    headersTimedOut = true;
    if (!controller.signal.aborted) controller.abort();
  }, mapGatewayHeadersTimeoutMs);
  const clearBodyIdleTimeout = () => {
    if (bodyIdleTimeout !== null) clearTimeout(bodyIdleTimeout);
    bodyIdleTimeout = null;
  };
  const armBodyIdleTimeout = () => {
    clearBodyIdleTimeout();
    bodyIdleTimeout = setTimeout(() => {
      bodyIdleTimedOut = true;
      if (!controller.signal.aborted) controller.abort();
    }, mapGatewayBodyIdleTimeoutMs);
  };
  request.once("aborted", abortClientRequest);
  response.once("close", abortClosedResponse);

  let upstream;
  try {
    const upstreamHeaders = {
      accept: String(request.headers.accept || "*/*"),
      "x-nodedc-user-id": subjectId,
      ...(ionReferer ? { "x-nodedc-ion-referer": ionReferer } : {}),
    };
    for (const name of ["range", "if-none-match", "if-modified-since"]) {
      const value = String(request.headers[name] || "").trim();
      if (value) upstreamHeaders[name] = value;
    }
    upstream = await fetch(target, {
      method: request.method,
      headers: upstreamHeaders,
      signal: controller.signal,
    });
    // The connection/header deadline ends as soon as Gateway has produced a
    // response. The body has a separate progress-based idle timeout below, so
    // a healthy large Cesium tile is never killed by an absolute wall clock.
    clearTimeout(headersTimeout);
    if (clientDisconnected || response.destroyed) {
      await upstream.body?.cancel().catch(() => undefined);
      return;
    }

    const cacheState = String(upstream.headers.get("x-nodedc-map-cache") || "");
    const cacheable = pathname === "/api/map/cache"
      && [200, 206, 304].includes(upstream.status)
      && browserCacheableMapStates.has(cacheState)
      && !mapGatewayRefreshRequested(incoming, pathname);
    const etag = upstream.headers.get("etag");
    const lastModified = upstream.headers.get("last-modified");
    const notModified = cacheable
      && upstream.status === 200
      && request.method === "GET"
      && requestValidatorMatches(request, etag, lastModified);
    const headers = ["content-type", "content-length", "content-range", "accept-ranges", "etag", "last-modified", "x-nodedc-map-cache", "x-nodedc-map-cache-age"];
    for (const header of headers) {
      const value = upstream.headers.get(header);
      if (value) response.setHeader(header, value);
    }
    if (cacheable) {
      // The object was confirmed by the private Gateway as a persistent-cache
      // hit. Keep it in this browser only; shared reverse proxies must still
      // revalidate the authenticated request.
      response.setHeader("cache-control", "private, max-age=300, stale-while-revalidate=60");
      response.setHeader("vary", "Cookie");
    } else {
      // Provider responses, health/configuration calls, errors and explicit
      // refreshes must never create an uncontrolled browser-side copy.
      response.setHeader("cache-control", "no-store");
    }
    response.statusCode = notModified ? 304 : upstream.status;
    if (notModified) {
      response.removeHeader("content-length");
      response.removeHeader("content-range");
      await upstream.body?.cancel().catch(() => undefined);
      return response.end();
    }
    if (request.method === "HEAD" || upstream.status === 304 || !upstream.body) {
      await upstream.body?.cancel().catch(() => undefined);
      return response.end();
    }
    const bodyProgress = new Transform({
      transform(chunk, _encoding, callback) {
        armBodyIdleTimeout();
        callback(null, chunk);
      },
      flush(callback) {
        // Once Gateway reached EOF there is no upstream body left to time out.
        // Let Node finish draining buffered bytes to a slow browser; its own
        // disconnect is still handled by the response close listener.
        clearBodyIdleTimeout();
        callback();
      },
    });
    armBodyIdleTimeout();
    await pipeline(Readable.fromWeb(upstream.body), bodyProgress, response, { signal: controller.signal });
  } catch (error) {
    if (clientDisconnected || response.destroyed) return;
    if (response.headersSent) {
      if (!response.writableEnded && !response.destroyed) response.destroy(error);
      return;
    }
    if (headersTimedOut) throw applicationError("map_gateway_headers_timeout", 504);
    if (bodyIdleTimedOut) throw applicationError("map_gateway_body_idle_timeout", 504);
    throw error;
  } finally {
    clearTimeout(headersTimeout);
    clearBodyIdleTimeout();
    request.off("aborted", abortClientRequest);
    response.off("close", abortClosedResponse);
  }
}

function requireFoundryAdmin(request) {
  const access = foundryAuth.currentUserAccess(request);
  if (!access.admin) throw applicationError("module_foundry_admin_required", 403);
  const user = foundryAuth.currentUserProfile(request);
  const actorId = String(user?.id || (!foundryAuth.authRequired ? "local-dev" : "")).trim();
  if (!actorId) throw applicationError("module_foundry_admin_required", 403);
  return { actorId };
}

function signedGatewayAdminHeaders(method, pathname, actorId, body, ionReferer) {
  if (!mapGatewayAdminSecret) throw applicationError("map_gateway_admin_not_configured", 503);
  const timestamp = String(Date.now());
  const bodyHash = createHash("sha256").update(body).digest("hex");
  const message = `nodedc.map-gateway.admin.v2\n${method}\n${pathname}\n${timestamp}\n${actorId}\n${bodyHash}\n${ionReferer}`;
  const signature = createHmac("sha256", mapGatewayAdminSecret).update(message).digest("hex");
  return {
    "x-nodedc-admin-timestamp": timestamp,
    "x-nodedc-admin-actor": actorId,
    "x-nodedc-admin-signature": signature,
    ...(ionReferer ? { "x-nodedc-ion-referer": ionReferer } : {}),
  };
}

async function requestMapGatewayAdmin({ method, pathname, actorId, payload, ionReferer = "" }) {
  if (!mapGatewayInternalUrl) throw applicationError("map_gateway_not_configured", 503);
  const body = payload === undefined ? "" : JSON.stringify(payload);
  const upstream = await fetch(new URL(pathname, `${mapGatewayInternalUrl}/`), {
    method,
    headers: {
      accept: "application/json",
      ...(body ? { "content-type": "application/json" } : {}),
      ...signedGatewayAdminHeaders(method, pathname, actorId, body, ionReferer),
    },
    body: body || undefined,
    signal: AbortSignal.timeout(10_000),
  });
  const result = await upstream.json().catch(() => null);
  if (!upstream.ok || !result?.ok) {
    const status = upstream.status >= 400 && upstream.status < 600 ? upstream.status : 502;
    const safeError = ["map_gateway_admin_not_configured", "map_gateway_admin_unauthorized", "cesium_ion_token_verification_failed"].includes(result?.error)
      ? result.error
      : "map_gateway_settings_unavailable";
    throw applicationError(safeError, status);
  }
  return result;
}

const serverSockets = new Set();
const server = createServer(async (request, response) => {
  try {
    const url = new URL(request.url || "/", `http://${request.headers.host || "127.0.0.1"}`);

    if (await foundryAgentGateway.handlePublicRequest(request, response, url)) return;
    if (await foundryAgentGateway.handleOntologyMcp(request, response, url)) return;

    if (url.pathname === "/auth/nodedc/handoff" && request.method === "GET") {
      await foundryAuth.handleLauncherHandoff(request, response, url);
      return;
    }

    if (url.pathname === "/auth/logout" && request.method === "GET") {
      foundryAuth.handleLogout(request, response);
      return;
    }

    if (url.pathname === "/healthz" && request.method === "GET") {
      const config = foundryMcpConfig();
      json(response, 200, {
        status: "ok",
        service: "nodedc-module-foundry",
        mcp: {
          configured: Boolean(config.capabilitySecret && config.mcpUrl),
          entitlementConfigured: Boolean(config.internalAccessToken),
        },
        codexAgent: foundryAgentGateway.health(),
        dataProductBindingApi: {
          configured: Boolean(foundryBindingGrantsDir && externalDataPlaneInternalUrl && externalDataPlaneReaderGrantsDir),
          auth: "scoped-workload-grant",
        },
        dataProductConsumerProvisioner: {
          configured: foundryReaderGrantProvisioner.configured,
          auth: "dedicated-ed25519-service-identity",
          sourceScope: "external-data-plane-resolved",
        },
      });
      return;
    }

    if (url.pathname === "/api/mcp") {
      await handleFoundryMcpRequest(request, response, {
        getConfig: foundryMcpConfig,
        operations: foundryMcpOperations,
        authenticateAgentToken: foundryAgentGateway.authenticateFoundryToken,
      });
      return;
    }

    if (url.pathname === "/api/ai-workspace/entitlements") {
      await handleFoundryEntitlementRequest(request, response, { getConfig: foundryMcpConfig });
      return;
    }

    if (url.pathname === FOUNDRY_BINDING_CATALOG_PATH || url.pathname === FOUNDRY_BINDING_UPSERT_PATH) {
      await handleFoundryBindingApiRequest(request, response, {
        grantsDir: foundryBindingGrantsDir,
        production: process.env.NODE_ENV === "production",
        preflightReaderGrant: preflightFoundryBindingReaderGrant,
        upsertBinding: (input, actor) => foundryMcpOperations.upsertMapDataProductBinding(input, actor),
      });
      return;
    }

    if (await foundryAuth.ensureRequestSession(request, response, url)) {
      return;
    }

    const foundryUserProfile = foundryAuth.currentUserProfile(request)
      || (!foundryAuth.authRequired ? {
        id: "local_foundry_user",
        email: "local-foundry@nodedc.local",
        displayName: "Local Foundry User",
        avatarUrl: null,
        initials: "LF",
      } : null);
    if (await foundryAgentGateway.handleManagementRequest(request, response, url, foundryUserProfile)) return;

    if (url.pathname === "/api/session/profile" && request.method === "GET") {
      const access = foundryAuth.currentUserAccess(request);
      json(response, 200, { user: foundryAuth.currentUserProfile(request), profileUrl: foundryAuth.profileUrl, access: { role: access.role } });
      return;
    }

    if (url.pathname === "/api/platform-settings/cesium-ion" && request.method === "GET") {
      const { actorId } = requireFoundryAdmin(request);
      const settings = await requestMapGatewayAdmin({
        method: "GET",
        pathname: "/api/map/admin/cesium-ion",
        actorId,
        ionReferer: foundryRequestIonReferer(request),
      });
      json(response, 200, { configured: settings.configured === true, updatedAt: settings.updatedAt || null, updatedBy: settings.updatedBy || null, verification: settings.verification || "not-configured" });
      return;
    }

    if (url.pathname === "/api/platform-settings/cesium-ion" && request.method === "PUT") {
      const { actorId } = requireFoundryAdmin(request);
      const input = await readJsonBody(request, 8 * 1024);
      const token = typeof input?.token === "string" ? input.token.trim() : "";
      if (token.length < 16 || token.length > 4096 || /[\u0000-\u001f\u007f\s]/.test(token)) {
        throw applicationError("invalid_cesium_ion_token");
      }
      const settings = await requestMapGatewayAdmin({
        method: "PUT",
        pathname: "/api/map/admin/cesium-ion",
        actorId,
        payload: { token },
        ionReferer: foundryRequestIonReferer(request),
      });
      json(response, 200, { configured: settings.configured === true, updatedAt: settings.updatedAt || null, updatedBy: settings.updatedBy || null, verification: settings.verification || "not-configured" });
      return;
    }

    const mapGatewayMatch = url.pathname.match(/^\/api\/map-gateway(\/.*)$/);
    if (mapGatewayMatch && ["GET", "HEAD"].includes(request.method || "")) {
      await proxyMapGateway(request, response, mapGatewayMatch[1]);
      return;
    }

    const runtimeDataProductMatch = url.pathname.match(/^\/api\/applications\/([0-9a-f-]{36})\/pages\/([a-z0-9-]+)\/data-bindings\/([A-Za-z0-9._:-]{1,160})\/(snapshot|history|stream)$/i);
    if (runtimeDataProductMatch && request.method === "GET") {
      const [, applicationId, pageId, bindingId, resource] = runtimeDataProductMatch;
      const target = await resolveRuntimeMapDataProductBinding(applicationId, pageId, bindingId);
      if (resource === "snapshot") await proxyRuntimeDataProductSnapshot(response, target);
      else if (resource === "history") await proxyRuntimeDataProductHistory(response, url, target);
      else await proxyRuntimeDataProductStream(request, response, url, target);
      return;
    }

    if (url.pathname === "/api/layout" && request.method === "GET") {
      try {
        json(response, 200, JSON.parse(await readFile(layoutPath, "utf8")));
      } catch (error) {
        if (error?.code === "ENOENT") return json(response, 200, null);
        throw error;
      }
      return;
    }

    if (url.pathname === "/api/applications" && request.method === "GET") {
      const manifests = [];
      for (const entry of await readdir(applicationsDir, { withFileTypes: true })) {
        if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
        try {
          const manifest = validateApplicationManifest(JSON.parse(await readFile(join(applicationsDir, entry.name), "utf8")));
          manifests.push(applicationSummary(manifest));
        } catch {
      // A damaged draft must not make the complete Foundry project list unavailable.
        }
      }
      manifests.sort((left, right) => String(right.updatedAt).localeCompare(String(left.updatedAt)));
      json(response, 200, manifests);
      return;
    }

    if (url.pathname === "/api/page-templates" && request.method === "GET") {
      json(response, 200, pageRegistry);
      return;
    }

    const pageLayoutMatch = url.pathname.match(/^\/api\/page-layouts\/([a-z0-9-]+)$/i);
    if (pageLayoutMatch && request.method === "GET") {
      try {
        const stored = JSON.parse(await readFile(pageLayoutPath(pageLayoutMatch[1]), "utf8"));
        json(response, 200, pageLayoutMatch[1] === "map" ? validateMapPageLayout(stored) : stored);
      } catch (error) {
        if (error?.code === "ENOENT") return json(response, 200, null);
        throw error;
      }
      return;
    }
    if (pageLayoutMatch && request.method === "PUT") {
      throw applicationError("page_library_read_only", 405);
    }

    if (url.pathname === "/api/map/runtime-config" && request.method === "GET") {
      // Foundry has no provider credentials. The private Platform Gateway is
      // mandatory for live Cesium resources in every environment.
      const gatewayReady = Boolean(mapGatewayInternalUrl);
      const gaussianAssetId = String(process.env.CESIUM_GAUSSIAN_SPLAT_ASSET_ID || "").trim();
      json(response, 200, {
        cesiumVersion: "1.143.0",
        provider: gatewayReady ? "nodedc-map-gateway" : "gateway-required",
        ionReady: gatewayReady,
        gatewayReady,
        osmBuildingsReady: gatewayReady,
        gaussianSplatsReady: gatewayReady && Boolean(gaussianAssetId),
        gaussianAssetId: gaussianAssetId || null,
        assetEndpointBase: "/api/map-gateway/api/map/ion/assets",
        resourceProxyBase: gatewayReady ? "/api/map-gateway/api/map/cache?url=" : null,
        gatewayHealthUrl: gatewayReady ? "/api/map-gateway/healthz" : null,
        cache: { mode: gatewayReady ? "gateway" : "external-required", persistent: gatewayReady },
      });
      return;
    }

    if (url.pathname === "/api/design-profiles" && request.method === "GET") {
      const profiles = [];
      for (const entry of await readdir(designProfilesDir, { withFileTypes: true })) {
        if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
        try {
          const profile = validateDesignProfile(JSON.parse(await readFile(join(designProfilesDir, entry.name), "utf8")));
          profiles.push(designProfileSummary(profile, await readDesignProfileReleases(profile.id)));
        } catch { /* skip damaged draft */ }
      }
      profiles.sort((left, right) => left.name.localeCompare(right.name));
      json(response, 200, profiles);
      return;
    }

    if (url.pathname === "/api/design-profiles" && request.method === "POST") {
      const input = await readJsonBody(request);
      const now = new Date().toISOString();
      const profile = validateDesignProfile({
        schemaVersion: "0.1.0",
        id: randomUUID(),
        name: input?.name,
        version: "0.1.0",
        status: "draft",
        layout: input?.layout,
        timestamps: { createdAt: now, updatedAt: now },
      });
      await writeDesignProfile(profile);
      json(response, 201, profile);
      return;
    }

    const designProfileMatch = url.pathname.match(/^\/api\/design-profiles\/(default|[0-9a-f-]{36})$/i);
    if (designProfileMatch && request.method === "GET") {
      try { json(response, 200, validateDesignProfile(JSON.parse(await readFile(designProfilePath(designProfileMatch[1]), "utf8")))); }
      catch (error) { if (error?.code === "ENOENT") return json(response, 404, { error: "design_profile_not_found" }); throw error; }
      return;
    }
    if (designProfileMatch && request.method === "PUT") {
      let current;
      try { current = validateDesignProfile(JSON.parse(await readFile(designProfilePath(designProfileMatch[1]), "utf8"))); }
      catch (error) { if (error?.code === "ENOENT") return json(response, 404, { error: "design_profile_not_found" }); throw error; }
      const input = await readJsonBody(request);
      const next = validateDesignProfile({
        ...current,
        name: input?.name || current.name,
        version: nextPatchVersion(current.version),
        layout: input?.layout,
        timestamps: { createdAt: current.timestamps.createdAt, updatedAt: new Date().toISOString() },
      });
      await writeDesignProfile(next);
      json(response, 200, next);
      return;
    }

    const designProfileVersionsMatch = url.pathname.match(/^\/api\/design-profiles\/(default|[0-9a-f-]{36})\/versions$/i);
    if (designProfileVersionsMatch && request.method === "GET") {
      let current;
      try { current = validateDesignProfile(JSON.parse(await readFile(designProfilePath(designProfileVersionsMatch[1]), "utf8"))); }
      catch (error) { if (error?.code === "ENOENT") return json(response, 404, { error: "design_profile_not_found" }); throw error; }
      const releases = await readDesignProfileReleases(current.id);
      json(response, 200, { id: current.id, draft: designProfileVersionSummary(current), published: releases.map(designProfileVersionSummary) });
      return;
    }

    const designProfileVersionMatch = url.pathname.match(/^\/api\/design-profiles\/(default|[0-9a-f-]{36})\/versions\/(\d+\.\d+\.\d+)$/i);
    if (designProfileVersionMatch && request.method === "GET") {
      try { json(response, 200, validateDesignProfile(JSON.parse(await readFile(designProfileReleasePath(designProfileVersionMatch[1], designProfileVersionMatch[2]), "utf8")))); }
      catch (error) { if (error?.code === "ENOENT") return json(response, 404, { error: "design_profile_version_not_found" }); throw error; }
      return;
    }

    const designProfilePublishMatch = url.pathname.match(/^\/api\/design-profiles\/(default|[0-9a-f-]{36})\/publish$/i);
    if (designProfilePublishMatch && request.method === "POST") {
      let current;
      try { current = validateDesignProfile(JSON.parse(await readFile(designProfilePath(designProfilePublishMatch[1]), "utf8"))); }
      catch (error) { if (error?.code === "ENOENT") return json(response, 404, { error: "design_profile_not_found" }); throw error; }
      const release = await writeDesignProfileRelease(current);
      json(response, 201, release);
      return;
    }

    if (url.pathname === "/api/applications" && request.method === "POST") {
      const input = await readJsonBody(request);
      const manifest = validateApplicationManifest(createApplicationManifest(input));
      await assertDesignProfileReference(manifest.designProfile);
      await writeApplicationManifest(manifest);
      json(response, 201, manifest);
      return;
    }

    const applicationMatch = url.pathname.match(/^\/api\/applications\/([0-9a-f-]{36})$/i);
    if (applicationMatch && request.method === "GET") {
      try {
        const manifest = validateApplicationManifest(JSON.parse(await readFile(applicationPath(applicationMatch[1]), "utf8")));
        json(response, 200, manifest);
      } catch (error) {
        if (error?.code === "ENOENT") return json(response, 404, { error: "application_not_found" });
        throw error;
      }
      return;
    }

    if (applicationMatch && request.method === "PUT") {
      const currentPath = applicationPath(applicationMatch[1]);
      let current;
      try {
        current = validateApplicationManifest(JSON.parse(await readFile(currentPath, "utf8")));
      } catch (error) {
        if (error?.code === "ENOENT") return json(response, 404, { error: "application_not_found" });
        throw error;
      }
      const input = await readJsonBody(request);
      if (String(input?.id || "") !== applicationMatch[1]) throw applicationError("application_id_mismatch");
      const next = validateApplicationManifest({
        ...input,
        timestamps: {
          createdAt: current.timestamps.createdAt,
          updatedAt: new Date().toISOString(),
        },
      });
      await assertDesignProfileReference(next.designProfile);
      await writeApplicationManifest(next);
      json(response, 200, next);
      return;
    }

    if (applicationMatch && request.method === "DELETE") {
      const currentPath = applicationPath(applicationMatch[1]);
      try { await stat(currentPath); } catch (error) { if (error?.code === "ENOENT") return json(response, 404, { error: "application_not_found" }); throw error; }
      const deletedPath = join(runtimeDir, "deleted-applications");
      await mkdir(deletedPath, { recursive: true });
      await rename(currentPath, join(deletedPath, `${applicationMatch[1]}-${Date.now()}.json`));
      json(response, 200, { deleted: true, id: applicationMatch[1] });
      return;
    }

    if (url.pathname === "/api/layout" && request.method === "PUT") {
      const layout = await readJsonBody(request);
      const next = { ...layout, savedAt: new Date().toISOString(), schemaVersion: 1 };
      const tempPath = `${layoutPath}.tmp`;
      await writeFile(tempPath, `${JSON.stringify(next, null, 2)}\n`, "utf8");
      await rename(tempPath, layoutPath);
      json(response, 200, next);
      return;
    }

    if (url.pathname === "/api/layout/media" && request.method === "PUT") {
      const originalName = decodeURIComponent(String(request.headers["x-file-name"] || "stage-video.mp4"));
      const fileName = safeUploadName(originalName, String(request.headers["content-type"] || ""));
      const targetPath = join(uploadDir, fileName);
      await pipeline(request, createWriteStream(targetPath, { flags: "wx" }));
      json(response, 201, { fileName: originalName, url: `/uploads/${fileName}` });
      return;
    }

    if (url.pathname.startsWith("/uploads/")) {
      const fileName = basename(normalize(url.pathname.slice("/uploads/".length)));
      await serveFile(request, response, join(uploadDir, fileName));
      return;
    }

    const relativePath = url.pathname === "/" ? "index.html" : url.pathname.replace(/^\//, "");
    const candidate = join(distDir, normalize(relativePath));
    try {
      await serveFile(request, response, candidate);
    } catch (error) {
      if (error?.code !== "ENOENT") throw error;
      await serveFile(request, response, join(distDir, "index.html"));
    }
  } catch (error) {
    const statusCode = error?.statusCode || (error?.message === "payload_too_large" ? 413 : 500);
    json(response, statusCode, { error: error?.message || "server_error" });
  }
});

server.on("connection", (socket) => {
  serverSockets.add(socket);
  socket.once("close", () => serverSockets.delete(socket));
});

let shutdownPromise = null;
function shutdownServer(signal) {
  if (shutdownPromise) return shutdownPromise;
  shutdownPromise = (async () => {
    for (const activeStream of activeRuntimeStreams) {
      activeStream.controller.abort();
      activeStream.response.destroy();
    }
    await dataProductConsumerManager.shutdown();
    await new Promise((resolveShutdown) => {
      const timeout = setTimeout(() => {
        for (const socket of serverSockets) socket.destroy();
      }, 5_000);
      server.close((error) => {
        clearTimeout(timeout);
        if (error) {
          process.exitCode = 1;
          console.error(`NDC Module Foundry shutdown error (${signal}): ${error.message}`);
        }
        resolveShutdown();
      });
    });
  })();
  return shutdownPromise;
}

async function shutdownAndExit(signal) {
  await shutdownServer(signal);
  // A canceled upstream fetch may leave an idle keep-alive socket owned by
  // Node's global HTTP dispatcher. All Foundry state and inbound sockets are
  // already closed at this point, so finish the container stop deterministically.
  process.exit(process.exitCode || 0);
}

process.once("SIGTERM", () => { void shutdownAndExit("SIGTERM"); });
process.once("SIGINT", () => { void shutdownAndExit("SIGINT"); });

server.listen(port, host, () => {
  console.log(`NDC Module Foundry: http://${host}:${port}`);
  console.log(`Layout store: ${layoutPath}`);
  console.log(`Application drafts: ${applicationsDir}`);
  console.log(`Foundry MCP: /api/mcp`);
  console.log(`AI Workspace entitlement adapter: /api/ai-workspace/entitlements`);
});
