import {
  buildDefaultRecord,
  buildSpritePreviewDataUrl,
  fetchJsonOrThrow,
  normalizeNpcRecordForLoad,
} from "../editorCore";
import type { JsonObject } from "../contracts/json";
import { buildSpritesPayloadFromImagesPayload, buildTilesPayloadFromImagesPayload } from "../contentTransforms/graphicsPayload";
import type {
  HeightLayerPatchPayload,
  NpcOverlay,
  RoomLayerPayload,
  SpriteCatalogEntry,
  TileCatalogEntry,
} from "../components/worldshaperShared";
import {
  TILE_COLORS,
  buildSpriteCatalog,
  buildTileCatalogById,
  normalizeMapBackgroundColor,
  resizeRows,
} from "../components/worldshaperShared";
import { normalizeImagesPayloadSnapshot } from "./graphicsDocumentHelpers";

export type WorldshaperStudioBootstrap = {
  mapId: string;
  mapName: string;
  width: number;
  height: number;
  tileSize: number;
  backgroundTileId: string;
  roomLayers: RoomLayerPayload[];
  heightLayers: HeightLayerPatchPayload[];
  tileColors: Record<string, string>;
  baseRows: string[];
  npcOverlays: NpcOverlay[];
  contentByType: Record<string, JsonObject>;
  spriteCatalog: Record<string, SpriteCatalogEntry>;
  tileCatalogById: Record<string, TileCatalogEntry>;
  defaultNpcTemplate: JsonObject;
  apiBase: string;
  backgroundColor: string;
  heightBlurStep?: number;
  editorUi?: Record<string, unknown>;
  sourceMode?: "world";
  worldId?: string;
  worldName?: string;
  worldChunkWidth?: number;
  worldChunkHeight?: number;
  worldOriginChunkX?: number;
  worldOriginChunkY?: number;
  worldChunkRadius?: number;
  worldTileOffsetX?: number;
  worldTileOffsetY?: number;
  worldSpawnX?: number;
  worldSpawnY?: number;
  worldBookmarks?: Array<{ id: string; label: string; x: number; y: number }>;
  sourceChunks?: Array<{ chunkX: number; chunkY: number }>;
};

declare global {
  interface Window {
    __WORLDSHAPER_STUDIO_BOOTSTRAPS__?: Record<string, WorldshaperStudioBootstrap>;
  }
}

const POPUP_BOOTSTRAP_STORAGE_KEY_PREFIX = "worldshaper:studio-bootstrap:";
const STANDALONE_WORLD_BOOTSTRAP_STORAGE_KEY_PREFIX = "worldshaper:standalone-world-bootstrap:";
const DEFAULT_WORLD_CHUNK_RADIUS = 1;
const DEFAULT_HEIGHT_BLUR_STEP = 0.1;

function normalizeHeightBlurStep(value: unknown, fallback = DEFAULT_HEIGHT_BLUR_STEP): number {
  const normalized = Number(value);
  if (!Number.isFinite(normalized)) {
    return fallback;
  }
  return Math.max(0, Math.min(1, normalized));
}

function normalizeBootstrapEditorUi(value: unknown): Record<string, unknown> {
  const source = value && typeof value === "object" && !Array.isArray(value)
    ? value as Record<string, unknown>
    : null;
  if (!source) {
    return { panelLayouts: {} };
  }
  const panelLayouts = source.panelLayouts && typeof source.panelLayouts === "object" && !Array.isArray(source.panelLayouts)
    ? JSON.parse(JSON.stringify(source.panelLayouts))
    : {};
  return {
    panelLayouts,
  };
}

function hasMeaningfulBootstrapEditorUi(value: unknown): boolean {
  const normalized = normalizeBootstrapEditorUi(value) as { panelLayouts?: Record<string, unknown> };
  const panelLayouts = normalized.panelLayouts && typeof normalized.panelLayouts === "object" && !Array.isArray(normalized.panelLayouts)
    ? normalized.panelLayouts
    : {};
  return Object.keys(panelLayouts).length > 0;
}

function cloneBootstrap(bootstrap: WorldshaperStudioBootstrap): WorldshaperStudioBootstrap {
  if (typeof structuredClone === "function") {
    return structuredClone(bootstrap);
  }
  return JSON.parse(JSON.stringify(bootstrap)) as WorldshaperStudioBootstrap;
}

