// @ts-nocheck

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

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

export function composeWorldRoomLayers(chunks, chunkWidth, chunkHeight, originChunkX, originChunkY, worldWidth, worldHeight) {
  const layerMap = new Map();
  (Array.isArray(chunks) ? 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);
      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;
        }
        const maxWidth = Math.max(0, worldWidth - offsetX);
        writeRowSegment(targetLayer.rows, targetY, offsetX, row.slice(0, maxWidth));
      });
      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) => (Number(a.layer) || 0) - (Number(b.layer) || 0));
}

export function composeWorldHeightLayers(chunks, chunkWidth, chunkHeight, originChunkX, originChunkY) {
  const patches = [];
  (Array.isArray(chunks) ? 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));
  });
}

export function buildWorldLayerMetadata(chunks) {
  const layerMap = new Map();
  (Array.isArray(chunks) ? chunks : []).forEach((chunk) => {
    const rawLayers = Array.isArray(chunk?.roomLayers) ? chunk.roomLayers : [];
    rawLayers.forEach((rawLayer) => {
      const layerNumber = Number(rawLayer?.layer) || 0;
      if (layerMap.has(layerNumber)) {
        return;
      }
      layerMap.set(layerNumber, {
        layer: layerNumber,
        name: typeof rawLayer?.name === "string" && String(rawLayer.name).trim() ? String(rawLayer.name).trim() : undefined,
        rows: [],
        instanceIds: Array.isArray(rawLayer?.instanceIds) ? rawLayer.instanceIds.map((entry) => String(entry || "").trim()).filter(Boolean) : [],
      });
    });
  });
  if (!layerMap.has(0)) {
    layerMap.set(0, {
      layer: 0,
      rows: [],
      instanceIds: [],
    });
  }
  if (!Array.from(layerMap.keys()).some((layerNumber) => layerNumber > 0)) {
    layerMap.set(1, {
      layer: 1,
      rows: [],
      instanceIds: [],
    });
  }
  return Array.from(layerMap.values()).sort((a, b) => (Number(a.layer) || 0) - (Number(b.layer) || 0));
}

export function sliceNormalizedRows(rows, startX, startY, width, height, fillChar) {
  return Array.from({ length: Math.max(1, Number(height) || 1) }, (_, rowOffset) => {
    const sourceRow = String((Array.isArray(rows) ? rows[startY + rowOffset] : "") || "");
    const paddedRow = sourceRow.length >= startX + width
      ? sourceRow
      : sourceRow + String(fillChar || " ").repeat(Math.max(0, (startX + width) - sourceRow.length));
    return paddedRow.slice(startX, startX + width);
  });
}

export function buildChunkHeightLayersFromDocument({ mapDocument, cloneHeightLayers, baseTileX, baseTileY, chunkWidth, chunkHeight }) {
  return (Array.isArray(mapDocument.heightLayers) ? cloneHeightLayers(mapDocument.heightLayers) : [])
    .map((entry) => {
      const patchX = Math.max(0, Number(entry?.x) || 0);
      const patchY = Math.max(0, Number(entry?.y) || 0);
      const rows = Array.isArray(entry?.rows) ? entry.rows.map((row) => String(row || "")) : [];
      const patchWidth = rows.reduce((max, row) => Math.max(max, row.length), 0);
      const patchHeight = rows.length;
      const patchRight = patchX + patchWidth;
      const patchBottom = patchY + patchHeight;
      const chunkRight = baseTileX + chunkWidth;
      const chunkBottom = baseTileY + chunkHeight;
      const overlapLeft = Math.max(baseTileX, patchX);
      const overlapTop = Math.max(baseTileY, patchY);
      const overlapRight = Math.min(chunkRight, patchRight);
      const overlapBottom = Math.min(chunkBottom, patchBottom);
      if (overlapRight <= overlapLeft || overlapBottom <= overlapTop) {
        return null;
      }
      const localRows = [];
      for (let y = overlapTop; y < overlapBottom; y += 1) {
        const sourceRow = String(rows[y - patchY] || "");
        localRows.push(sourceRow.slice(overlapLeft - patchX, overlapRight - patchX).replace(/\s+$/g, ""));
      }
      return {
        id: String(entry?.id || "").trim(),
        name: typeof entry?.name === "string" && entry.name.trim() ? entry.name.trim() : undefined,
        z: Math.max(1, Number(entry?.z) || 1),
        x: overlapLeft - baseTileX,
        y: overlapTop - baseTileY,
        rows: localRows,
      };
    })
    .filter((entry) => entry && entry.id);
}

