import { createReadStream, createWriteStream } from "node:fs";
import { mkdir, readFile, readdir, rename, stat, writeFile } from "node:fs/promises";
import { createServer } from "node:http";
import { randomUUID } from "node:crypto";
import { basename, extname, join, normalize } from "node:path";
import { pipeline } from "node:stream/promises";
import { fileURLToPath } from "node:url";

const root = fileURLToPath(new URL("..", import.meta.url));
const distDir = join(root, "apps", "catalog", "dist");
const runtimeDir = 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 layoutPath = join(runtimeDir, "layout.json");
const pageRegistryPath = join(root, "registry", "pages.json");
const port = Number(process.env.PORT || 3333);
const cesiumIonAssetAllowlist = new Set(
  String(process.env.CESIUM_ION_ASSET_ALLOWLIST || "1,96188")
    .split(",")
    .map((value) => value.trim())
    .filter(Boolean),
);

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 });
const pageRegistry = JSON.parse(await readFile(pageRegistryPath, "utf8"));

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) {
  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 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;
  for (const key of ["imageryVisible", "cacheEnabled", "terrainEnabled", "monochrome", "atmosphereEnabled", "fogEnabled", "sunEnabled", "shadowsEnabled", "buildingsVisible", "gridVisible", "gridLodEnabled", "gridDotsEnabled"]) {
    requireBoolean(settings[key], `invalid_map_page_setting_${key}`);
  }
  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}`);
  }
  return {
    schemaVersion: 1,
    pageId: "map",
    settings,
    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,
    },
  };
}

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"),
    },
  };
}

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) };
}

async function ensureDefaultDesignProfile() {
  try {
    await readFile(designProfilePath("default"), "utf8");
  } catch (error) {
    if (error?.code !== "ENOENT") throw error;
    let layout = {};
    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();
  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");
    if (page.layout !== undefined) {
      if (!isObject(page.layout)) throw applicationError("invalid_application_page_layout");
      if (page.template.id === "map" && page.layout.map !== undefined) validateMapPageLayout(page.layout.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");
    }
  }
  return {
    ...value,
    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 || "Первый Application Draft NDC Module Studio."),
    },
    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);
  const tempPath = `${targetPath}.${randomUUID()}.tmp`;
  await writeFile(tempPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
  await rename(tempPath, targetPath);
}

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;
}

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 server = createServer(async (request, response) => {
  try {
    const url = new URL(request.url || "/", `http://${request.headers.host || "127.0.0.1"}`);

    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 Studio 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 {
        json(response, 200, JSON.parse(await readFile(pageLayoutPath(pageLayoutMatch[1]), "utf8")));
      } catch (error) {
        if (error?.code === "ENOENT") return json(response, 200, null);
        throw error;
      }
      return;
    }
    if (pageLayoutMatch && request.method === "PUT") {
      const pageId = pageLayoutMatch[1];
      if (pageId !== "map") throw applicationError("unsupported_page_layout");
      const layout = validateMapPageLayout(await readJsonBody(request));
      const next = { ...layout, savedAt: new Date().toISOString() };
      const targetPath = pageLayoutPath(pageId);
      const tempPath = `${targetPath}.${randomUUID()}.tmp`;
      await writeFile(tempPath, `${JSON.stringify(next, null, 2)}\n`, "utf8");
      await rename(tempPath, targetPath);
      json(response, 200, next);
      return;
    }

    if (url.pathname === "/api/map/runtime-config" && request.method === "GET") {
      const ionReady = Boolean(process.env.CESIUM_ION_TOKEN);
      // The local Platform gateway is part of the Module Studio development
      // topology. Production must receive its address explicitly; a browser
      // must never receive the Ion token itself in either case.
      const gatewayUrl = String(
        process.env.NODEDC_MAP_GATEWAY_URL || (process.env.NODE_ENV === "production" ? "" : "http://127.0.0.1:18103"),
      ).trim();
      const gatewayBase = gatewayUrl.replace(/\/$/, "");
      const localGatewayReady = ionReady;
      const gaussianAssetId = String(process.env.CESIUM_GAUSSIAN_SPLAT_ASSET_ID || "").trim();
      json(response, 200, {
        cesiumVersion: "1.143.0",
        provider: gatewayUrl ? "nodedc-map-gateway" : localGatewayReady ? "studio-dev-gateway" : "osm",
        ionReady,
        gatewayReady: Boolean(gatewayUrl) || localGatewayReady,
        osmBuildingsReady: Boolean(gatewayUrl) || localGatewayReady,
        gaussianSplatsReady: (Boolean(gatewayUrl) || localGatewayReady) && Boolean(gaussianAssetId),
        gaussianAssetId: gaussianAssetId || null,
        assetEndpointBase: gatewayUrl ? `${gatewayBase}/api/map/ion/assets` : "/api/map/ion/assets",
        resourceProxyBase: gatewayUrl ? `${gatewayBase}/api/map/cache?url=` : null,
        gatewayHealthUrl: gatewayUrl ? `${gatewayBase}/healthz` : null,
        cache: { mode: gatewayUrl ? "gateway" : "external-required", persistent: Boolean(gatewayUrl) },
      });
      return;
    }

    const cesiumAssetEndpointMatch = url.pathname.match(/^\/api\/map\/ion\/assets\/(\d+)\/endpoint$/);
    if (cesiumAssetEndpointMatch && request.method === "GET") {
      const masterToken = String(process.env.CESIUM_ION_TOKEN || "").trim();
      const assetId = cesiumAssetEndpointMatch[1];
      if (!masterToken) return json(response, 503, { error: "cesium_ion_not_configured" });
      if (!cesiumIonAssetAllowlist.has(assetId)) return json(response, 403, { error: "cesium_asset_not_allowed" });
      const upstream = await fetch(`https://api.cesium.com/v1/assets/${assetId}/endpoint`, {
        headers: { authorization: `Bearer ${masterToken}` },
      });
      if (!upstream.ok) return json(response, upstream.status, { error: "cesium_ion_endpoint_unavailable" });
      const endpoint = await upstream.json();
      json(response, 200, {
        assetId,
        type: endpoint.type,
        url: endpoint.url,
        accessToken: endpoint.accessToken,
        attributions: Array.isArray(endpoint.attributions) ? endpoint.attributions : [],
      });
      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.listen(port, "127.0.0.1", () => {
  console.log(`NODE.DC Design Guideline: http://127.0.0.1:${port}`);
  console.log(`Layout store: ${layoutPath}`);
  console.log(`Application drafts: ${applicationsDir}`);
});