function getBootstrapRegistry(hostWindow: Window): Record<string, WorldshaperStudioBootstrap> {
  if (!hostWindow.__WORLDSHAPER_STUDIO_BOOTSTRAPS__) {
    hostWindow.__WORLDSHAPER_STUDIO_BOOTSTRAPS__ = {};
  }
  return hostWindow.__WORLDSHAPER_STUDIO_BOOTSTRAPS__;
}

function getPopupBootstrapStorageKey(token: string): string {
  return POPUP_BOOTSTRAP_STORAGE_KEY_PREFIX + token;
}

function getStandaloneWorldBootstrapStorageKey(worldId: string): string {
  return STANDALONE_WORLD_BOOTSTRAP_STORAGE_KEY_PREFIX + String(worldId || "").trim();
}

function readBootstrapFromOpener(token: string, popupWindow: Window): WorldshaperStudioBootstrap | null {
  try {
    const opener = popupWindow.opener;
    if (!opener || opener.closed) {
      return null;
    }
    const registry = opener.__WORLDSHAPER_STUDIO_BOOTSTRAPS__;
    const bootstrap = registry?.[token];
    return bootstrap ? cloneBootstrap(bootstrap) : null;
  } catch {
    return null;
  }
}

function cacheBootstrap(token: string, bootstrap: WorldshaperStudioBootstrap, popupWindow: Window): void {
  try {
    popupWindow.sessionStorage.setItem(
      getPopupBootstrapStorageKey(token),
      JSON.stringify(bootstrap),
    );
  } catch {
    // Ignore storage failures and keep the opener handoff path.
  }
}

function readCachedBootstrap(token: string, popupWindow: Window): WorldshaperStudioBootstrap | null {
  try {
    const raw = popupWindow.sessionStorage.getItem(getPopupBootstrapStorageKey(token));
    if (!raw) {
      return null;
    }
    return JSON.parse(raw) as WorldshaperStudioBootstrap;
  } catch {
    return null;
  }
}

export function createWorldshaperStudioToken(): string {
  return "map-editor-" + Date.now().toString(36) + "-" + Math.random().toString(36).slice(2, 10);
}

export function registerWorldshaperStudioBootstrap(
  token: string,
  bootstrap: WorldshaperStudioBootstrap,
  hostWindow: Window = window,
): void {
  getBootstrapRegistry(hostWindow)[token] = cloneBootstrap(bootstrap);
}

export function clearWorldshaperStudioBootstrap(token: string, hostWindow: Window = window): void {
  if (!token) {
    return;
  }
  const registry = hostWindow.__WORLDSHAPER_STUDIO_BOOTSTRAPS__;
  if (!registry) {
    return;
  }
  delete registry[token];
  if (Object.keys(registry).length === 0) {
    delete hostWindow.__WORLDSHAPER_STUDIO_BOOTSTRAPS__;
  }
}

export function loadWorldshaperStudioBootstrap(
  token: string,
  popupWindow: Window = window,
): WorldshaperStudioBootstrap | null {
  if (!token) {
    return null;
  }
  const openerBootstrap = readBootstrapFromOpener(token, popupWindow);
  if (openerBootstrap) {
    cacheBootstrap(token, openerBootstrap, popupWindow);
    return openerBootstrap;
  }
  return readCachedBootstrap(token, popupWindow);
}

export function cacheStandaloneWorldshaperBootstrap(
  bootstrap: WorldshaperStudioBootstrap,
  popupWindow: Window = window,
): boolean {
  const worldId = String(bootstrap?.worldId || bootstrap?.mapId || "").trim();
  if (!worldId) {
    return false;
  }
  try {
    popupWindow.sessionStorage.setItem(
      getStandaloneWorldBootstrapStorageKey(worldId),
      JSON.stringify(cloneBootstrap(bootstrap)),
    );
    return true;
  } catch {
    return false;
  }
}

export function readStandaloneWorldshaperBootstrap(
  requestedWorldId: string,
  popupWindow: Window = window,
): WorldshaperStudioBootstrap | null {
  const worldId = String(requestedWorldId || "").trim();
  if (!worldId) {
    return null;
  }
  try {
    const raw = popupWindow.sessionStorage.getItem(getStandaloneWorldBootstrapStorageKey(worldId));
    if (!raw) {
      return null;
    }
    return JSON.parse(raw) as WorldshaperStudioBootstrap;
  } catch {
    return null;
  }
}