export function buildChunkInstancesFromDocument({ mapDocument, cloneValue, baseTileX, baseTileY, chunkWidth, chunkHeight, tileOffsetX, tileOffsetY }) {
  const chunkInstances = cloneValue(mapDocument.npcOverlays)
    .filter((npc) => {
      const localX = Math.floor(Number(npc?.x));
      const localY = Math.floor(Number(npc?.y));
      return Number.isFinite(localX)
        && Number.isFinite(localY)
        && localX >= baseTileX
        && localX < baseTileX + chunkWidth
        && localY >= baseTileY
        && localY < baseTileY + chunkHeight;
    })
    .map((npc) => ({
      id: String(npc.id || "").trim(),
      templateId: String(npc?.record?.templateId || "").trim(),
      layer: Number(npc.layer) || 0,
      x: Math.floor(Number(npc.x) || 0) - baseTileX,
      y: Math.floor(Number(npc.y) || 0) - baseTileY,
      record: {
        ...cloneValue(npc.record || {}),
        id: String(npc.id || "").trim(),
        layer: Number(npc.layer) || 0,
        templateId: String(npc?.record?.templateId || "").trim(),
        name: String(npc.name || npc?.record?.name || ""),
        entityType: String(npc?.record?.entityType || npc?.entityType || "friendly"),
        faction: String(npc.faction || npc?.record?.faction || ""),
        spriteId: String(npc.spriteId || npc?.record?.spriteId || ""),
        dialogueId: String(npc.dialogueId || npc?.record?.dialogueId || ""),
        description: String(npc.description || npc?.record?.description || ""),
        tags: cloneValue(npc?.record?.tags) || [],
        enabled: typeof npc?.record?.enabled === "boolean" ? npc.record.enabled : true,
        position: {
          x: Math.floor(Number(npc.x) || 0) + tileOffsetX,
          y: Math.floor(Number(npc.y) || 0) + tileOffsetY,
        },
      },
    }))
    .filter((entry) => entry.id);
  const npcIdsByLayer = new Map();
  chunkInstances.forEach((entry) => {
    const layerNumber = Number(entry.layer) || 0;
    if (!npcIdsByLayer.has(layerNumber)) {
      npcIdsByLayer.set(layerNumber, []);
    }
    npcIdsByLayer.get(layerNumber).push(entry.id);
  });
  return {
    chunkInstances,
    npcIdsByLayer,
  };
}

export function normalizeWorldChunkRows(rows, width, height, fillChar) {
  const safeWidth = Math.max(1, Math.floor(Number(width) || 1));
  const safeHeight = Math.max(1, Math.floor(Number(height) || 1));
  return Array.from({ length: safeHeight }, (_entry, rowIndex) => {
    const sourceRow = String((Array.isArray(rows) ? rows[rowIndex] : "") || "");
    return sourceRow.length >= safeWidth
      ? sourceRow.slice(0, safeWidth)
      : (sourceRow + String(fillChar || " ").repeat(Math.max(0, safeWidth - sourceRow.length)));
  });
}

export function cloneWorldChunkHeightLayers(source) {
  return (Array.isArray(source) ? source : [])
    .map((entry, index) => ({
      id: String(entry?.id || `height_patch_${index + 1}`).trim() || `height_patch_${index + 1}`,
      name: typeof entry?.name === "string" && entry.name.trim() ? entry.name.trim() : undefined,
      z: Math.max(1, Math.floor(Number(entry?.z) || 1)),
      x: Math.max(0, Math.floor(Number(entry?.x) || 0)),
      y: Math.max(0, Math.floor(Number(entry?.y) || 0)),
      rows: Array.isArray(entry?.rows) ? entry.rows.map((row) => String(row || "")) : [],
    }))
    .filter((entry) => entry.id);
}

