import useI18n from '@/hooks/useI18n';
import {
  Graph,
  GraphData,
  ICanvas,
  IShapeBase,
  Item,
  Menu,
  Tooltip,
} from '@antv/g6';
import { onBeforeUnmount, ref } from 'vue';
import {
  edgeCubicAnimateCircleMove,
  edgeCubicAnimateLineDash,
  edgeLineAnimateState,
} from './registerEdge';
import {
  nodeCircleAnimateShapeR,
  nodeCircleAnimateShapeStroke,
  nodeImageAnimateState,
  nodeRectAnimateState,
} from './registerNode';

/**图实例对象 */
export const graphG6 = ref<any>(null);

/**图事件变更 */
export const graphEvent = ref<{
  type: string;
  target: HTMLElement | (IShapeBase & ICanvas);
  item: Item | null;
} | null>(null);

/**图元素选择开始结束点 */
export const selectSourceTargetOptions = ref<Record<string, any>[]>([]);

/**图元素选择嵌入分组 */
export const selectComboOptions = ref<Record<string, any>[]>([]);

export default function useGraph() {
  //实例化i18n
  const { t } = useI18n();

  /**图模式选择项 */
  const graphMode = ref<'default' | 'edit'>('default');

  /**图模式选择项 */
  const graphModeOptions = [
    {
      value: 'default',
      label: t('views.monitor.topologyBuild.graphModeDefault'),
    },
    {
      value: 'edit',
      label: t('views.monitor.topologyBuild.graphModeEdit'),
    },
  ];

  /**图画布右击菜单 */
  const graphCanvasMenu = new Menu({
    offsetX: 6,
    offseY: 10,
    itemTypes: ['canvas'],
    getContent(evt) {
      if (!evt) return t('views.monitor.topologyBuild.graphNotInfo');
      const edit = graphMode.value === 'edit';
      return `
      <div
        style="
          display: flex;
          flex-direction: column;
          width: 140px;
        "
      >
        <h3>${t('views.monitor.topologyBuild.graphCanvas')}</h3>
        <div id="show" style="cursor: pointer; margin-bottom: 2px">
          ${t('views.monitor.topologyBuild.graphMenuHideAllShow')}
        </div>
        <div id="create-edge" style="cursor: pointer; margin-bottom: 2px; display: ${
          edit ? 'black' : 'none'
        }">
          ${t('views.monitor.topologyBuild.graphMenuAddEdge')}
        </div>
        <div id="create-node" style="cursor: pointer; margin-bottom: 2px; display: ${
          edit ? 'black' : 'none'
        }">
          ${t('views.monitor.topologyBuild.graphMenuAddNode')}
        </div>
        <div id="create-combo" style="cursor: pointer; margin-bottom: 2px; display: ${
          edit ? 'black' : 'none'
        }">
          ${t('views.monitor.topologyBuild.graphMenuAddCombo')}
        </div> 
      </div>`;
    },
    handleMenuClick(target, item) {
      // console.log(target, item);
      const targetId = target.id;
      switch (targetId) {
        case 'create-edge':
        case 'create-node':
        case 'create-combo':
          graphEvent.value = { type: `canvas-${targetId}`, target, item };
          break;
        case 'show':
          // 显示节点
          graphG6.value.getNodes().forEach((node: any) => {
            if (!node.isVisible()) {
              graphG6.value.showItem(node);
              graphG6.value.refreshItem(node);
            }
          });
          // 显示边
          graphG6.value.getEdges().forEach((edge: any) => {
            if (!edge.isVisible()) {
              graphG6.value.showItem(edge);
              graphG6.value.refreshItem(edge);
            }
          });
          // 显示分组
          graphG6.value.getCombos().forEach((combo: any) => {
            if (!combo.isVisible()) {
              graphG6.value.showItem(combo);
              graphG6.value.updateCombo(combo);
            }
          });
          break;
      }
    },
  });

  /**图分组Combo 右击菜单 */
  const graphComboMenu = new Menu({
    offsetX: 6,
    offseY: 10,
    itemTypes: ['combo'],
    getContent(evt) {
      if (!evt) return t('views.monitor.topologyBuild.graphNotInfo');
      const item = evt.item?.getModel();
      const edit = graphMode.value === 'edit';
      return `
    <div
      style="
        display: flex;
        flex-direction: column;
        width: 140px;
      "
    >
      <h3 style="margin-bottom: 8px">
      ${t('views.monitor.topologyBuild.graphCombo')}:
      ${item?.label || item?.id}
      </h3>
      <div id="hide" style="cursor: pointer; margin-bottom: 2px">
        ${t('views.monitor.topologyBuild.graphMenuHide')}
      </div>
      <div id="edit" style="cursor: pointer; margin-bottom: 2px;display: ${
        edit ? 'black' : 'none'
      }">
        ${t('views.monitor.topologyBuild.graphMenuEdit')}
      </div>
      <div id="delete" style="cursor: pointer; margin-bottom: 2px; display: ${
        edit ? 'black' : 'none'
      }">
        ${t('views.monitor.topologyBuild.graphMenuDel')}
      </div>
      
    </div>
    `;
    },
    handleMenuClick(target, item) {
      const targetId = target.id;
      switch (targetId) {
        case 'edit':
          graphEvent.value = { type: `combo-${targetId}`, target, item };
          break;
        case 'delete':
          graphG6.value.uncombo(item);
          graphG6.value.updateCombos();
          break;
        case 'hide':
          graphG6.value.hideItem(item);
          break;
      }
    },
  });

  /**图节点右击菜单 */
  const graphNodeMenu = new Menu({
    offsetX: 6,
    offseY: 10,
    itemTypes: ['node'],
    getContent(evt) {
      if (!evt) return t('views.monitor.topologyBuild.graphNotInfo');
      const item = evt.item?.getModel();
      const edit = graphMode.value === 'edit';
      return `
    <div
      style="
        display: flex;
        flex-direction: column;
        width: 140px;
      "
    >
      <h3 style="margin-bottom: 8px">
      ${t('views.monitor.topologyBuild.graphNode')}:
      ${item?.label || item?.id}
      </h3>
      <div id="hide" style="cursor: pointer; margin-bottom: 4px">
        ${t('views.monitor.topologyBuild.graphMenuHide')}
      </div>
      <div id="edit" style="cursor: pointer; margin-bottom: 4px; display: ${
        edit ? 'black' : 'none'
      }">
        ${t('views.monitor.topologyBuild.graphMenuEdit')}
      </div>
      <div id="delete" style="cursor: pointer; margin-bottom: 4px; display: ${
        edit ? 'black' : 'none'
      }">
        ${t('views.monitor.topologyBuild.graphMenuDel')}
      </div>
      
    </div>
    `;
    },
    handleMenuClick(target, item) {
      // console.log(target, item);
      const targetId = target.id;
      switch (targetId) {
        case 'edit':
          graphEvent.value = { type: `node-${targetId}`, target, item };
          break;
        case 'delete':
          graphG6.value.removeItem(item);
          break;
        case 'hide':
          graphG6.value.hideItem(item);
          break;
      }
    },
  });

  /**图节点展示 */
  const graphNodeTooltip = new Tooltip({
    offsetX: 10,
    offsetY: 20,
    getContent(evt) {
      if (!evt) return t('views.monitor.topologyBuild.graphNotInfo');
      const item = evt.item?.getModel();
      return `
      <div
        style="
          display: flex;
          flex-direction: column;
          width: 140px;
        "
      >
         <h3>
         ${t('views.monitor.topologyBuild.graphNode')}:
         ${item?.label || item?.id}
         </h3>
      </div>
      `;
    },
    itemTypes: ['node'],
  });

  /**图边右击菜单 */
  const graphEdgeMenu = new Menu({
    offsetX: 6,
    offseY: 10,
    itemTypes: ['edge'],
    getContent(evt) {
      if (!evt) return t('views.monitor.topologyBuild.graphNotInfo');
      const item = evt.item?.getModel();
      const edit = graphMode.value === 'edit';
      return `
    <div
      style="
        display: flex;
        flex-direction: column;
        width: 140px;
      "
    >
      <h3 style="margin-bottom: 8px">
      ${t('views.monitor.topologyBuild.graphEdge')}
      ${item?.label && `:${item?.label}`}
      </h3>
      <div id="hide" style="cursor: pointer; margin-bottom: 4px">
        ${t('views.monitor.topologyBuild.graphMenuHide')}
      </div>
      <div id="edit" style="cursor: pointer; margin-bottom: 4px; display: ${
        edit ? 'black' : 'none'
      }">
        ${t('views.monitor.topologyBuild.graphMenuEdit')}
      </div>
      <div id="delete" style="cursor: pointer; margin-bottom: 4px; display: ${
        edit ? 'black' : 'none'
      }">
        ${t('views.monitor.topologyBuild.graphMenuDel')}
      </div> 
    </div>
    `;
    },
    handleMenuClick(target, item) {
      // console.log(target, item);
      const targetId = target.id;
      switch (targetId) {
        case 'edit':
          graphEvent.value = { type: `edge-${targetId}`, target, item };
          break;
        case 'delete':
          graphG6.value.removeItem(item);
          break;
        case 'hide':
          graphG6.value.hideItem(item);
          break;
      }
    },
  });

  /**图边展示 */
  const graphEdgeTooltip = new Tooltip({
    offsetX: 10,
    offsetY: 20,
    getContent(evt) {
      if (!evt) return t('views.monitor.topologyBuild.graphNotInfo');
      const item = evt.item?.getModel();
      return `
      <div
        style="
          display: flex;
          flex-direction: column;
          width: 140px;
        "
      >
        <h3> 
          ${t('views.monitor.topologyBuild.graphEdge')}
          ${item?.label && `:${item?.label}`}
        </h3> 
      </div>
      `;
    },
    itemTypes: ['edge'],
  });

  /**图绑定事件 */
  function fnGraphEvent(graph: Graph) {
    // 调用 graph.add / graph.addItem 方法之后触发
    graph.on('afteradditem', evt => {
      fnSelectSourceTargetOptionsData();
    });

    // 鼠标进入节点事件
    graph.on('edge:mouseenter', (ev: any) => {
      // 获得鼠标当前目标边
      const edge = ev.item;
      // 该边的起始点
      const source = edge.getSource();
      // 该边的结束点
      const target = edge.getTarget();
      // 先将边提前，再将端点提前。这样该边两个端点还是在该边上层，较符合常规。
      // edge.toFront();
      // source.toFront();
      // target.toFront();
    });

    graph.on('edge:mouseleave', (ev: any) => {
      // 获得图上所有边实例
      const edges = graph.getEdges();
      // 遍历边，将所有边的层级放置在后方，以恢复原样
      // edges.forEach(edge => {
      //   edge.toBack();
      // });
    });

    graph.on('node:mouseenter', evt => {
      // 获得鼠标当前目标节点
      const node = evt.item;
      // 获取该节点的所有相关边
      const edges = node && graph.getEdges();
      // 遍历相关边，将所有相关边提前，再将相关边的两个端点提前，以保证相关边的端点在边的上方常规效果
      // edges.forEach((edge: any) => {
      //   edge.toFront();
      //   edge.getSource().toFront();
      //   edge.getTarget().toFront();
      // });
      // graphEvent.value = {
      //   type: 'node:mouseenter',
      //   target: evt.target,
      //   item: evt.item,
      // };
    });

    graph.on('node:mouseleave', (ev: any) => {
      // 获得图上所有边实例
      const edges = graph.getEdges();
      // 遍历边，将所有边的层级放置在后方，以恢复原样
      // edges.forEach(edge => {
      //   edge.toBack();
      // });
    });
  }

  /**
   * 图元素选择开始结束点数据获取
   */
  function fnSelectSourceTargetOptionsData() {
    // 节点
    selectSourceTargetOptions.value = [];
    graphG6.value.getNodes().forEach((node: any) => {
      const info = JSON.parse(JSON.stringify(node.getModel()));
      selectSourceTargetOptions.value.push({
        value: info.id,
        label: info.label || info.id,
        info,
      });
    });
    // 分组
    selectComboOptions.value = [
      {
        value: '',
        label: '#',
      },
    ];
    graphG6.value.getCombos().forEach((combo: any) => {
      const info = JSON.parse(JSON.stringify(combo.getModel()));
      const comboInfo = {
        value: info.id,
        label: info.label || info.id,
        info,
      };
      selectSourceTargetOptions.value.push(comboInfo);
      selectComboOptions.value.push(comboInfo);
    });
  }

  /**注册自定义边或节点 */
  function registerEdgeNode() {
    // 边
    edgeCubicAnimateLineDash();
    edgeCubicAnimateCircleMove();
    edgeLineAnimateState();
    // 节点
    nodeCircleAnimateShapeR();
    nodeCircleAnimateShapeStroke();
    nodeRectAnimateState();
    nodeImageAnimateState();
  }

  /**图数据渲染 */
  function handleRanderGraph(
    container: HTMLElement | undefined,
    data: GraphData
  ) {
    if (!container) return;
    const { clientHeight, clientWidth } = container;

    registerEdgeNode();

    const graph = new Graph({
      container: container,
      width: clientWidth,
      height: clientHeight,
      fitCenter: true,
      modes: {
        default: [
          {
            type: 'click-select',
            selectEdge: true,
          },
          'drag-combo',
          {
            type: 'drag-node',
            onlyChangeComboSize: true,
          },
          'drag-canvas',
          'zoom-canvas',
          'collapse-expand-combo',
        ],
        edit: [
          {
            type: 'click-select',
            selectEdge: true,
          },
          {
            type: 'drag-node',
            shouldEnd: (e: any) => {
              return true;
            },
          },
          { type: 'drag-combo' },
          'drag-canvas',
          'zoom-canvas',
          { type: 'create-edge', key: 'alt' },
        ],
      },
      groupByTypes: false,
      // 全局节点
      defaultNode: {
        type: 'rect',
        size: [80, 40],
        style: {
          radius: 4,
          // fill: '#ffffff',
          stroke: '#ffffff',
          lineWidth: 1,
          cursor: 'pointer',
        },
        labelCfg: {
          position: 'center',
          offset: 0,
          style: {
            fill: '#000000',
            fontSize: 12,
            fontWeight: 500,
          },
        },
        icon: {
          show: false,
          img: '/svg/service.svg',
          width: 25,
          height: 25,
          offset: 20, // triangle 特有
        },
        direction: 'up', // triangle 三角形的方向
      },
      // 全局边
      defaultEdge: {
        type: 'polyline',
        style: {
          offset: 20, // 拐弯处距离节点最小距离
          radius: 2, // 拐弯处的圆角弧度，若不设置则为直角
          stroke: '#ffffff',
          lineWidth: 1,
          cursor: 'pointer',
        },
        labelCfg: {
          refX: 0,
          refY: 0,
          position: 'middle',
          autoRotate: false,
          style: {
            fill: '#ffffff',
            fontSize: 12,
            fontWeight: 500,
          },
        },
      },
      // 全局分组节点
      defaultCombo: {
        type: 'rect', // Combo 类型
        size: [40, 40],
        padding: [30, 30, 30, 30],
        style: {
          radius: 2,
          fill: '#ffffff',
          stroke: '#ffffff',
          lineWidth: 1,
          cursor: 'grab',
          fillOpacity: 0.5,
        },
        labelCfg: {
          refX: 10,
          refY: 10,
          position: 'top',
          style: {
            fill: '#000000',
            fontSize: 12,
            fontWeight: 500,
          },
        },
      },
      plugins: [
        graphCanvasMenu,
        graphComboMenu,
        graphNodeMenu,
        graphNodeTooltip,
        graphEdgeMenu,
        graphEdgeTooltip,
      ],
      animate: true, // 是否使用动画过度，默认为 false
      animateCfg: {
        duration: 500, // Number，一次动画的时长
        easing: 'linearEasing', // String，动画函数
      },
    });
    graph.data(data);
    graph.render();

    // 图绑定事件
    fnGraphEvent(graph);

    graphG6.value = graph;

    // 创建 ResizeObserver 实例
    var observer = new ResizeObserver(function (entries) {
      // 当元素大小发生变化时触发回调函数
      entries.forEach(function (entry) {
        if (!graphG6.value) {
          return;
        }
        graphG6.value.changeSize(
          entry.contentRect.width,
          entry.contentRect.height - 30
        );
        graphG6.value.fitCenter();
      });
    });
    // 监听元素大小变化
    observer.observe(container);

    // 图元素选择开始结束点数据
    fnSelectSourceTargetOptionsData();

    return graph;
  }

  /**图模式改变 default | edit */
  function handleChangeMode(value: any) {
    // console.log(value, JSON.parse(JSON.stringify(graphG6.value.save())));
    graphG6.value.setMode(value);
    graphMode.value = graphG6.value.getCurrentMode();
  }

  onBeforeUnmount(() => {
    graphG6.value = null;
    graphEvent.value = null;
    selectSourceTargetOptions.value = [];
    selectComboOptions.value = [];
  });

  return {
    graphMode,
    graphModeOptions,
    handleRanderGraph,
    handleChangeMode,
  };
}