function getContentApiUrl(pathname: string, apiBase: string): string {
  return new URL(pathname, apiBase).toString();
}

function normalizeContentPayload(type: string, payload: JsonObject): JsonObject {
  if (type !== "npcs" || !Array.isArray(payload.npcs)) {
    return payload;
  }
  return {
    ...payload,
    npcs: payload.npcs.map((record) => {
      if (!record || typeof record !== "object" || Array.isArray(record)) {
        return record;
      }
      return normalizeNpcRecordForLoad(record as JsonObject);
    }),
  };
}

async function fetchWorldshaperStudioContentBundle(apiBase: string): Promise<Record<string, JsonObject>> {
  const typesPayload = await fetchJsonOrThrow<{ types?: string[] }>(getContentApiUrl("/api/types", apiBase));
  const fallbackTypes = ["npcs", "npc_templates", "dialogues", "factions", "images"];
  const requestedTypes = Array.isArray(typesPayload.types) && typesPayload.types.length > 0
    ? typesPayload.types
    : fallbackTypes;
  const normalizedTypes = Array.from(new Set(
    requestedTypes
      .map((type) => String(type || "").trim())
      .filter((type) => type !== "tiles" && type !== "sprites")
      .concat("images")
      .filter(Boolean),
  ));
  const payloads = await Promise.all(
    normalizedTypes.map((type) => fetchJsonOrThrow<JsonObject>(getContentApiUrl(`/api/content/${type}`, apiBase))),
  );
  return normalizedTypes.reduce<Record<string, JsonObject>>((acc, type, index) => {
    acc[type] = normalizeContentPayload(type, payloads[index] || {});
    return acc;
  }, {});
}

type WorldChunkRoutePayload = {
  schemaVersion?: number;
  worldId?: string;
  chunkX?: number;
  chunkY?: number;
  width?: number;
  height?: number;
  backgroundTileId?: string;
  roomLayers?: Array<Record<string, unknown>>;
  heightLayers?: Array<Record<string, unknown>>;
  instances?: Array<Record<string, unknown>>;
};

type WorldInfoRoutePayload = {
  ok?: boolean;
  world?: {
    schemaVersion?: number;
    id?: string;
    name?: string;
    chunkWidth?: number;
    chunkHeight?: number;
    tileSize?: number;
    backgroundColor?: string;
    defaultBackgroundTileId?: string;
    heightBlurStep?: number;
    heightDetailStep?: number;
    editorUi?: Record<string, unknown>;
    spawn?: { x?: number; y?: number };
    editor?: { defaultZoom?: number; gridVisible?: boolean };
  };
  bookmarks?: {
    schemaVersion?: number;
    worldId?: string;
    bookmarks?: Array<{ id?: string; label?: string; x?: number; y?: number }>;
  };
};

type WorldChunksRoutePayload = {
  ok?: boolean;
  world?: WorldInfoRoutePayload["world"];
  center?: { chunkX?: number; chunkY?: number };
  radius?: number;
  chunks?: WorldChunkRoutePayload[];
};

function createFilledRows(width: number, height: number, fillChar: string): string[] {
  return Array.from({ length: Math.max(1, height) }, () => String(fillChar || " ").repeat(Math.max(1, width)));
}

function writeRowSegment(rows: string[], y: number, x: number, segment: string): void {
  if (!Array.isArray(rows) || y < 0 || y >= rows.length || !segment) {
    return;
  }
  const sourceRow = String(rows[y] || "");
  const safeX = Math.max(0, x);
  const padded = sourceRow.length >= safeX
    ? sourceRow
    : (sourceRow + " ".repeat(Math.max(0, safeX - sourceRow.length)));
  const before = padded.slice(0, safeX);
  const afterStart = safeX + segment.length;
  const after = afterStart < padded.length ? padded.slice(afterStart) : "";
  rows[y] = before + segment + after;
}