export function buildWorldChunkLayerInstanceIds(roomLayers, instances, width, height) {
  const safeWidth = Math.max(1, Math.floor(Number(width) || 1));
  const safeHeight = Math.max(1, Math.floor(Number(height) || 1));
  const nextLayers = new Map();
  (Array.isArray(roomLayers) ? roomLayers : []).forEach((layer) => {
    const layerNumber = Math.max(0, Math.floor(Number(layer?.layer) || 0));
    nextLayers.set(layerNumber, {
      layer: layerNumber,
      name: typeof layer?.name === "string" && layer.name.trim() ? layer.name.trim() : undefined,
      rows: normalizeWorldChunkRows(layer?.rows, safeWidth, safeHeight, layerNumber === 0 ? "." : " "),
      instanceIds: [],
    });
  });
  if (!nextLayers.has(0)) {
    nextLayers.set(0, {
      layer: 0,
      rows: normalizeWorldChunkRows([], safeWidth, safeHeight, "."),
      instanceIds: [],
    });
  }
  if (!Array.from(nextLayers.keys()).some((layerNumber) => layerNumber > 0)) {
    nextLayers.set(1, {
      layer: 1,
      rows: normalizeWorldChunkRows([], safeWidth, safeHeight, " "),
      instanceIds: [],
    });
  }
  (Array.isArray(instances) ? instances : []).forEach((entry) => {
    const layerNumber = Math.max(0, Math.floor(Number(entry?.layer) || 0));
    const instanceId = String(entry?.id || "").trim();
    if (!instanceId) {
      return;
    }
    if (!nextLayers.has(layerNumber)) {
      nextLayers.set(layerNumber, {
        layer: layerNumber,
        rows: normalizeWorldChunkRows([], safeWidth, safeHeight, layerNumber === 0 ? "." : " "),
        instanceIds: [],
      });
    }
    nextLayers.get(layerNumber).instanceIds.push(instanceId);
  });
  return Array.from(nextLayers.values())
    .map((entry) => ({
      ...entry,
      instanceIds: Array.from(new Set((Array.isArray(entry.instanceIds) ? entry.instanceIds : []).map((id) => String(id || "").trim()).filter(Boolean))),
    }))
    .sort((left, right) => (Number(left.layer) || 0) - (Number(right.layer) || 0));
}

export function normalizeWorldChunkInstances({ sourceInstances, chunkX, chunkY, width, height, options, cloneValue, runtimeUniqueId }) {
  const config = options && typeof options === "object" ? options : {};
  const duplicateIds = config.duplicateIds === true;
  const safeChunkX = Math.floor(Number(chunkX) || 0);
  const safeChunkY = Math.floor(Number(chunkY) || 0);
  const safeWidth = Math.max(1, Math.floor(Number(width) || 1));
  const safeHeight = Math.max(1, Math.floor(Number(height) || 1));
  return (Array.isArray(sourceInstances) ? sourceInstances : [])
    .map((entry) => {
      const record = entry?.record && typeof entry.record === "object" && !Array.isArray(entry.record)
        ? cloneValue(entry.record)
        : {};
      const nextId = duplicateIds
        ? runtimeUniqueId()
        : (String(entry?.id || record?.id || runtimeUniqueId()).trim() || runtimeUniqueId());
      const nextLayer = Math.max(0, Math.floor(Number(entry?.layer ?? record?.layer) || 0));
      const nextX = Math.max(0, Math.min(safeWidth - 1, Math.floor(Number(entry?.x) || 0)));
      const nextY = Math.max(0, Math.min(safeHeight - 1, Math.floor(Number(entry?.y) || 0)));
      const nextTemplateId = String(entry?.templateId || record?.templateId || "").trim();
      record.id = nextId;
      record.layer = nextLayer;
      record.templateId = nextTemplateId;
      record.position = {
        x: (safeChunkX * safeWidth) + nextX,
        y: (safeChunkY * safeHeight) + nextY,
      };
      return {
        id: nextId,
        templateId: nextTemplateId,
        layer: nextLayer,
        x: nextX,
        y: nextY,
        record,
      };
    })
    .filter((entry) => entry.id);
}

