function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
/*
 * Copyright OpenSearch Contributors
 * SPDX-License-Identifier: Apache-2.0
 */

import { useCallback } from 'react';
import { useReactFlow } from '@xyflow/react';
import { useNodeRelationships } from '../hooks/use_node_relationships.hook';
export const useCollapseSiblings = () => {
  const _useReactFlow = useReactFlow(),
    getNodes = _useReactFlow.getNodes,
    getEdges = _useReactFlow.getEdges;
  const _useNodeRelationships = useNodeRelationships(),
    getAggregateSiblings = _useNodeRelationships.getAggregateSiblings,
    getParentNodes = _useNodeRelationships.getParentNodes,
    getChildrenNodes = _useNodeRelationships.getChildrenNodes;
  const applyCollapseSiblings = useCallback(nodeId => {
    const siblings = getAggregateSiblings(nodeId);
    const siblingIds = siblings.map(sibling => sibling.id);

    // Update current nodes in the graph
    const updatedNodes = getNodes().map(node => {
      // hide all siblings of same type
      if (siblingIds.includes(node.id)) {
        return _objectSpread(_objectSpread({}, node), {}, {
          hidden: true,
          data: _objectSpread(_objectSpread({}, node.data), {}, {
            isStacked: true
          })
        });
      }

      // if node is clicked node mark it as stacked
      if (node.id === nodeId) {
        return _objectSpread(_objectSpread({}, node), {}, {
          data: _objectSpread(_objectSpread({}, node.data), {}, {
            isStacked: true,
            isTopOfTheStack: true
          })
        });
      }
      return node;
    });
    const parents = getParentNodes(nodeId);
    const parentIds = parents.map(parent => parent.id);
    const children = getChildrenNodes(nodeId);
    const childrenIds = children.map(child => child.id);
    const updatedEdges = getEdges().map(edge => {
      // hide all edges coming from the same parent, we will only show the one between parent and nodeId
      if (parentIds.includes(edge.source) && siblingIds.includes(edge.target)) {
        return _objectSpread(_objectSpread({}, edge), {}, {
          hidden: true
        });
      }

      // if siblings have edges coming from other parents, we will want to rewire edge
      // clicked node id (clicked node is visible node in the aggregated stack)
      if (!parentIds.includes(edge.source) && siblingIds.includes(edge.target)) {
        return _objectSpread(_objectSpread({}, edge), {}, {
          target: nodeId,
          hidden: false,
          data: {
            original: _objectSpread({}, edge)
          }
        });
      }

      // hide all edges connecting siblings that with clicked node children, because those are collapsed
      // and exist as edges coming from clicked node, that will be visible node in the stack
      if (siblingIds.includes(edge.source) && childrenIds.includes(edge.target)) {
        return _objectSpread(_objectSpread({}, edge), {}, {
          hidden: true
        });
      }

      // if siblings connect to other children than those of the clicked node,
      // we will rewire outgoing edge such that clicked node is the source
      if (siblingIds.includes(edge.source) && !childrenIds.includes(edge.target)) {
        return _objectSpread(_objectSpread({}, edge), {}, {
          source: nodeId,
          hidden: false,
          data: {
            original: _objectSpread({}, edge)
          }
        });
      }
      return edge;
    });
    return {
      nodes: updatedNodes,
      edges: updatedEdges
    };
  }, [getAggregateSiblings, getParentNodes, getChildrenNodes, getNodes, getEdges]);
  return applyCollapseSiblings;
};