function composeWorldRoomLayers(
  chunks: WorldChunkRoutePayload[],
  chunkWidth: number,
  chunkHeight: number,
  originChunkX: number,
  originChunkY: number,
  worldWidth: number,
  worldHeight: number,
): RoomLayerPayload[] {
  const layerMap = new Map<number, RoomLayerPayload>();
  chunks.forEach((chunk) => {
    const baseChunkX = Math.floor(Number(chunk.chunkX) || 0);
    const baseChunkY = Math.floor(Number(chunk.chunkY) || 0);
    const offsetX = (baseChunkX - originChunkX) * chunkWidth;
    const offsetY = (baseChunkY - originChunkY) * chunkHeight;
    const rawLayers = Array.isArray(chunk.roomLayers) ? chunk.roomLayers : [];
    rawLayers.forEach((rawLayer) => {
      const layerNumber = Number(rawLayer?.layer) || 0;
      const fillChar = layerNumber === 0 ? "." : " ";
      if (!layerMap.has(layerNumber)) {
        layerMap.set(layerNumber, {
          layer: layerNumber,
          name: typeof rawLayer?.name === "string" && String(rawLayer.name).trim() ? String(rawLayer.name).trim() : undefined,
          rows: createFilledRows(worldWidth, worldHeight, fillChar),
          instanceIds: [],
        });
      }
      const targetLayer = layerMap.get(layerNumber) as RoomLayerPayload;
      const sourceRows = Array.isArray(rawLayer?.rows) ? rawLayer.rows.map((row) => String(row || "")) : [];
      sourceRows.forEach((row, localY) => {
        const targetY = offsetY + localY;
        if (targetY < 0 || targetY >= targetLayer.rows.length) {
          return;
        }
        writeRowSegment(targetLayer.rows, targetY, offsetX, row.slice(0, worldWidth - offsetX));
      });
      const sourceInstanceIds = Array.isArray(rawLayer?.instanceIds)
        ? rawLayer.instanceIds.map((entry) => String(entry || "").trim()).filter(Boolean)
        : [];
      targetLayer.instanceIds = Array.from(new Set([...targetLayer.instanceIds, ...sourceInstanceIds]));
    });
  });
  if (!layerMap.has(0)) {
    layerMap.set(0, {
      layer: 0,
      rows: createFilledRows(worldWidth, worldHeight, "."),
      instanceIds: [],
    });
  }
  return Array.from(layerMap.values()).sort((a, b) => a.layer - b.layer);
}

function composeWorldHeightLayers(
  chunks: WorldChunkRoutePayload[],
  chunkWidth: number,
  chunkHeight: number,
  originChunkX: number,
  originChunkY: number,
): HeightLayerPatchPayload[] {
  const patches: HeightLayerPatchPayload[] = [];
  chunks.forEach((chunk) => {
    const baseChunkX = Math.floor(Number(chunk.chunkX) || 0);
    const baseChunkY = Math.floor(Number(chunk.chunkY) || 0);
    const offsetX = (baseChunkX - originChunkX) * chunkWidth;
    const offsetY = (baseChunkY - originChunkY) * chunkHeight;
    const rawHeightLayers = Array.isArray(chunk.heightLayers) ? chunk.heightLayers : [];
    rawHeightLayers.forEach((entry, index) => {
      const fallbackId = `height_${baseChunkX}_${baseChunkY}_${index + 1}`;
      patches.push({
        id: String(entry?.id || fallbackId).trim() || fallbackId,
        name: typeof entry?.name === "string" && String(entry.name).trim() ? String(entry.name).trim() : undefined,
        z: Math.max(1, Math.floor(Number(entry?.z) || 1)),
        x: offsetX + Math.max(0, Number(entry?.x) || 0),
        y: offsetY + Math.max(0, Number(entry?.y) || 0),
        rows: Array.isArray(entry?.rows) ? entry.rows.map((row) => String(row || "")) : [],
      });
    });
  });
  return patches.sort((a, b) => {
    if (a.z !== b.z) {
      return a.z - b.z;
    }
    return String(a.name || a.id).localeCompare(String(b.name || b.id));
  });
}