export function createEmptyWorldChunkPayload({ chunkX, chunkY, chunkWidth, chunkHeight, worldId }) {
  const safeChunkX = Math.floor(Number(chunkX) || 0);
  const safeChunkY = Math.floor(Number(chunkY) || 0);
  return {
    schemaVersion: 1,
    worldId: String(worldId || "").trim(),
    chunkX: safeChunkX,
    chunkY: safeChunkY,
    width: chunkWidth,
    height: chunkHeight,
    backgroundTileId: "",
    roomLayers: [
      {
        layer: 0,
        rows: Array.from({ length: chunkHeight }, () => ".".repeat(chunkWidth)),
        instanceIds: [],
      },
      {
        layer: 1,
        rows: Array.from({ length: chunkHeight }, () => " ".repeat(chunkWidth)),
        instanceIds: [],
      },
    ],
    heightLayers: [],
    instances: [],
  };
}

export function normalizeCachedWorldChunkPayload({ chunkPayload, chunkX, chunkY, chunkWidth, chunkHeight, worldId, cloneValue, runtimeUniqueId, options }) {
  const safeChunkX = Math.floor(Number(chunkX ?? chunkPayload?.chunkX) || 0);
  const safeChunkY = Math.floor(Number(chunkY ?? chunkPayload?.chunkY) || 0);
  const safeWidth = Math.max(1, Math.floor(Number(chunkPayload?.width) || Number(chunkWidth) || 32));
  const safeHeight = Math.max(1, Math.floor(Number(chunkPayload?.height) || Number(chunkHeight) || 32));
  const instances = normalizeWorldChunkInstances({
    sourceInstances: chunkPayload?.instances,
    chunkX: safeChunkX,
    chunkY: safeChunkY,
    width: safeWidth,
    height: safeHeight,
    options,
    cloneValue,
    runtimeUniqueId,
  });
  const roomLayers = buildWorldChunkLayerInstanceIds(chunkPayload?.roomLayers, instances, safeWidth, safeHeight);
  return {
    schemaVersion: Math.max(1, Math.floor(Number(chunkPayload?.schemaVersion) || 1)),
    worldId: String(chunkPayload?.worldId || worldId || "").trim(),
    chunkX: safeChunkX,
    chunkY: safeChunkY,
    width: safeWidth,
    height: safeHeight,
    backgroundTileId: String(chunkPayload?.backgroundTileId || "").trim(),
    roomLayers,
    heightLayers: cloneWorldChunkHeightLayers(chunkPayload?.heightLayers),
    instances,
  };
}

export function isChunkFillSymbol(ch, fillChar) {
  const symbol = String(ch || "").charAt(0);
  return !symbol || symbol === fillChar || symbol === "." || symbol === " ";
}

export function isWorldChunkPayloadEmpty({ chunkPayload, chunkWidth, chunkHeight, worldId, cloneValue, runtimeUniqueId }) {
  const normalized = normalizeCachedWorldChunkPayload({
    chunkPayload,
    chunkX: chunkPayload?.chunkX,
    chunkY: chunkPayload?.chunkY,
    chunkWidth,
    chunkHeight,
    worldId,
    cloneValue,
    runtimeUniqueId,
  });
  if (String(normalized?.backgroundTileId || "").trim()) {
    return false;
  }
  if (Array.isArray(normalized?.instances) && normalized.instances.length > 0) {
    return false;
  }
  if ((Array.isArray(normalized?.heightLayers) ? normalized.heightLayers : []).some((entry) => (
    Array.isArray(entry?.rows) && entry.rows.some((row) => /[^ .]/.test(String(row || "")))
  ))) {
    return false;
  }
  return !(Array.isArray(normalized?.roomLayers) ? normalized.roomLayers : []).some((layer) => {
    const fillChar = (Number(layer?.layer) || 0) === 0 ? "." : " ";
    return (Array.isArray(layer?.rows) ? layer.rows : []).some((row) => {
      const sourceRow = String(row || "");
      for (let index = 0; index < sourceRow.length; index += 1) {
        if (!isChunkFillSymbol(sourceRow.charAt(index), fillChar)) {
          return true;
        }
      }
      return false;
    });
  });
}

