var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/plus/pisellTopology/topologyDeviceListView.ts
var topologyDeviceListView_exports = {};
__export(topologyDeviceListView_exports, {
  TOPOLOGY_DEVICE_KIND_PREFIX: () => import_topologyFloorPlanConstants2.TOPOLOGY_DEVICE_KIND_PREFIX,
  TOPOLOGY_DEVICE_KIND_VALUES: () => TOPOLOGY_DEVICE_KIND_VALUES,
  TOPOLOGY_DEVICE_TYPE_CODES: () => TOPOLOGY_DEVICE_TYPE_CODES,
  buildTopologyConnectionAwareSceneElements: () => buildTopologyConnectionAwareSceneElements,
  buildTopologyDeviceDataSources: () => buildTopologyDeviceDataSources,
  buildTopologyDeviceElementKinds: () => buildTopologyDeviceElementKinds,
  buildTopologyEdgesFromConnections: () => buildTopologyEdgesFromConnections,
  buildTopologyFloorMapConfigFromDevices: () => buildTopologyFloorMapConfigFromDevices,
  buildTopologyWorkareaGroupedSceneElements: () => buildTopologyWorkareaGroupedSceneElements,
  collectConnectedComponentDeviceIds: () => collectConnectedComponentDeviceIds,
  deviceIpAddress: () => deviceIpAddress,
  extractRawDeviceConnectionList: () => extractRawDeviceConnectionList,
  extractRawDeviceList: () => extractRawDeviceList,
  getConnectionTypeStyle: () => getConnectionTypeStyle,
  reconcileTopologyView: () => reconcileTopologyView
});
module.exports = __toCommonJS(topologyDeviceListView_exports);
var import_materials = require("@pisell/materials");
var import_topologyFloorPlanConstants = require("./topologyFloorPlanConstants");
var import_topologyLocale = require("./topologyLocale");
var import_topologyFloorPlanConstants2 = require("./topologyFloorPlanConstants");
var NODE_WIDTH = 132;
var NODE_HEIGHT = 72;
var NODE_GAP = 56;
var LAYER_GAP_Y = 56;
var CLUSTER_GAP = 56;
var CLUSTER_ROW_MAX_WIDTH = 1400;
var PADDING = 40;
var ZONE_INNER_PADDING = 32;
var ZONE_TITLE_TOP = 20;
var GROUP_GAP = 32;
var DEVICE_CATEGORY_ID = "devices";
var TOPOLOGY_DEVICE_TYPE_CODES = [
  "pos",
  "receipt_printer",
  "label_printer",
  "switch",
  "info_display",
  "terminal",
  "chenlei",
  "test1"
];
var TYPE_CODE_LABEL = {
  pos: "POS",
  receipt_printer: "小票打印机",
  label_printer: "标签打印机",
  switch: "交换机",
  info_display: "显示屏",
  terminal: "终端",
  chenlei: "chenlei",
  test1: "test1"
};
function typeCodeToKindValue(code) {
  return `${import_topologyFloorPlanConstants.TOPOLOGY_DEVICE_KIND_PREFIX}${code}`;
}
var TOPOLOGY_DEVICE_KIND_VALUES = [
  ...TOPOLOGY_DEVICE_TYPE_CODES.map(typeCodeToKindValue),
  `${import_topologyFloorPlanConstants.TOPOLOGY_DEVICE_KIND_PREFIX}unknown`
];
function extractRawDeviceList(response) {
  if (Array.isArray(response)) return response;
  if (response && typeof response === "object") {
    const arr = response.data;
    if (Array.isArray(arr)) return arr;
  }
  return [];
}
function extractRawDeviceConnectionList(response) {
  if (Array.isArray(response)) return response;
  if (response && typeof response === "object") {
    const arr = response.data;
    if (Array.isArray(arr)) return arr;
  }
  return [];
}
function pickLangText(source, fallback) {
  if (typeof source === "string") return source.trim() || fallback;
  if (!source || typeof source !== "object") return fallback;
  const candidates = [
    source["zh-CN"],
    source["zh-HK"],
    source.en,
    source.original
  ];
  for (const v of candidates) {
    if (typeof v === "string" && v.trim()) return v.trim();
  }
  return fallback;
}
function deviceDisplayName(device) {
  var _a;
  return pickLangText(device.name, void 0) ?? pickLangText((_a = device.model) == null ? void 0 : _a.name, void 0) ?? device.number ?? `#${device.id}`;
}
function deviceIpAddress(device) {
  const data = device.data;
  if (data && typeof data === "object") {
    const network = data.network;
    if (network && typeof network === "object" && !Array.isArray(network)) {
      const lip = network.local_ip;
      if (typeof lip === "string" && lip.trim()) return lip.trim();
    }
  }
  return void 0;
}
function deviceStatus(device) {
  switch (device.status) {
    case "online":
      return "online";
    case "offline":
      return "offline";
    case "warning":
      return "warning";
    default:
      return "unknown";
  }
}
function buildTopologyDeviceDataSources(rawDevices) {
  const records = rawDevices.map((device) => {
    var _a;
    return {
      id: String(device.id),
      name: deviceDisplayName(device),
      model: pickLangText((_a = device.model) == null ? void 0 : _a.name, void 0) ?? device.model_code ?? void 0,
      sn: device.number ?? void 0,
      status: deviceStatus(device),
      ip: deviceIpAddress(device)
    };
  });
  return { [import_topologyFloorPlanConstants.TOPOLOGY_DEVICES_DATA_SOURCE_KEY]: records };
}
function buildTopologyDeviceElementKinds(displayLocale = "en") {
  const typeCodeToKind = /* @__PURE__ */ new Map();
  const kinds = TOPOLOGY_DEVICE_TYPE_CODES.map(
    (code) => {
      const value = typeCodeToKindValue(code);
      typeCodeToKind.set(code, value);
      return {
        value,
        label: TYPE_CODE_LABEL[code] ?? code,
        categoryId: DEVICE_CATEGORY_ID,
        dataBindingPolicy: "optional",
        allowedDataSourceKeys: [import_topologyFloorPlanConstants.TOPOLOGY_DEVICES_DATA_SOURCE_KEY],
        showInPalette: false
      };
    }
  );
  kinds.push({
    value: `${import_topologyFloorPlanConstants.TOPOLOGY_DEVICE_KIND_PREFIX}unknown`,
    label: "Unknown",
    categoryId: DEVICE_CATEGORY_ID,
    dataBindingPolicy: "optional",
    allowedDataSourceKeys: [import_topologyFloorPlanConstants.TOPOLOGY_DEVICES_DATA_SOURCE_KEY],
    showInPalette: false
  });
  kinds.push({
    value: import_materials.FLOOR_MAP_SELECTION_ZONE_ELEMENT_KIND,
    label: (0, import_topologyLocale.getTopologyCategoryAreaLabel)(displayLocale),
    categoryId: DEVICE_CATEGORY_ID,
    dataBindingPolicy: "none",
    showInPalette: false
  });
  const categories = [
    {
      id: DEVICE_CATEGORY_ID,
      label: (0, import_topologyLocale.getTopologyCategoryDevicesLabel)(displayLocale),
      order: 0
    }
  ];
  return { categories, kinds, typeCodeToKind };
}
function buildAdjacency(rawDevices, rawConnections) {
  const adj = /* @__PURE__ */ new Map();
  for (const d of rawDevices) {
    adj.set(String(d.id), /* @__PURE__ */ new Set());
  }
  for (const c of rawConnections) {
    const s = String(c.source_device_id);
    const t = String(c.target_device_id);
    if (s === t) continue;
    if (!adj.has(s) || !adj.has(t)) continue;
    adj.get(s).add(t);
    adj.get(t).add(s);
  }
  return adj;
}
function collectConnectedComponentDeviceIds(rawDevices, rawConnections, anchorId) {
  if (!rawDevices.some((d) => String(d.id) === anchorId)) return null;
  const adj = buildAdjacency(rawDevices, rawConnections);
  const components = findConnectedComponents(rawDevices, adj);
  for (const comp of components) {
    if (comp.includes(anchorId)) return new Set(comp);
  }
  return /* @__PURE__ */ new Set([anchorId]);
}
function findConnectedComponents(rawDevices, adj) {
  const visited = /* @__PURE__ */ new Set();
  const components = [];
  for (const d of rawDevices) {
    const id = String(d.id);
    if (visited.has(id)) continue;
    const queue = [id];
    const comp = [];
    while (queue.length) {
      const cur = queue.shift();
      if (visited.has(cur)) continue;
      visited.add(cur);
      comp.push(cur);
      for (const n of adj.get(cur) ?? []) {
        if (!visited.has(n)) queue.push(n);
      }
    }
    components.push(comp);
  }
  return components;
}
var DEVICE_LAYER_ORDER = ["smart", "dumb", "integrated"];
function classifyDeviceLayer(device) {
  if (device.type_kind === "dumb") return "dumb";
  if (device.type_kind === "integrated") return "integrated";
  return "smart";
}
function snakeCenterByDegree(ids, adj) {
  if (ids.length <= 1) return [...ids];
  const sorted = [...ids].sort((a, b) => {
    var _a, _b;
    const da = ((_a = adj.get(a)) == null ? void 0 : _a.size) ?? 0;
    const db = ((_b = adj.get(b)) == null ? void 0 : _b.size) ?? 0;
    if (db !== da) return db - da;
    return ids.indexOf(a) - ids.indexOf(b);
  });
  const result = [];
  sorted.forEach((id, idx) => {
    if (idx % 2 === 0) result.push(id);
    else result.unshift(id);
  });
  return result;
}
function avgConnectedIdx(id, adj, referenceIdx, fallbackLen) {
  const neighbors = adj.get(id);
  if (!neighbors || neighbors.size === 0) return fallbackLen;
  let sum = 0;
  let cnt = 0;
  for (const n of neighbors) {
    const idx = referenceIdx.get(n);
    if (idx == null) continue;
    sum += idx;
    cnt += 1;
  }
  return cnt === 0 ? fallbackLen : sum / cnt;
}
function sortLayerByReference(target, reference, adj) {
  if (target.length <= 1 || reference.length === 0) return;
  const refIdx = new Map(
    reference.map((id, idx) => [id, idx])
  );
  target.sort(
    (a, b) => avgConnectedIdx(a, adj, refIdx, target.length) - avgConnectedIdx(b, adj, refIdx, target.length)
  );
}
function layoutClusterByKind(comp, adj, deviceById) {
  if (comp.length === 1) {
    return {
      positions: /* @__PURE__ */ new Map([[comp[0], { x: 0, y: 0 }]]),
      width: NODE_WIDTH,
      height: NODE_HEIGHT,
      size: 1
    };
  }
  const byLayer = {
    smart: [],
    dumb: [],
    integrated: []
  };
  for (const id of comp) {
    const device = deviceById.get(id);
    if (!device) continue;
    byLayer[classifyDeviceLayer(device)].push(id);
  }
  const layers = DEVICE_LAYER_ORDER.map((k) => byLayer[k]);
  if (layers[0].length > 0) {
    layers[0] = snakeCenterByDegree(layers[0], adj);
  }
  for (let i = 1; i < layers.length; i++) {
    sortLayerByReference(layers[i], layers[i - 1], adj);
  }
  const nonEmpty = layers.filter((l) => l.length > 0);
  const widths = nonEmpty.map(
    (row) => row.length * NODE_WIDTH + (row.length - 1) * NODE_GAP
  );
  const width = Math.max(...widths, NODE_WIDTH);
  const height = nonEmpty.length * NODE_HEIGHT + (nonEmpty.length - 1) * LAYER_GAP_Y;
  const positions = /* @__PURE__ */ new Map();
  let y = 0;
  for (const row of layers) {
    if (row.length === 0) continue;
    const rowWidth = row.length * NODE_WIDTH + (row.length - 1) * NODE_GAP;
    const startX = (width - rowWidth) / 2;
    row.forEach((id, idx) => {
      positions.set(id, {
        x: startX + idx * (NODE_WIDTH + NODE_GAP),
        y
      });
    });
    y += NODE_HEIGHT + LAYER_GAP_Y;
  }
  return { positions, width, height, size: comp.length };
}
function packClusters(clusters, gap = CLUSTER_GAP, rowMaxWidth = CLUSTER_ROW_MAX_WIDTH) {
  let rowX = 0;
  let rowY = 0;
  let rowMaxH = 0;
  let totalRight = 0;
  let totalBottom = 0;
  const placements = [];
  for (const cluster of clusters) {
    if (rowX > 0 && rowX + cluster.width > rowMaxWidth) {
      rowY += rowMaxH + gap;
      rowX = 0;
      rowMaxH = 0;
    }
    placements.push({ cluster, offsetX: rowX, offsetY: rowY });
    rowX += cluster.width + gap;
    rowMaxH = Math.max(rowMaxH, cluster.height);
    totalRight = Math.max(totalRight, rowX - gap);
    totalBottom = Math.max(totalBottom, rowY + cluster.height);
  }
  return { placements, totalRight, totalBottom };
}
function splitByLayer(ids, deviceById) {
  const out = {
    smart: [],
    dumb: [],
    integrated: []
  };
  for (const id of ids) {
    const device = deviceById.get(id);
    if (!device) continue;
    out[classifyDeviceLayer(device)].push(id);
  }
  return out;
}
function placeIsolatedRow(ids, startX, startY, positions) {
  if (ids.length === 0) return { width: 0, height: 0 };
  const cols = Math.max(
    1,
    Math.min(ids.length, Math.ceil(Math.sqrt(ids.length * 1.5)))
  );
  const rows = Math.ceil(ids.length / cols);
  ids.forEach((id, idx) => {
    const col = idx % cols;
    const row = Math.floor(idx / cols);
    positions.set(id, {
      x: startX + col * (NODE_WIDTH + NODE_GAP),
      y: startY + row * (NODE_HEIGHT + NODE_GAP)
    });
  });
  const width = cols * NODE_WIDTH + (cols - 1) * NODE_GAP;
  const height = rows * NODE_HEIGHT + (rows - 1) * NODE_GAP;
  return { width, height };
}
function buildDeviceSceneElement(device, x, y, typeCodeToKind) {
  return {
    instanceId: `topology-device-${device.id}`,
    canvasId: import_topologyFloorPlanConstants.TOPOLOGY_MAIN_CANVAS_ID,
    x: Math.round(x),
    y: Math.round(y),
    width: NODE_WIDTH,
    height: NODE_HEIGHT,
    elementKind: resolveDeviceKind(device, typeCodeToKind),
    name: deviceDisplayName(device),
    dataBinding: {
      dataSourceKey: import_topologyFloorPlanConstants.TOPOLOGY_DEVICES_DATA_SOURCE_KEY,
      recordId: String(device.id)
    }
  };
}
function computeDeviceBlockLayout(devices, connections) {
  const positions = /* @__PURE__ */ new Map();
  if (devices.length === 0) return { positions, width: 0, height: 0 };
  const deviceById = new Map(
    devices.map((d) => [String(d.id), d])
  );
  const adj = buildAdjacency(devices, connections);
  const components = findConnectedComponents(devices, adj);
  const connectedComps = components.filter((c) => c.length > 1);
  const isolatedIds = components.filter((c) => c.length === 1).map((c) => c[0]);
  const laidClusters = connectedComps.map((c) => layoutClusterByKind(c, adj, deviceById)).sort((a, b) => b.size - a.size);
  const { placements, totalBottom: clusterTotalBottom } = packClusters(laidClusters);
  let maxRight = 0;
  let maxBottom = 0;
  for (const p of placements) {
    for (const [id, pos] of p.cluster.positions) {
      const x = p.offsetX + pos.x;
      const y = p.offsetY + pos.y;
      positions.set(id, { x, y });
      maxRight = Math.max(maxRight, x + NODE_WIDTH);
      maxBottom = Math.max(maxBottom, y + NODE_HEIGHT);
    }
  }
  if (isolatedIds.length > 0) {
    const isoByLayer = splitByLayer(isolatedIds, deviceById);
    let isoY = clusterTotalBottom > 0 ? clusterTotalBottom + CLUSTER_GAP : 0;
    for (const layer of DEVICE_LAYER_ORDER) {
      const row = isoByLayer[layer];
      if (row.length === 0) continue;
      const rect = placeIsolatedRow(row, 0, isoY, positions);
      maxRight = Math.max(maxRight, rect.width);
      maxBottom = Math.max(maxBottom, isoY + rect.height);
      isoY += rect.height + LAYER_GAP_Y;
    }
  }
  return { positions, width: maxRight, height: maxBottom };
}
function buildTopologyConnectionAwareSceneElements(rawDevices, rawConnections, typeCodeToKind) {
  if (rawDevices.length === 0) {
    return { sceneElements: [] };
  }
  const { positions } = computeDeviceBlockLayout(rawDevices, rawConnections);
  const sceneElements = rawDevices.map((device) => {
    const pos = positions.get(String(device.id)) ?? { x: 0, y: 0 };
    return buildDeviceSceneElement(
      device,
      PADDING + pos.x,
      PADDING + pos.y,
      typeCodeToKind
    );
  });
  return { sceneElements };
}
function getDeviceWorkareaKey(device) {
  var _a;
  const raw = ((_a = device.workarea) == null ? void 0 : _a.id) ?? device.workarea_id;
  if (raw == null) return null;
  const key = String(raw).trim();
  if (!key || key === "0") return null;
  return key;
}
function groupDevicesByWorkarea(devices) {
  var _a, _b;
  const map = /* @__PURE__ */ new Map();
  const ungrouped = [];
  for (const device of devices) {
    const key = getDeviceWorkareaKey(device);
    if (key == null) {
      ungrouped.push(device);
      continue;
    }
    let group = map.get(key);
    if (!group) {
      group = {
        workareaId: key,
        name: pickLangText((_a = device.workarea) == null ? void 0 : _a.name, void 0) ?? `Workarea ${key}`,
        sort: typeof ((_b = device.workarea) == null ? void 0 : _b.sort) === "number" ? device.workarea.sort : 0,
        devices: []
      };
      map.set(key, group);
    }
    group.devices.push(device);
  }
  const groups = [...map.values()].sort(
    (a, b) => a.sort - b.sort || a.name.localeCompare(b.name)
  );
  if (ungrouped.length > 0) {
    groups.push({
      workareaId: null,
      name: "",
      sort: Number.MAX_SAFE_INTEGER,
      devices: ungrouped
    });
  }
  return groups;
}
function buildTopologyWorkareaGroupedSceneElements(rawDevices, rawConnections, typeCodeToKind) {
  if (rawDevices.length === 0) {
    return { sceneElements: [] };
  }
  const groups = groupDevicesByWorkarea(rawDevices);
  const blocks = groups.map((group) => {
    const hasZone = group.workareaId != null;
    const idSet = new Set(group.devices.map((d) => String(d.id)));
    const intraConnections = rawConnections.filter(
      (c) => idSet.has(String(c.source_device_id)) && idSet.has(String(c.target_device_id))
    );
    const block = computeDeviceBlockLayout(group.devices, intraConnections);
    const innerPad = hasZone ? ZONE_INNER_PADDING : 0;
    const titleTop = hasZone ? ZONE_TITLE_TOP : 0;
    return {
      group,
      hasZone,
      block,
      innerPad,
      titleTop,
      outerW: block.width + innerPad * 2,
      outerH: block.height + innerPad * 2 + titleTop
    };
  });
  const packed = packClusters(
    blocks.map((b) => ({
      positions: b.block.positions,
      width: b.outerW,
      height: b.outerH,
      size: b.group.devices.length
    })),
    GROUP_GAP
  );
  const sceneElements = [];
  packed.placements.forEach(({ offsetX, offsetY }, i) => {
    const b = blocks[i];
    const originX = PADDING + offsetX;
    const originY = PADDING + offsetY;
    if (b.hasZone) {
      sceneElements.push({
        instanceId: `topology-workarea-${b.group.workareaId}`,
        canvasId: import_topologyFloorPlanConstants.TOPOLOGY_MAIN_CANVAS_ID,
        x: Math.round(originX),
        y: Math.round(originY),
        width: Math.round(b.outerW),
        height: Math.round(b.outerH),
        elementKind: import_materials.FLOOR_MAP_SELECTION_ZONE_ELEMENT_KIND,
        name: b.group.name,
        /** 选区置于设备下方，避免遮挡 / 抢占点击 */
        zIndex: -50
      });
    }
    const deviceOriginX = originX + b.innerPad;
    const deviceOriginY = originY + b.innerPad + b.titleTop;
    for (const device of b.group.devices) {
      const pos = b.block.positions.get(String(device.id)) ?? { x: 0, y: 0 };
      sceneElements.push(
        buildDeviceSceneElement(
          device,
          deviceOriginX + pos.x,
          deviceOriginY + pos.y,
          typeCodeToKind
        )
      );
    }
  });
  return { sceneElements };
}
function sceneInstanceIdFromDeviceId(deviceId) {
  return `topology-device-${deviceId}`;
}
var SCENE_INSTANCE_ID_PREFIX = "topology-device-";
function deviceIdFromSceneInstanceId(instanceId) {
  if (!instanceId.startsWith(SCENE_INSTANCE_ID_PREFIX)) return null;
  const rest = instanceId.slice(SCENE_INSTANCE_ID_PREFIX.length);
  return rest.length > 0 ? rest : null;
}
function resolveDeviceKind(device, typeCodeToKind) {
  const code = (device.type_code ?? "").trim();
  return (code && typeCodeToKind.get(code)) ?? `${import_topologyFloorPlanConstants.TOPOLOGY_DEVICE_KIND_PREFIX}unknown`;
}
var CONNECTION_TYPE_STYLE = {
  ethernet: {},
  lan: {},
  wired: {},
  usb: { color: "#8b5cf6" },
  bluetooth: { color: "#3b82f6", dashed: true },
  bt: { color: "#3b82f6", dashed: true },
  wifi: { color: "#06b6d4", dashed: true },
  "wi-fi": { color: "#06b6d4", dashed: true },
  wireless: { color: "#06b6d4", dashed: true }
};
function getConnectionTypeStyle(connectionType) {
  if (!connectionType) return {};
  const key = connectionType.trim().toLowerCase();
  return CONNECTION_TYPE_STYLE[key] ?? {};
}
function connectionStatusToEdgeStatus(status) {
  switch (status) {
    case "connected":
    case "online":
      return "online";
    case "disconnected":
    case "offline":
      return "offline";
    case "warning":
      return "warning";
    default:
      return "unknown";
  }
}
function buildTopologyEdgesFromConnections(rawConnections, rawDevices) {
  const deviceById = new Map(
    rawDevices.map((d) => [String(d.id), d])
  );
  const layerOrder = (id) => {
    const device = deviceById.get(id);
    if (!device) return 0;
    return DEVICE_LAYER_ORDER.indexOf(classifyDeviceLayer(device));
  };
  return rawConnections.filter((c) => {
    const sId = String(c.source_device_id);
    const tId = String(c.target_device_id);
    return deviceById.has(sId) && deviceById.has(tId) && sId !== tId;
  }).map((c) => {
    var _a, _b;
    const sId = String(c.source_device_id);
    const tId = String(c.target_device_id);
    const sLayer = layerOrder(sId);
    const tLayer = layerOrder(tId);
    let sourceAnchor;
    let targetAnchor;
    if (sLayer < tLayer) {
      sourceAnchor = "bottom";
      targetAnchor = "top";
    } else if (sLayer > tLayer) {
      sourceAnchor = "top";
      targetAnchor = "bottom";
    } else {
      sourceAnchor = "bottom";
      targetAnchor = "top";
    }
    const typeStyle = getConnectionTypeStyle((_a = c.config) == null ? void 0 : _a.connection_type);
    return {
      id: `topology-connection-${c.id}`,
      sourceId: sceneInstanceIdFromDeviceId(sId),
      targetId: sceneInstanceIdFromDeviceId(tId),
      sourceAnchor,
      targetAnchor,
      status: connectionStatusToEdgeStatus(c.status),
      ...typeStyle.color ? { color: typeStyle.color } : {},
      ...typeStyle.dashed ? { dashed: true } : {},
      extensions: {
        connectionType: ((_b = c.config) == null ? void 0 : _b.connection_type) ?? null
      }
    };
  });
}
function topologyMainCanvasConfig(displayLocale = "en") {
  return [
    {
      id: import_topologyFloorPlanConstants.TOPOLOGY_MAIN_CANVAS_ID,
      name: (0, import_topologyLocale.getTopologyCanvasDevicesName)(displayLocale),
      order: 0,
      enabled: true,
      mapLayer: { showGrid: false, backgroundColor: "#ffffff" }
    }
  ];
}
function buildTopologyFloorMapConfigFromDevices(rawDevices, rawConnections = [], displayLocale = "en") {
  const { categories, kinds, typeCodeToKind } = buildTopologyDeviceElementKinds(displayLocale);
  const { sceneElements } = buildTopologyWorkareaGroupedSceneElements(
    rawDevices,
    rawConnections,
    typeCodeToKind
  );
  const edges = buildTopologyEdgesFromConnections(rawConnections, rawDevices);
  const config = {
    canvases: topologyMainCanvasConfig(displayLocale),
    canvasUi: { canCreate: false, canEdit: false },
    elementKindCategories: categories,
    elementKinds: kinds,
    sceneElements,
    edges
  };
  return {
    config,
    dataSources: buildTopologyDeviceDataSources(rawDevices)
  };
}
function layoutNewcomerSceneElements(added, rawConnections, keptScene, ghostScene, typeCodeToKind) {
  if (added.length === 0) return [];
  let baseY = PADDING;
  const allExisting = [...keptScene, ...ghostScene];
  for (const el of allExisting) {
    const bottom = (el.y ?? 0) + (el.height ?? NODE_HEIGHT);
    if (bottom > baseY) baseY = bottom;
  }
  if (allExisting.length > 0) baseY += CLUSTER_GAP * 2;
  const { sceneElements } = buildTopologyConnectionAwareSceneElements(
    added,
    rawConnections,
    typeCodeToKind
  );
  const dy = baseY - PADDING;
  return dy === 0 ? sceneElements : sceneElements.map((el) => ({ ...el, y: (el.y ?? 0) + dy }));
}
function reconcileTopologyView(params) {
  var _a;
  const { rawDevices, rawConnections, savedSceneElements, savedEdges } = params;
  const displayLocale = params.displayLocale ?? "en";
  const { categories, kinds, typeCodeToKind } = buildTopologyDeviceElementKinds(displayLocale);
  const dataSources = buildTopologyDeviceDataSources(rawDevices);
  if (!savedSceneElements || savedSceneElements.length === 0) {
    const { sceneElements: sceneElements2 } = buildTopologyWorkareaGroupedSceneElements(
      rawDevices,
      rawConnections,
      typeCodeToKind
    );
    const edges2 = buildTopologyEdgesFromConnections(rawConnections, rawDevices);
    return {
      config: {
        canvases: topologyMainCanvasConfig(displayLocale),
        canvasUi: { canCreate: false, canEdit: false },
        elementKindCategories: categories,
        elementKinds: kinds,
        sceneElements: sceneElements2,
        edges: edges2
      },
      dataSources,
      addedDeviceIds: rawDevices.map((d) => String(d.id)),
      ghostInstanceIds: [],
      ghostDeviceIds: [],
      keptDeviceIds: []
    };
  }
  const boundById = /* @__PURE__ */ new Map();
  const freeScene = [];
  for (const el of savedSceneElements) {
    const fromBinding = (_a = el.dataBinding) == null ? void 0 : _a.recordId;
    const id = typeof fromBinding === "string" && fromBinding.trim() ? fromBinding : deviceIdFromSceneInstanceId(el.instanceId);
    if (id) {
      boundById.set(id, el);
    } else {
      freeScene.push(el);
    }
  }
  const deviceById = new Map(rawDevices.map((d) => [String(d.id), d]));
  const keptScene = [];
  const newDevices = [];
  const keptDeviceIds = [];
  for (const device of rawDevices) {
    const id = String(device.id);
    const saved = boundById.get(id);
    if (saved) {
      keptScene.push({
        ...saved,
        elementKind: resolveDeviceKind(device, typeCodeToKind),
        name: deviceDisplayName(device),
        dataBinding: {
          dataSourceKey: import_topologyFloorPlanConstants.TOPOLOGY_DEVICES_DATA_SOURCE_KEY,
          recordId: id
        }
      });
      keptDeviceIds.push(id);
    } else {
      newDevices.push(device);
    }
  }
  const ghostScene = [];
  const ghostInstanceIds = [];
  const ghostDeviceIds = [];
  for (const [id, saved] of boundById) {
    if (deviceById.has(id)) continue;
    ghostScene.push(saved);
    ghostInstanceIds.push(saved.instanceId);
    ghostDeviceIds.push(id);
  }
  const newScene = layoutNewcomerSceneElements(
    newDevices,
    rawConnections,
    [...keptScene, ...freeScene],
    ghostScene,
    typeCodeToKind
  );
  const sceneElements = [
    ...freeScene,
    ...keptScene,
    ...newScene,
    ...ghostScene
  ];
  const savedEdgeById = new Map(
    (savedEdges ?? []).map((e) => [e.id, e])
  );
  const rebuilt = buildTopologyEdgesFromConnections(rawConnections, rawDevices);
  const edges = rebuilt.map((e) => {
    const saved = savedEdgeById.get(e.id);
    return (saved == null ? void 0 : saved.routing) ? { ...e, routing: saved.routing } : e;
  });
  const config = {
    canvases: topologyMainCanvasConfig(displayLocale),
    canvasUi: { canCreate: false, canEdit: false },
    elementKindCategories: categories,
    elementKinds: kinds,
    sceneElements,
    edges
  };
  return {
    config,
    dataSources,
    addedDeviceIds: newDevices.map((d) => String(d.id)),
    ghostInstanceIds,
    ghostDeviceIds,
    keptDeviceIds
  };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  TOPOLOGY_DEVICE_KIND_PREFIX,
  TOPOLOGY_DEVICE_KIND_VALUES,
  TOPOLOGY_DEVICE_TYPE_CODES,
  buildTopologyConnectionAwareSceneElements,
  buildTopologyDeviceDataSources,
  buildTopologyDeviceElementKinds,
  buildTopologyEdgesFromConnections,
  buildTopologyFloorMapConfigFromDevices,
  buildTopologyWorkareaGroupedSceneElements,
  collectConnectedComponentDeviceIds,
  deviceIpAddress,
  extractRawDeviceConnectionList,
  extractRawDeviceList,
  getConnectionTypeStyle,
  reconcileTopologyView
});