function buildNpcOverlaysFromWorldChunks(
  chunks: WorldChunkRoutePayload[],
  spriteCatalog: Record<string, SpriteCatalogEntry>,
  chunkWidth: number,
  chunkHeight: number,
  originChunkX: number,
  originChunkY: number,
): NpcOverlay[] {
  return chunks.flatMap((chunk) => {
    const baseChunkX = Math.floor(Number(chunk.chunkX) || 0);
    const baseChunkY = Math.floor(Number(chunk.chunkY) || 0);
    const offsetX = (baseChunkX - originChunkX) * chunkWidth;
    const offsetY = (baseChunkY - originChunkY) * chunkHeight;
    const instances = Array.isArray(chunk.instances) ? chunk.instances : [];
    return instances
      .filter((entry): entry is Record<string, unknown> => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry))
      .map((entry) => {
        const record = entry.record && typeof entry.record === "object" && !Array.isArray(entry.record)
          ? { ...(entry.record as JsonObject) }
          : {} as JsonObject;
        const spriteId = String(record.spriteId || entry.spriteId || "").trim();
        const spriteEntry = spriteCatalog[spriteId] || null;
        const localX = Math.max(0, Number(entry.x) || 0);
        const localY = Math.max(0, Number(entry.y) || 0);
        const overlayX = offsetX + localX;
        const overlayY = offsetY + localY;
        record.position = {
          x: overlayX,
          y: overlayY,
        };
        return {
          id: String(entry.id || "").trim(),
          layer: Number(entry.layer) || 0,
          name: String(record.name || entry.id || "NPC"),
          spriteId,
          x: overlayX,
          y: overlayY,
          dataUrl: spriteEntry ? spriteEntry.dataUrl : null,
          spriteWidth: spriteEntry ? spriteEntry.spriteWidth : 28,
          spriteHeight: spriteEntry ? spriteEntry.spriteHeight : 28,
          opacity: spriteEntry ? spriteEntry.opacity : 1,
          record,
        };
      })
      .filter((entry) => entry.id);
  });
}