export function transformChunkLocalCoord(localX, localY, width, height, operation) {
  const safeX = Math.floor(Number(localX) || 0);
  const safeY = Math.floor(Number(localY) || 0);
  const safeWidth = Math.max(1, Math.floor(Number(width) || 1));
  const safeHeight = Math.max(1, Math.floor(Number(height) || 1));
  switch (String(operation || "").trim()) {
    case "flipHorizontal":
      return { x: (safeWidth - 1) - safeX, y: safeY };
    case "flipVertical":
      return { x: safeX, y: (safeHeight - 1) - safeY };
    case "rotate180":
      return { x: (safeWidth - 1) - safeX, y: (safeHeight - 1) - safeY };
    case "rotate90cw":
      if (safeWidth !== safeHeight) {
        return null;
      }
      return { x: (safeWidth - 1) - safeY, y: safeX };
    case "rotate90ccw":
      if (safeWidth !== safeHeight) {
        return null;
      }
      return { x: safeY, y: (safeHeight - 1) - safeX };
    default:
      return { x: safeX, y: safeY };
  }
}

export function transformChunkRows(rows, width, height, fillChar, operation) {
  const safeWidth = Math.max(1, Math.floor(Number(width) || 1));
  const safeHeight = Math.max(1, Math.floor(Number(height) || 1));
  const sourceRows = normalizeWorldChunkRows(rows, safeWidth, safeHeight, fillChar);
  const nextRows = Array.from({ length: safeHeight }, () => Array.from({ length: safeWidth }, () => String(fillChar || " ").charAt(0) || " "));
  for (let rowIndex = 0; rowIndex < safeHeight; rowIndex += 1) {
    const sourceRow = sourceRows[rowIndex];
    for (let columnIndex = 0; columnIndex < safeWidth; columnIndex += 1) {
      const char = String(sourceRow.charAt(columnIndex) || fillChar).charAt(0) || String(fillChar || " ").charAt(0) || " ";
      if (isChunkFillSymbol(char, fillChar)) {
        continue;
      }
      const nextCoord = transformChunkLocalCoord(columnIndex, rowIndex, safeWidth, safeHeight, operation);
      if (!nextCoord) {
        continue;
      }
      nextRows[nextCoord.y][nextCoord.x] = char;
    }
  }
  return nextRows.map((row) => row.join(""));
}

