var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/plus/pisellTopology/PisellTopology.tsx
var PisellTopology_exports = {};
__export(PisellTopology_exports, {
  PisellTopology: () => PisellTopology,
  PisellTopologyCore: () => PisellTopologyCore
});
module.exports = __toCommonJS(PisellTopology_exports);
var import_react = __toESM(require("react"));
var import_classnames = __toESM(require("classnames"));
var import_materials = require("@pisell/materials");
var import_useEngineContext = __toESM(require("../../hooks/useEngineContext"));
var import_locales = __toESM(require("./locales"));
var import_topologyLocale = require("./topologyLocale");
var import_utils = require("@pisell/utils");
var import_utils2 = require("../../utils");
var import_TopologyDeviceCard = require("./TopologyDeviceCard");
var import_TopologyFloorMapEditToggle = require("./components/TopologyFloorMapEditToggle");
var import_TopologyConnectionLegend = require("./components/TopologyConnectionLegend");
var import_topologyDeviceListView = require("./topologyDeviceListView");
var import_topologyDeviceApi = require("./topologyDeviceApi");
var import_topologyFloorPlanConstants = require("./topologyFloorPlanConstants");
var import_useTopologyFloorPlan = require("./floorPlan/useTopologyFloorPlan");
var import_resolveAppHelperIsWebPos = require("./floorPlan/resolveAppHelperIsWebPos");
var import_topologyFloorPlanApi = require("./floorPlan/topologyFloorPlanApi");
var import_deviceDetail = require("../saasDevice/devicePlanning/modules/deviceDetail");
var import_hooks = require("../saasDevice/devicePlanning/hooks");
var import_locales2 = __toESM(require("../saasDevice/devicePlanning/locales"));
var import_useTopologyDeviceDetail = require("./useTopologyDeviceDetail");
var import_PisellTopology = require("./PisellTopology.less");
var PREFIX = "pisell-topology";
var PREVIEW_HTTP_CLIENT = {
  get: async () => ({ data: [] }),
  post: async () => ({ data: {} }),
  put: async () => ({ data: {} }),
  remove: async () => ({ data: {} }),
  custom: async () => ({ data: {} })
};
function buildDeviceRenderItemByKind(kindValues, devicesById) {
  const map = {};
  map[import_materials.FLOOR_MAP_SELECTION_ZONE_ELEMENT_KIND] = (item) => {
    var _a;
    return /* @__PURE__ */ import_react.default.createElement(import_materials.FloorMapSelectionZoneElement, { name: item.name ?? ((_a = item._sceneElement) == null ? void 0 : _a.name) });
  };
  for (const kind of kindValues) {
    map[kind] = (item) => {
      var _a;
      const binding = (_a = item._sceneElement) == null ? void 0 : _a.dataBinding;
      const device = (binding == null ? void 0 : binding.recordId) != null ? devicesById.get(String(binding.recordId)) : void 0;
      return /* @__PURE__ */ import_react.default.createElement(import_TopologyDeviceCard.TopologyDeviceCard, { item, device });
    };
  }
  return map;
}
function PisellTopology(props) {
  var _a;
  const {
    className,
    style,
    devices: devicesProp,
    overviewHud: overviewHudProp,
    /** 低代码 mode='edit' 时强制编辑；'read' 时由画布右上「编辑拓扑」按钮切换 */
    mode: propMode = "read",
    floorPlanCode: floorPlanCodeProp,
    floorPlanCanvasWidth,
    floorPlanCanvasHeight,
    floorPlanName,
    floorPlanSort,
    floorPlanStatus,
    putFloorPlan,
    onFloorPlanPersisted
  } = props;
  const floorPlanCode = (floorPlanCodeProp == null ? void 0 : floorPlanCodeProp.trim()) || import_topologyFloorPlanConstants.PISELL_TOPOLOGY_FLOOR_PLAN_CODE;
  const overviewHud = overviewHudProp === false ? false : overviewHudProp === true || overviewHudProp === void 0 ? void 0 : overviewHudProp;
  const engineCtx = (0, import_useEngineContext.default)();
  const displayLocale = (0, import_topologyLocale.resolveTopologyDisplayLocale)(engineCtx);
  const { request: engineRequest, isWebPos: isWebPosRaw } = ((_a = engineCtx == null ? void 0 : engineCtx.appHelper) == null ? void 0 : _a.utils) || {};
  const subscribeFloorPlanPush = (0, import_resolveAppHelperIsWebPos.resolveAppHelperIsWebPos)(isWebPosRaw);
  const translation = (0, import_hooks.useTranslation)();
  (0, import_react.useEffect)(() => {
    import_utils.locales.init((0, import_topologyLocale.normalizeTopologyLocaleMaps)(import_locales.default), displayLocale);
    import_utils.locales.init(import_locales2.default, displayLocale);
    (0, import_materials.initFloorMapLayoutLocales)(displayLocale);
  }, [displayLocale]);
  import_utils2.request.setRequest(engineRequest ?? PREVIEW_HTTP_CLIENT);
  (0, import_react.useEffect)(() => {
    if (engineRequest) {
      import_utils2.request.setRequest(engineRequest);
    }
  }, [engineRequest]);
  const [rawDevices, setRawDevices] = (0, import_react.useState)([]);
  const [rawConnections, setRawConnections] = (0, import_react.useState)([]);
  const [devicesFetchSettled, setDevicesFetchSettled] = (0, import_react.useState)(
    () => Boolean(devicesProp && devicesProp.length > 0)
  );
  (0, import_react.useEffect)(() => {
    if (devicesProp && devicesProp.length > 0) {
      setRawConnections([]);
      setDevicesFetchSettled(true);
      return;
    }
    setDevicesFetchSettled(false);
    let cancelled = false;
    Promise.all([
      (0, import_topologyDeviceApi.fetchTopologyDeviceList)(),
      (0, import_topologyDeviceApi.fetchTopologyDeviceConnectionList)()
    ]).then(([deviceRes, connectionRes]) => {
      if (cancelled) return;
      const devices = (0, import_topologyDeviceListView.extractRawDeviceList)(deviceRes.response);
      const conns = (0, import_topologyDeviceListView.extractRawDeviceConnectionList)(connectionRes.response);
      setRawDevices(devices);
      setRawConnections(conns);
    }).catch((error) => {
      if (cancelled) return;
      console.error("[PisellTopology] 拉取设备 / 连接失败:", error);
      setRawDevices([]);
      setRawConnections([]);
    }).finally(() => {
      if (!cancelled) setDevicesFetchSettled(true);
    });
    return () => {
      cancelled = true;
    };
  }, [devicesProp]);
  const propRawDevices = (0, import_react.useMemo)(() => {
    if (!devicesProp || devicesProp.length === 0) return [];
    return devicesProp.map((row, index) => ({
      id: row.id ?? `prop-${index}`,
      type_code: "unknown",
      name: row.name ?? null,
      model: row.model ? { name: { original: row.model } } : null,
      number: row.sn ?? null,
      status: row.status ?? null
    }));
  }, [devicesProp]);
  const effectiveRawDevices = propRawDevices.length > 0 ? propRawDevices : rawDevices;
  const deviceDetail = (0, import_useTopologyDeviceDetail.useTopologyDeviceDetail)({
    rawDevices: effectiveRawDevices,
    translation
  });
  const [mapEditInternal, setMapEditInternal] = (0, import_react.useState)(false);
  const effectiveMode = propMode === "edit" || mapEditInternal ? "edit" : "read";
  const forceEditFromProps = propMode === "edit";
  const enableFloorPlanSync = !devicesProp || devicesProp.length === 0;
  const {
    floorPlanRemoteId,
    savedSceneElements,
    savedEdges,
    isLoaded: floorPlanLoaded,
    applyLocalSave,
    setRemoteFloorPlanView
  } = (0, import_useTopologyFloorPlan.useTopologyFloorPlan)({
    floorPlanCode,
    enabled: enableFloorPlanSync,
    subscribeFloorPlanPush
  });
  const isViewReady = devicesFetchSettled && (!enableFloorPlanSync || floorPlanLoaded);
  const reconciled = (0, import_react.useMemo)(() => {
    if (!isViewReady) return null;
    return (0, import_topologyDeviceListView.reconcileTopologyView)({
      rawDevices: effectiveRawDevices,
      rawConnections,
      savedSceneElements: enableFloorPlanSync ? savedSceneElements : void 0,
      savedEdges: enableFloorPlanSync ? savedEdges : void 0,
      displayLocale
    });
  }, [
    isViewReady,
    effectiveRawDevices,
    rawConnections,
    enableFloorPlanSync,
    savedSceneElements,
    savedEdges,
    displayLocale
  ]);
  const baseFloorConfig = (0, import_react.useMemo)(() => {
    const canEditCanvas = effectiveMode === "edit";
    const core = reconciled == null ? void 0 : reconciled.config;
    if (!core) {
      return {
        canvases: [
          {
            id: import_topologyFloorPlanConstants.TOPOLOGY_MAIN_CANVAS_ID,
            name: (0, import_topologyLocale.getTopologyCanvasDevicesName)(displayLocale),
            order: 0,
            enabled: true,
            mapLayer: { showGrid: false, backgroundColor: "#ffffff" }
          }
        ],
        canvasUi: { canCreate: canEditCanvas, canEdit: canEditCanvas },
        elementKinds: [],
        sceneElements: [],
        edges: []
      };
    }
    return {
      ...core,
      canvasUi: { canCreate: canEditCanvas, canEdit: canEditCanvas }
    };
  }, [reconciled, effectiveMode, displayLocale]);
  const dataSources = (reconciled == null ? void 0 : reconciled.dataSources) ?? { devices: [] };
  const inflightSaveRef = (0, import_react.useRef)(null);
  (0, import_react.useEffect)(() => {
    var _a2;
    if (!enableFloorPlanSync) return;
    if (!isViewReady || !reconciled) return;
    if (!floorPlanLoaded) return;
    if (floorPlanRemoteId == null) return;
    if (effectiveRawDevices.length === 0) return;
    if ((((_a2 = reconciled.config.sceneElements) == null ? void 0 : _a2.length) ?? 0) === 0) return;
    if (reconciled.addedDeviceIds.length === 0) return;
    if (effectiveMode === "edit") return;
    const token = Symbol("topology-autosave");
    inflightSaveRef.current = token;
    const sceneSnapshot = reconciled.config.sceneElements ?? [];
    const edgeSnapshot = reconciled.config.edges ?? [];
    (0, import_topologyFloorPlanApi.saveViewConfigToShopFloorPlan)(floorPlanRemoteId, reconciled.config, {
      canvasWidth: floorPlanCanvasWidth,
      canvasHeight: floorPlanCanvasHeight,
      code: floorPlanCode,
      name: floorPlanName,
      sort: floorPlanSort,
      status: floorPlanStatus,
      putFloorPlan: putFloorPlan != null ? (planId, body) => putFloorPlan(planId, body) : void 0
    }).then(() => {
      if (inflightSaveRef.current !== token) return;
      applyLocalSave({
        sceneElements: sceneSnapshot,
        edges: edgeSnapshot
      });
      onFloorPlanPersisted == null ? void 0 : onFloorPlanPersisted();
    }).catch((err) => {
      console.warn("[PisellTopology] auto-save floor-plan failed:", err);
    });
  }, [
    enableFloorPlanSync,
    isViewReady,
    floorPlanLoaded,
    floorPlanRemoteId,
    reconciled,
    effectiveRawDevices.length,
    effectiveMode,
    floorPlanCode,
    floorPlanCanvasWidth,
    floorPlanCanvasHeight,
    floorPlanName,
    floorPlanSort,
    floorPlanStatus,
    putFloorPlan,
    onFloorPlanPersisted,
    applyLocalSave
  ]);
  const devicesById = (0, import_react.useMemo)(() => {
    const list = dataSources[import_topologyFloorPlanConstants.TOPOLOGY_DEVICES_DATA_SOURCE_KEY] ?? [];
    return new Map(list.map((d) => [d.id, d]));
  }, [dataSources]);
  const renderItemByKind = (0, import_react.useMemo)(
    () => buildDeviceRenderItemByKind(import_topologyDeviceListView.TOPOLOGY_DEVICE_KIND_VALUES, devicesById),
    [devicesById]
  );
  const floorMapLayoutRef = (0, import_react.useRef)(null);
  const onSaveWithApi = (0, import_react.useMemo)(() => {
    const persistTargetId = floorPlanRemoteId;
    const canPersist = enableFloorPlanSync && persistTargetId != null && Number.isFinite(persistTargetId) && persistTargetId > 0;
    return (0, import_materials.wrapFloorMapOnSaveWithRemotePersist)({
      canPersist,
      persistTargetId: persistTargetId ?? 0,
      persist: (id, config) => (0, import_topologyFloorPlanApi.saveViewConfigToShopFloorPlan)(id, config, {
        canvasWidth: floorPlanCanvasWidth,
        canvasHeight: floorPlanCanvasHeight,
        code: floorPlanCode,
        name: floorPlanName,
        sort: floorPlanSort,
        status: floorPlanStatus,
        putFloorPlan: putFloorPlan != null ? (planId, body) => putFloorPlan(planId, body) : void 0
      }),
      setRemoteFloorPlanView,
      onFloorPlanPersisted,
      prevOnSave: props.onSave,
      onPersistError: import_topologyFloorPlanApi.toastFloorPlanSaveError
    });
  }, [
    enableFloorPlanSync,
    floorPlanRemoteId,
    floorPlanCanvasWidth,
    floorPlanCanvasHeight,
    floorPlanCode,
    floorPlanName,
    floorPlanSort,
    floorPlanStatus,
    putFloorPlan,
    setRemoteFloorPlanView,
    onFloorPlanPersisted,
    props.onSave
  ]);
  const handleAutoArrange = (0, import_react.useCallback)(() => {
    var _a2, _b;
    if (effectiveRawDevices.length === 0) return;
    const { config } = (0, import_topologyDeviceListView.reconcileTopologyView)({
      rawDevices: effectiveRawDevices,
      rawConnections,
      displayLocale
    });
    const next = {
      ...baseFloorConfig,
      ...config,
      canvasUi: baseFloorConfig.canvasUi
    };
    (_b = (_a2 = floorMapLayoutRef.current) == null ? void 0 : _a2.applySceneSnapshot) == null ? void 0 : _b.call(_a2, next);
  }, [effectiveRawDevices, rawConnections, baseFloorConfig, displayLocale]);
  return /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-root` }, /* @__PURE__ */ import_react.default.createElement("div", { className: `${PREFIX}-legend-anchor` }, /* @__PURE__ */ import_react.default.createElement(import_TopologyConnectionLegend.TopologyConnectionLegend, null)), /* @__PURE__ */ import_react.default.createElement(
    import_materials.PisellFloorMapLayout,
    {
      ref: floorMapLayoutRef,
      className: (0, import_classnames.default)(PREFIX, className),
      style: {
        width: "100%",
        height: "100%",
        minHeight: 0,
        flex: 1,
        ...style
      },
      items: [],
      renderItem: () => null,
      floorMapConfig: baseFloorConfig,
      dataSources,
      loading: !isViewReady,
      mode: effectiveMode,
      itemUnit: "pixel",
      enableEdges: true,
      enableHover: false,
      onItemClick: (item) => {
        if (effectiveMode !== "read") return;
        deviceDetail.openByItem(item);
      },
      toolbarShowSave: effectiveMode === "edit",
      onSave: onSaveWithApi,
      renderItemByKind,
      floorMapViewportOverlay: overviewHud,
      viewportOverlayPlacement: "top-start",
      controls: {
        showZoom: true,
        showFitBounds: true,
        showReset: true,
        showGridToggle: false,
        horizontalAlign: "end"
      },
      onExitEdit: forceEditFromProps ? void 0 : () => setMapEditInternal(false),
      viewportDockTrailing: /* @__PURE__ */ import_react.default.createElement(
        import_TopologyFloorMapEditToggle.TopologyFloorMapEditToggle,
        {
          mapEditInternal,
          setMapEditInternal,
          floorMapLayoutRef,
          forceEditMode: forceEditFromProps,
          onAutoArrange: enableFloorPlanSync ? handleAutoArrange : void 0
        }
      ),
      pan: { enabled: true },
      zoom: { autoFitOnMount: true, min: 0.25, max: 2 }
    }
  ), deviceDetail.record ? /* @__PURE__ */ import_react.default.createElement(
    import_deviceDetail.DeviceDetailDrawer,
    {
      key: deviceDetail.record.id,
      open: deviceDetail.open,
      record: deviceDetail.record,
      readonly: true,
      getText: import_utils.locales.getText,
      translation,
      onClose: deviceDetail.close
    }
  ) : null);
}
var PisellTopologyCore = PisellTopology;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  PisellTopology,
  PisellTopologyCore
});