export async function loadStandaloneWorldshaperBootstrap(
  requestedWorldId: string,
  apiBase: string = window.location.origin,
): Promise<WorldshaperStudioBootstrap> {
  const worldId = String(requestedWorldId || "").trim();
  if (!worldId) {
    throw new Error("A world id is required.");
  }
  const cachedBootstrap = readStandaloneWorldshaperBootstrap(worldId, window);
  try {
    const contentByType = await fetchWorldshaperStudioContentBundle(apiBase);
    const worldInfoPayload = await fetchJsonOrThrow<WorldInfoRoutePayload>(getContentApiUrl(`/api/world/${encodeURIComponent(worldId)}`, apiBase));
    const world = worldInfoPayload?.world;
    if (!world) {
      throw new Error(`World ${worldId} was not found.`);
    }
    const bookmarks = Array.isArray(worldInfoPayload?.bookmarks?.bookmarks)
      ? worldInfoPayload.bookmarks.bookmarks.map((entry, index) => ({
        id: String(entry?.id || `bookmark_${index + 1}`).trim() || `bookmark_${index + 1}`,
        label: String(entry?.label || entry?.id || `Bookmark ${index + 1}`).trim() || `Bookmark ${index + 1}`,
        x: Math.floor(Number(entry?.x) || 0),
        y: Math.floor(Number(entry?.y) || 0),
      }))
      : [];
    const chunkWidth = Math.max(1, Number(world.chunkWidth) || DEFAULT_WORLD_CHUNK_RADIUS * 32);
    const chunkHeight = Math.max(1, Number(world.chunkHeight) || DEFAULT_WORLD_CHUNK_RADIUS * 32);
    const spawnX = Math.floor(Number(world.spawn?.x) || 0);
    const spawnY = Math.floor(Number(world.spawn?.y) || 0);
    const initialViewBookmark = bookmarks[0] || null;
    const initialViewTileX = initialViewBookmark ? Math.floor(Number(initialViewBookmark.x) || 0) : spawnX;
    const initialViewTileY = initialViewBookmark ? Math.floor(Number(initialViewBookmark.y) || 0) : spawnY;
    const centerChunkX = Math.floor(initialViewTileX / chunkWidth);
    const centerChunkY = Math.floor(initialViewTileY / chunkHeight);
    const chunkRadius = DEFAULT_WORLD_CHUNK_RADIUS;
    const chunksPayload = await fetchJsonOrThrow<WorldChunksRoutePayload>(
      getContentApiUrl(
        `/api/world/${encodeURIComponent(worldId)}/chunks?chunkX=${centerChunkX}&chunkY=${centerChunkY}&radius=${chunkRadius}&createIfMissing=1`,
        apiBase,
      ),
    );
    const chunks = Array.isArray(chunksPayload?.chunks) ? chunksPayload.chunks : [];
    const originChunkX = centerChunkX - chunkRadius;
    const originChunkY = centerChunkY - chunkRadius;
    const composedWidth = ((chunkRadius * 2) + 1) * chunkWidth;
    const composedHeight = ((chunkRadius * 2) + 1) * chunkHeight;
    const imagesPayload = normalizeImagesPayloadSnapshot(contentByType.images || { schemaVersion: 1, images: [] });
    contentByType.images = imagesPayload;
    const spritePayload = buildSpritesPayloadFromImagesPayload(imagesPayload);
    const spriteRecords = spritePayload && Array.isArray(spritePayload.sprites)
      ? spritePayload.sprites.filter((entry): entry is JsonObject => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry))
      : [];
    const tilePayload = buildTilesPayloadFromImagesPayload(imagesPayload);
    const tileRecords = tilePayload && Array.isArray(tilePayload.tiles)
      ? tilePayload.tiles.filter((entry): entry is JsonObject => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry))
      : [];
    const npcsPayload = contentByType.npcs;
    const allNpcRecords = npcsPayload && Array.isArray(npcsPayload.npcs)
      ? npcsPayload.npcs.filter((entry): entry is JsonObject => Boolean(entry) && typeof entry === "object" && !Array.isArray(entry))
      : [];
    const spriteCatalog = buildSpriteCatalog(spriteRecords, buildSpritePreviewDataUrl);
    const tileCatalogById = buildTileCatalogById(tileRecords, buildSpritePreviewDataUrl);
    const roomLayers = composeWorldRoomLayers(chunks, chunkWidth, chunkHeight, originChunkX, originChunkY, composedWidth, composedHeight);
    const heightLayers = composeWorldHeightLayers(chunks, chunkWidth, chunkHeight, originChunkX, originChunkY);
    const npcOverlays = buildNpcOverlaysFromWorldChunks(chunks, spriteCatalog, chunkWidth, chunkHeight, originChunkX, originChunkY);
    const bootstrap: WorldshaperStudioBootstrap = {
      mapId: worldId,
      mapName: String(world.name || worldId),
      width: composedWidth,
      height: composedHeight,
      tileSize: Math.max(8, Number(world.tileSize) || 32),
      backgroundTileId: String(world.defaultBackgroundTileId || "").trim(),
      roomLayers,
      heightLayers,
      tileColors: TILE_COLORS,
      baseRows: resizeRows(roomLayers.find((layer) => Number(layer.layer) === 0)?.rows || [], composedWidth, composedHeight, "."),
      npcOverlays,
      contentByType,
      spriteCatalog,
      tileCatalogById,
      defaultNpcTemplate: normalizeNpcRecordForLoad(buildDefaultRecord("npcs", allNpcRecords)),
      apiBase,
      backgroundColor: normalizeMapBackgroundColor((world as Record<string, unknown>).backgroundColor || "#060A14"),
      heightBlurStep: normalizeHeightBlurStep(world.heightBlurStep ?? world.heightDetailStep),
      editorUi: hasMeaningfulBootstrapEditorUi(world?.editorUi)
        ? normalizeBootstrapEditorUi(world?.editorUi)
        : normalizeBootstrapEditorUi(cachedBootstrap?.editorUi),
      sourceMode: "world",
      worldId,
      worldName: String(world.name || worldId),
      worldChunkWidth: chunkWidth,
      worldChunkHeight: chunkHeight,
      worldOriginChunkX: originChunkX,
      worldOriginChunkY: originChunkY,
      worldChunkRadius: chunkRadius,
      worldTileOffsetX: originChunkX * chunkWidth,
      worldTileOffsetY: originChunkY * chunkHeight,
      worldSpawnX: spawnX,
      worldSpawnY: spawnY,
      worldBookmarks: bookmarks,
      sourceChunks: chunks.map((chunk) => ({
        chunkX: Math.floor(Number(chunk.chunkX) || 0),
        chunkY: Math.floor(Number(chunk.chunkY) || 0),
      })),
    };
    cacheStandaloneWorldshaperBootstrap(bootstrap, window);
    return bootstrap;
  } catch (error) {
    if (cachedBootstrap) {
      return cachedBootstrap;
    }
    throw error;
  }
}