export function transformChunkHeightPatch(patch, width, height, operation) {
  const safeWidth = Math.max(1, Math.floor(Number(width) || 1));
  const safeHeight = Math.max(1, Math.floor(Number(height) || 1));
  const sourceRows = Array.isArray(patch?.rows) ? patch.rows.map((row) => String(row || "")) : [];
  const patchWidth = sourceRows.reduce((max, row) => Math.max(max, row.length), 0);
  const patchHeight = sourceRows.length;
  const transformedCells = [];
  for (let localY = 0; localY < patchHeight; localY += 1) {
    const row = sourceRows[localY] || "";
    for (let localX = 0; localX < patchWidth; localX += 1) {
      const char = String(row.charAt(localX) || " ").charAt(0) || " ";
      if (char === " " || char === ".") {
        continue;
      }
      const worldX = Math.max(0, Math.floor(Number(patch?.x) || 0)) + localX;
      const worldY = Math.max(0, Math.floor(Number(patch?.y) || 0)) + localY;
      if (worldX < 0 || worldY < 0 || worldX >= safeWidth || worldY >= safeHeight) {
        continue;
      }
      const nextCoord = transformChunkLocalCoord(worldX, worldY, safeWidth, safeHeight, operation);
      if (!nextCoord) {
        continue;
      }
      transformedCells.push({
        x: nextCoord.x,
        y: nextCoord.y,
        char,
      });
    }
  }
  if (transformedCells.length <= 0) {
    return null;
  }
  const minX = transformedCells.reduce((min, entry) => Math.min(min, entry.x), transformedCells[0].x);
  const maxX = transformedCells.reduce((max, entry) => Math.max(max, entry.x), transformedCells[0].x);
  const minY = transformedCells.reduce((min, entry) => Math.min(min, entry.y), transformedCells[0].y);
  const maxY = transformedCells.reduce((max, entry) => Math.max(max, entry.y), transformedCells[0].y);
  const nextRows = Array.from({ length: (maxY - minY) + 1 }, () => Array.from({ length: (maxX - minX) + 1 }, () => " "));
  transformedCells.forEach((entry) => {
    nextRows[entry.y - minY][entry.x - minX] = entry.char;
  });
  return {
    id: String(patch?.id || "").trim(),
    name: typeof patch?.name === "string" && patch.name.trim() ? patch.name.trim() : undefined,
    z: Math.max(1, Math.floor(Number(patch?.z) || 1)),
    x: minX,
    y: minY,
    rows: nextRows.map((row) => row.join("").replace(/\s+$/g, "")),
  };
}

export function transformWorldChunkPayload({ chunkPayload, operation, chunkWidth, chunkHeight, worldId, cloneValue, runtimeUniqueId, options }) {
  const config = options && typeof options === "object" ? options : {};
  const normalized = normalizeCachedWorldChunkPayload({
    chunkPayload,
    chunkX: chunkPayload?.chunkX,
    chunkY: chunkPayload?.chunkY,
    chunkWidth,
    chunkHeight,
    worldId,
    cloneValue,
    runtimeUniqueId,
    options: config,
  });
  const safeWidth = Math.max(1, Math.floor(Number(normalized?.width) || 1));
  const safeHeight = Math.max(1, Math.floor(Number(normalized?.height) || 1));
  const normalizedOperation = String(operation || "").trim();
  if ((normalizedOperation === "rotate90cw" || normalizedOperation === "rotate90ccw") && safeWidth !== safeHeight) {
    throw new Error("Chunk rotation requires square chunks.");
  }
  const instances = normalizeWorldChunkInstances({
    sourceInstances: (Array.isArray(normalized.instances) ? normalized.instances : []).map((entry) => {
      const nextCoord = transformChunkLocalCoord(entry.x, entry.y, safeWidth, safeHeight, normalizedOperation);
      return {
        ...cloneValue(entry),
        x: nextCoord?.x ?? entry.x,
        y: nextCoord?.y ?? entry.y,
      };
    }),
    chunkX: normalized.chunkX,
    chunkY: normalized.chunkY,
    width: safeWidth,
    height: safeHeight,
    options: config,
    cloneValue,
    runtimeUniqueId,
  });
  const roomLayers = buildWorldChunkLayerInstanceIds(
    (Array.isArray(normalized.roomLayers) ? normalized.roomLayers : []).map((layer) => ({
      ...cloneValue(layer),
      rows: transformChunkRows(layer?.rows, safeWidth, safeHeight, (Number(layer?.layer) || 0) === 0 ? "." : " ", normalizedOperation),
    })),
    instances,
    safeWidth,
    safeHeight,
  );
  const heightLayers = cloneWorldChunkHeightLayers(normalized.heightLayers)
    .map((entry) => transformChunkHeightPatch(entry, safeWidth, safeHeight, normalizedOperation))
    .filter(Boolean)
    .sort((left, right) => {
      if ((Number(left?.z) || 0) !== (Number(right?.z) || 0)) {
        return (Number(left?.z) || 0) - (Number(right?.z) || 0);
      }
      return String(left?.name || left?.id || "").localeCompare(String(right?.name || right?.id || ""));
    });
  return {
    ...normalized,
    roomLayers,
    heightLayers,
    instances,
  };
}
