"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.MapContainer = void 0;
var _react = require("@xyflow/react");
var _react2 = _interopRequireWildcard(require("react"));
var _celestial_state_context = require("../shared/contexts/celestial_state_context");
var _breadcrumb_trail = require("./breadcrumb_trail");
var _celestial_controls = require("./celestial_controls");
var _layout_controls = require("./layout_controls");
var _celestial_node = require("./celestial_node");
var _celestial_edge = require("./edges/celestial_edge");
var _glass_background = require("./glass_background");
var _legend = require("./legend");
var _loader = require("./loader/loader");
var _t = require("../shared/i18n/t");
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/*
 * Copyright OpenSearch Contributors
 * SPDX-License-Identifier: Apache-2.0
 */

const defaultNodeTypes = {
  celestialNode: _celestial_node.CelestialNode
};
const defaultEdgeTypes = {
  celestialEdge: _celestial_edge.CelestialEdge
};

/**
 * Resolves `data.style.marker` into a top-level `markerEnd` so ReactFlow
 * creates SVG `<defs>` and passes the resolved URL string to edge components.
 */
function resolveEdgeMarkers(edges) {
  return edges.map(edge => {
    var _edge$data, _style$color;
    if (edge.markerEnd) return edge; // already set by consumer
    const style = (_edge$data = edge.data) === null || _edge$data === void 0 ? void 0 : _edge$data.style;
    if ((style === null || style === void 0 ? void 0 : style.marker) === 'none') return edge; // explicitly no marker
    // Must be a concrete color value (not CSS var) since ReactFlow
    // sets it as an SVG attribute on the marker <polyline>.
    const markerColor = (_style$color = style === null || style === void 0 ? void 0 : style.color) !== null && _style$color !== void 0 ? _style$color : '#b1b1b7';
    return {
      ...edge,
      markerEnd: {
        type: (style === null || style === void 0 ? void 0 : style.marker) === 'arrow' ? _react.MarkerType.Arrow : _react.MarkerType.ArrowClosed,
        color: markerColor,
        width: 20,
        height: 20
      }
    };
  });
}
const MapContainer = ({
  nodes,
  edges,
  isLoading,
  onNodesChange,
  onEdgesChange,
  breadcrumbs,
  onBreadcrumbClick,
  onEdgeClick,
  emptyState,
  hotspot,
  numMatches,
  nodeTypes: consumerNodeTypes,
  edgeTypes: consumerEdgeTypes,
  legend,
  showMinimap,
  showSliSlo,
  isDarkMode,
  showLayoutControls,
  nodesDraggable,
  rootBreadcrumbIcon,
  onNodeClickZoom,
  onEdgeClickZoom
}) => {
  const {
    viewLock
  } = (0, _celestial_state_context.useCelestialStateContext)();
  const reactFlowInstance = (0, _react.useReactFlow)();
  const mergedNodeTypes = (0, _react2.useMemo)(() => ({
    ...defaultNodeTypes,
    ...consumerNodeTypes
  }), [consumerNodeTypes]);
  const mergedEdgeTypes = (0, _react2.useMemo)(() => ({
    ...defaultEdgeTypes,
    ...consumerEdgeTypes
  }), [consumerEdgeTypes]);
  const resolvedEdges = (0, _react2.useMemo)(() => resolveEdgeMarkers(edges), [edges]);
  const renderLegend = () => {
    if (legend === false) return null;
    if (legend !== undefined) {
      return /*#__PURE__*/(0, _jsxRuntime.jsx)(_legend.Legend, {
        children: legend
      });
    }
    return /*#__PURE__*/(0, _jsxRuntime.jsx)(_legend.Legend, {
      showSliSlo: showSliSlo
    });
  };

  /** Focus camera on a clicked node (configurable via onNodeClickZoom) */
  const handleNodeClick = (0, _react2.useCallback)((_event, node) => {
    if (!onNodeClickZoom || onNodeClickZoom === 'none') return;
    viewLock.lock();
    const padding = 50;
    if (onNodeClickZoom === 'zoomToNode') {
      var _ref, _node$measured$width, _node$measured, _ref2, _node$measured$height, _node$measured2;
      const width = (_ref = (_node$measured$width = (_node$measured = node.measured) === null || _node$measured === void 0 ? void 0 : _node$measured.width) !== null && _node$measured$width !== void 0 ? _node$measured$width : node.width) !== null && _ref !== void 0 ? _ref : 272;
      const height = (_ref2 = (_node$measured$height = (_node$measured2 = node.measured) === null || _node$measured2 === void 0 ? void 0 : _node$measured2.height) !== null && _node$measured$height !== void 0 ? _node$measured$height : node.height) !== null && _ref2 !== void 0 ? _ref2 : 156;
      reactFlowInstance.fitBounds({
        x: node.position.x - padding,
        y: node.position.y - padding,
        width: width + 2 * padding,
        height: height + 2 * padding
      }, {
        padding: 0.3,
        duration: 400
      });
    } else if (onNodeClickZoom === 'zoomToNeighborhood') {
      const connectedEdges = resolvedEdges.filter(e => e.source === node.id || e.target === node.id);
      const neighborIds = new Set();
      connectedEdges.forEach(e => {
        neighborIds.add(e.source);
        neighborIds.add(e.target);
      });
      const neighborNodes = nodes.filter(n => neighborIds.has(n.id) || n.id === node.id);
      let minX = Infinity;
      let minY = Infinity;
      let maxX = -Infinity;
      let maxY = -Infinity;
      for (const n of neighborNodes) {
        var _ref3, _n$measured$width, _n$measured, _ref4, _n$measured$height, _n$measured2;
        const w = (_ref3 = (_n$measured$width = (_n$measured = n.measured) === null || _n$measured === void 0 ? void 0 : _n$measured.width) !== null && _n$measured$width !== void 0 ? _n$measured$width : n.width) !== null && _ref3 !== void 0 ? _ref3 : 272;
        const h = (_ref4 = (_n$measured$height = (_n$measured2 = n.measured) === null || _n$measured2 === void 0 ? void 0 : _n$measured2.height) !== null && _n$measured$height !== void 0 ? _n$measured$height : n.height) !== null && _ref4 !== void 0 ? _ref4 : 156;
        minX = Math.min(minX, n.position.x);
        minY = Math.min(minY, n.position.y);
        maxX = Math.max(maxX, n.position.x + w);
        maxY = Math.max(maxY, n.position.y + h);
      }
      reactFlowInstance.fitBounds({
        x: minX - padding,
        y: minY - padding,
        width: maxX - minX + 2 * padding,
        height: maxY - minY + 2 * padding
      }, {
        padding: 0.1,
        duration: 400
      });
    }
  }, [reactFlowInstance, viewLock, onNodeClickZoom, nodes, resolvedEdges]);

  /** Focus camera on the midpoint between an edge's source and target nodes */
  const handleEdgeClickWithFocus = (0, _react2.useCallback)((event, edge) => {
    onEdgeClick(event, edge);
    if (!onEdgeClickZoom || onEdgeClickZoom === 'none') return;
    viewLock.lock();
    const sourceNode = reactFlowInstance.getNode(edge.source);
    const targetNode = reactFlowInstance.getNode(edge.target);
    if (sourceNode && targetNode) {
      var _ref5, _sourceNode$measured$, _sourceNode$measured, _ref6, _sourceNode$measured$2, _sourceNode$measured2, _ref7, _targetNode$measured$, _targetNode$measured, _ref8, _targetNode$measured$2, _targetNode$measured2;
      const sWidth = (_ref5 = (_sourceNode$measured$ = (_sourceNode$measured = sourceNode.measured) === null || _sourceNode$measured === void 0 ? void 0 : _sourceNode$measured.width) !== null && _sourceNode$measured$ !== void 0 ? _sourceNode$measured$ : sourceNode.width) !== null && _ref5 !== void 0 ? _ref5 : 272;
      const sHeight = (_ref6 = (_sourceNode$measured$2 = (_sourceNode$measured2 = sourceNode.measured) === null || _sourceNode$measured2 === void 0 ? void 0 : _sourceNode$measured2.height) !== null && _sourceNode$measured$2 !== void 0 ? _sourceNode$measured$2 : sourceNode.height) !== null && _ref6 !== void 0 ? _ref6 : 156;
      const tWidth = (_ref7 = (_targetNode$measured$ = (_targetNode$measured = targetNode.measured) === null || _targetNode$measured === void 0 ? void 0 : _targetNode$measured.width) !== null && _targetNode$measured$ !== void 0 ? _targetNode$measured$ : targetNode.width) !== null && _ref7 !== void 0 ? _ref7 : 272;
      const tHeight = (_ref8 = (_targetNode$measured$2 = (_targetNode$measured2 = targetNode.measured) === null || _targetNode$measured2 === void 0 ? void 0 : _targetNode$measured2.height) !== null && _targetNode$measured$2 !== void 0 ? _targetNode$measured$2 : targetNode.height) !== null && _ref8 !== void 0 ? _ref8 : 156;
      const minX = Math.min(sourceNode.position.x, targetNode.position.x);
      const minY = Math.min(sourceNode.position.y, targetNode.position.y);
      const maxX = Math.max(sourceNode.position.x + sWidth, targetNode.position.x + tWidth);
      const maxY = Math.max(sourceNode.position.y + sHeight, targetNode.position.y + tHeight);
      const padding = 50;
      reactFlowInstance.fitBounds({
        x: minX - padding,
        y: minY - padding,
        width: maxX - minX + 2 * padding,
        height: maxY - minY + 2 * padding
      }, {
        padding: 0.1,
        duration: 400
      });
    }
  }, [reactFlowInstance, onEdgeClick, viewLock, onEdgeClickZoom]);
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
    className: `osd:flex osd:flex-col osd:h-full osd:overflow-hidden osd:rounded-2xl osd:relative`,
    children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
      className: "osd:absolute osd:top-2 osd:left-0 osd:flex osd:z-1000",
      children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_breadcrumb_trail.BreadcrumbTrail, {
        breadcrumbs: breadcrumbs,
        onBreadcrumbClick: onBreadcrumbClick,
        hotspot: hotspot,
        rootIcon: rootBreadcrumbIcon
      })
    }), numMatches !== undefined && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
      className: "osd:absolute osd:top-[14px] osd:right-4 osd:flex osd:z-1000",
      children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
        className: "osd:inline-flex osd:items-center osd:px-3 osd:py-1.5 osd:rounded-lg osd:text-sm osd:bg-blue-50 osd:text-black osd:border-2 osd:border-blue-500",
        children: [numMatches, " ", numMatches === 1 ? (0, _t.t)('matchForFilter') : (0, _t.t)('matchesForFilter')]
      })
    }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
      className: "osd:relative osd:flex-grow",
      children: [isLoading && /*#__PURE__*/(0, _jsxRuntime.jsx)(_glass_background.GlassBackground, {
        children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_loader.Loader, {})
      }), !isLoading && (nodes === null || nodes === void 0 ? void 0 : nodes.length) === 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
        className: "osd:bg-container-default osd:absolute osd:inset-0 osd:flex osd:items-center osd:justify-center osd:z-10",
        children: emptyState
      }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
        className: "osd:absolute osd:top-15 osd:right-4 osd:flex osd:flex-col osd:items-center osd:gap-4 osd:z-50",
        children: [renderLegend(), /*#__PURE__*/(0, _jsxRuntime.jsx)(_celestial_controls.CelestialControls, {}), showLayoutControls && /*#__PURE__*/(0, _jsxRuntime.jsx)(_layout_controls.LayoutControls, {})]
      }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_react.ReactFlow, {
        nodes: nodes,
        edges: resolvedEdges,
        onNodesChange: onNodesChange,
        onEdgesChange: onEdgesChange,
        onNodeClick: handleNodeClick,
        onEdgeClick: handleEdgeClickWithFocus,
        minZoom: 0,
        nodeTypes: mergedNodeTypes,
        edgeTypes: mergedEdgeTypes,
        nodesDraggable: nodesDraggable !== null && nodesDraggable !== void 0 ? nodesDraggable : false,
        proOptions: {
          hideAttribution: true
        },
        className: "osd:w-full osd:h-full osd:z-1",
        children: showMinimap && /*#__PURE__*/(0, _jsxRuntime.jsx)(_react.MiniMap, {
          nodeStrokeWidth: 3,
          nodeStrokeColor: isDarkMode ? '#424650' : '#B4B4BB',
          nodeColor: node => {
            var _node$data$health$sta, _node$data, _node$data2;
            const status = (_node$data$health$sta = (_node$data = node.data) === null || _node$data === void 0 || (_node$data = _node$data.health) === null || _node$data === void 0 ? void 0 : _node$data.status) !== null && _node$data$health$sta !== void 0 ? _node$data$health$sta : (_node$data2 = node.data) === null || _node$data2 === void 0 ? void 0 : _node$data2.status;
            if (status === 'breached' || status === 'critical' || status === 'error') return '#D13313';
            if (status === 'recovered' || status === 'warning') return '#FF9900';
            return isDarkMode ? '#424650' : '#B4B4BB';
          },
          bgColor: isDarkMode ? '#151D26' : '#FFFFFF',
          maskColor: isDarkMode ? 'rgba(35, 43, 55, 0.6)' : 'rgba(235, 235, 240, 0.6)',
          pannable: true,
          zoomable: true,
          style: {
            borderRadius: 8
          }
        })
      })]
    })]
  });
};
exports.MapContainer = MapContainer;