import { ContextMenuTool, edgeMenu } from "./contentMenu";
import Text from "@/components/basic/text";
import baseNode from "@/components/Base";
import { Cell, CellView, Edge, Graph, Node } from "@antv/x6";
import { nodeMenu } from "./contentMenu";
import { exportImage } from "@/components/ExportImage";
import { BaseEdge } from "@/components/Edge";
import { set, cloneDeep, get } from "lodash-es";
import { defaultData } from "@/config/data";
import codeBlock from "@/components/basic/CodeBlock";
import { ConnectorType } from "@/enum";

/**
 * 右键菜单处理方法
 */
export const menuHander = {
  /**复制 */
  copy(tool: ContextMenuTool) {
    tool.graph.select(tool.cell);
    handleCopy(tool.graph);
  },
  /**剪切 */
  cut(tool: ContextMenuTool) {
    tool.graph.select(tool.cell);
    tool.graph.cut(tool.graph.getSelectedCells(), {
      useLocalStorage: true,
      deep: false,
    });
    navigator.clipboard.writeText(" ");
  },
  /**复用 */
  duplicate(tool: ContextMenuTool) {
    tool.graph.select(tool.cell);
    handleDuplicate(tool.graph);
  },
  /**删除 */
  delete(tool: ContextMenuTool) {
    handleDelete(tool.graph);
  },
  /**粘贴 */
  paste(tool: ContextMenuTool, e: MouseEvent) {
    handlePaste(tool.graph, { x: e.offsetX, y: e.offsetY });
  },
  /**放大 */
  zoomIn(tool: ContextMenuTool) {
    const { sx } = tool.graph.scale();
    tool.graph.zoomTo(sx + 0.1);
  },
  /**缩小 */
  zoomOut(tool: ContextMenuTool) {
    const { sx } = tool.graph.scale();
    tool.graph.zoomTo(sx - 0.1);
  },
  /**重置视图 */
  resetView(tool: ContextMenuTool) {
    tool.graph.zoomToFit({});
  },
  // 全选
  selectAll(tool: ContextMenuTool) {
    selectAll(tool.graph);
  },
  // 创建连线
  createLine(tool: ContextMenuTool) {
    handleCreateEdge(tool.graph);
  },
  // 插入图片
  insertImage(tool: ContextMenuTool) {
    handleInsertImage(tool.graph);
  },
  // 上移一层
  up(tool: ContextMenuTool, e: MouseEvent) {
    tool.graph.select(tool.cell);
    setCellZIndex("up", tool.graph.getSelectedCells());
  },
  // 下移一层
  down(tool: ContextMenuTool, e: MouseEvent) {
    tool.graph.select(tool.cell);
    setCellZIndex("down", tool.graph.getSelectedCells());
  },
  // 置顶
  top(tool: ContextMenuTool, e: MouseEvent) {
    tool.graph.select(tool.cell);
    setCellZIndex("top", tool.graph.getSelectedCells());
  },
  // 置底
  bottom(tool: ContextMenuTool, e: MouseEvent) {
    tool.graph.select(tool.cell);
    setCellZIndex("bottom", tool.graph.getSelectedCells());
  },
  // 设置默认样式
  defaultStyle(tool: ContextMenuTool, e: MouseEvent) {},
  // 恢复默认样式
  resetStyle(tool: ContextMenuTool, e: MouseEvent) {},
  // 锁定
  lock(tool: ContextMenuTool, e: MouseEvent) {
    tool.graph.select(tool.cell);
    handleLock(tool.graph);
  },
  // 解锁
  unlock(tool: ContextMenuTool) {
    handleUnLock(tool.graph, tool.cell);
  },
  // 导出图形
  exportImage(tool: ContextMenuTool, e: MouseEvent) {
    exportImage(tool.graph);
  },
  // 复制所选图形为图片
  copyAsImage(tool: ContextMenuTool, e: MouseEvent) {
    tool.graph.toPNG((dataUrl) => {
      // base64转bolb
      let arr = dataUrl.split(",");
      let mime = arr[0].match(/:(.*?);/)?.[1];
      let bstr = atob(arr[1]);
      let n = bstr.length;
      let u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      const bolb = new Blob([u8arr], { type: mime });
      const data = [new ClipboardItem({ [bolb.type]: bolb })];
      navigator.clipboard.write(data);
    });
  },
  // 替换图形
  replace(tool: ContextMenuTool, e: MouseEvent) {},
};

export const selectAll = (graph: Graph) => {
  graph.getCells().forEach((cell) => {
    if (!cell.getData()?.isPage) {
      graph.select(cell);
    }
  });
};

/**
 * 执行粘贴
 * @param graph
 * @param position
 */
export const handlePaste = (
  graph: Graph,
  position?: { x: number; y: number }
) => {
  // 读取剪切板数据
  navigator.clipboard.read().then((items) => {
    console.log("剪切板内容：", items);
    const item = items?.[0];
    if (item) {
      /**读取图片数据 */
      if (item.types[0] === "image/png") {
        item.getType("image/png").then((blob) => {
          const reader = new FileReader();
          reader.readAsDataURL(blob);
          reader.onload = function (event) {
            const dataUrl = event.target?.result as string;
            // 获取图片大小
            const img = new Image();
            img.src = dataUrl;
            img.onload = function () {
              const width = img.width;
              const height = img.height;
              // 插入图片
              const node = {
                ...baseNode,
                data: {
                  ...baseNode.data,
                  fill: {
                    ...baseNode.data.fill,
                    fillType: "image",
                    imageUrl: dataUrl,
                  },
                },
                size: {
                  width,
                  height,
                },
                position,
              };
              graph.addNode(node);
            };
          };
        });
      }
      /**读取文本数据 */
      if (item.types[0] === "text/plain") {
        item.getType("text/plain").then((blob) => {
          const reader = new FileReader();
          reader.readAsText(blob);
          reader.onload = function (event) {
            const text = event.target?.result as string;
            const exd = position ? { position } : {};
            // 内部复制方法
            if (text === " ") {
              // 执行cell复制操作
              // todo 多选设置位置
              graph.paste({
                offset: {
                  dx: 20,
                  dy: 20,
                },
                nodeProps: {
                  ...exd,
                  // @ts-ignore
                  tools: [
                    {
                      name: "contextmenu",
                      args: {
                        menu: nodeMenu,
                      },
                    },
                  ],
                },
                edgeProps: {
                  ...exd,
                  // @ts-ignore
                  tools: [
                    {
                      name: "contextmenu",
                      args: {
                        menu: edgeMenu,
                      },
                    },
                  ],
                },
                useLocalStorage: true,
              });
            } else {
              // 宽度最低100 最高300 高度等于行高*行数
              const width =
                text.length * 15 >= 300
                  ? 300
                  : text.length * 15 < 100
                    ? 100
                    : text.length * 15;
              const height = text.split("\n").length * 20;
              const node = {
                ...Text.node,
                data: {
                  ...Text.node.data,
                  label: text,
                },
                position,
                size: {
                  width,
                  height,
                },
                tools: [
                  {
                    name: "contextmenu",
                    args: {
                      menu: nodeMenu,
                    },
                  },
                ],
              };
              // 插入文本
              graph.addNode(node);
            }
          };
        });
      }
    }
  });
};

/**
 * 执行拷贝
 * @param graph
 */
export const handleCopy = (graph: Graph) => {
  graph.copy(graph.getSelectedCells(), { useLocalStorage: true, deep: false });
  navigator.clipboard.writeText(" ");
};

/**
 * 执行复用
 * @param graph
 */
export const handleDuplicate = (graph: Graph) => {
  handleCopy(graph);
  graph.paste({
    offset: {
      dx: 20,
      dy: 20,
    },
    nodeProps: {
      // @ts-ignore
      tools: [
        {
          name: "contextmenu",
          args: {
            menu: nodeMenu,
          },
        },
      ],
    },
    edgeProps: {
      // @ts-ignore
      tools: [
        {
          name: "contextmenu",
          args: {
            menu: edgeMenu,
          },
        },
      ],
    },
    useLocalStorage: true,
  });
};

/**
 * 创建边线
 * @param graph
 */
export const handleCreateEdge = (graph: Graph) => {
  let createEdgeMode = true;
  let start: { x: number; y: number } | undefined;
  let edge: Edge | undefined;

  const graphRoot = document.querySelector(
    "#graph-container"
  ) as HTMLDivElement;
  if (graphRoot) {
    graphRoot.style.cursor = "crosshair";
  }
  const pageRoot = document.querySelector(
    "#flow_canvas_container"
  ) as HTMLDivElement;
  if (pageRoot) {
    pageRoot.style.cursor = "crosshair";
  }
  const handleCreate = ({ e, cell }: { e: MouseEvent; cell?: Cell }) => {
    if (cell && !cell.getData()?.isPage) return;
    start = { x: e.offsetX, y: e.offsetY };
    graphRoot.style.cursor = "default";
    pageRoot.style.cursor = "default";
  };
  const handleMove = ({
    e,
    x,
    y,
    node,
  }: {
    e: MouseEvent;
    x: number;
    y: number;
    node?: Node;
  }) => {
    if (node && !node.getData()?.isPage) return;
    if (!createEdgeMode || !start) return;

    // 判断起始点是否移动了10px
    if (Math.abs(x - start.x) > 10 || Math.abs(y - start.y) > 10) {
      // 判断是否已创建边，创建了则修改目标位置
      if (!edge) {
        edge = graph.addEdge({
          ...BaseEdge,
          source: {
            x: start.x,
            y: start.y,
          },
          target: {
            x: e.offsetX,
            y: e.offsetY,
          },
          data: {
            connectorType: ConnectorType.Rounded
          },
          tools: [
            {
              name: "contextmenu",
              args: {
                menu: edgeMenu,
              },
            },
          ],
        });
      } else {
        edge.setTarget({
          x: e.offsetX,
          y: e.offsetY,
        });
      }
    }
  };

  const handleCancel = () => {
    createEdgeMode = false;
    start = undefined;
    graphRoot.style.cursor = "default";
    pageRoot.style.cursor = "default";
    graph.off("blank:mousedown", handleCreate);
    graph.off("node:mousedown", handleCreate);
    graph.off("blank:mousemove", handleMove);
    graph.off("node:mousemove", handleMove);
  };

  graph.on("blank:mousedown", handleCreate);
  graph.on("node:mousedown", handleCreate);
  graph.on("blank:mousemove", handleMove);
  graph.on("node:mousemove", handleMove);

  graph.on("cell:click", ({ cell }) => {
    if (cell && cell.getData()?.isPage) return;
    handleCancel();
  });
  graph.on("cell:mouseup", handleCancel);
  graph.on("blank:mouseup", handleCancel);
  graph.on("cancel", handleCancel);
};

/**
 * 插入文本节点
 * @param graph
 */
export const handleInsertText = (graph: Graph) => {
  let createEdgeMode = true;

  const graphRoot = document.querySelector(
    "#graph-container"
  ) as HTMLDivElement;
  if (graphRoot) {
    graphRoot.style.cursor = "crosshair";
  }
  const pageRoot = document.querySelector(
    "#flow_canvas_container"
  ) as HTMLDivElement;
  if (pageRoot) {
    pageRoot.style.cursor = "crosshair";
  }
  const handleCreate = ({ e, cell }: { e: MouseEvent; cell?: Cell }) => {
    if (cell && !cell.getData()?.isPage) {
      handleCancel();
      return;
    }
    if (createEdgeMode) {
      const node = {
        ...Text.node,
        position: {
          x: e.offsetX,
          y: e.offsetY,
        },
        tools: [
          {
            name: "contextmenu",
            args: {
              menu: nodeMenu,
            },
          },
        ],
      };
      graph.addNode(node);
      handleCancel();
    }
  };

  const handleCancel = () => {
    createEdgeMode = false;
    graph.off("blank:click", handleCreate);
    graph.off("node:click", handleCreate);
    graphRoot.style.cursor = "default";
    pageRoot.style.cursor = "default";
  };

  graph.on("blank:click", handleCreate);
  graph.on("node:click", handleCreate);

  graph.on("cancel", handleCancel);
};

/**
 * 插入图片
 * @param graph
 */
export const handleInsertImage = (graph: Graph) => {};

/**
 * 插入代码块
 * @param graph
 */
export const handleInsertCode = (graph: Graph) => {
  let createEdgeMode = true;

  const graphRoot = document.querySelector(
    "#graph-container"
  ) as HTMLDivElement;
  if (graphRoot) {
    graphRoot.style.cursor = "crosshair";
  }
  const pageRoot = document.querySelector(
    "#flow_canvas_container"
  ) as HTMLDivElement;
  if (pageRoot) {
    pageRoot.style.cursor = "crosshair";
  }
  const handleCreate = ({ e, cell }: { e: MouseEvent; cell?: Cell }) => {
    if (cell && !cell.getData()?.isPage) {
      handleCancel();
      return;
    }
    if (createEdgeMode) {
      const node = {
        ...codeBlock.node,
        position: {
          x: e.offsetX,
          y: e.offsetY,
        },
        tools: [
          {
            name: "contextmenu",
            args: {
              menu: nodeMenu,
            },
          },
        ],
      };
      graph.addNode(node);
      handleCancel();
    }
  };

  const handleCancel = () => {
    createEdgeMode = false;
    graph.off("blank:click", handleCreate);
    graph.off("node:click", handleCreate);
    graphRoot.style.cursor = "default";
    pageRoot.style.cursor = "default";
  };

  graph.on("blank:click", handleCreate);
  graph.on("node:click", handleCreate);

  graph.on("cancel", handleCancel);
};

/**
 * 设置已选元素属性
 * @param graph x6图形
 * @param path 属性路径
 * @param value 属性值
 */
export const handleSetAttr = (graph: Graph, path: string, value: any) => {
  const cells = graph.getSelectedCells();
  (cells || []).forEach((cell) => {
    const data = cloneDeep(cell.getData() || {});
    // 获取原始值
    const val = get(data, path);
    // 如果是布尔值 则取相反值
    if (typeof val === "boolean") {
      set(data, path, !val);
    } else {
      set(data, path, value);
    }
    
    cell.setData({
      ...data,
    });
  });
};

/**
 * 对齐操作
 * @param type 对齐类型
 * @param cells 元素列表
 */
export const alignCell = (
  type: "left" | "hcenter" | "right" | "top" | "vcenter" | "bottom" | "h" | "v",
  cells: Cell[]
) => {
  const nodes = cells?.filter((item) => item.isNode());
  if (!nodes?.length) return;

  const maxX = Math.max(...nodes.map((cell) => cell.position().x));
  const maxY = Math.max(...nodes.map((cell) => cell.position().y));
  const minX = Math.min(...nodes.map((cell) => cell.position().x));
  const minY = Math.min(...nodes.map((cell) => cell.position().y));
  const middleX = (minX + maxX) / 2;
  const middleY = (minY + maxY) / 2;
  nodes?.forEach((node, index) => {
    const { x, y } = node.position();
    switch (type) {
      case "left":
        node.setPosition(minX, y);
        break;
      case "hcenter":
        node.setPosition(x, middleY);
        break;
      case "right":
        node.setPosition(maxX, y);
        break;
      case "top":
        node.setPosition(x, minY);
        break;
      case "vcenter":
        node.setPosition(middleX, y);
        break;
      case "bottom":
        node.setPosition(x, maxY);
        break;
      case "h": {
        if (nodes.length < 3) break;
        const interval = (maxX - minX) / (nodes.length - 1);
        node.setPosition(minX + interval * index, y);
        break;
      }
      case "v": {
        if (nodes.length < 3) break;
        const interval = (maxY - minY) / (nodes.length - 1);
        node.setPosition(x, minY + interval * index);
        break;
      }
    }
  });
};

/**
 * 匹配宽高操作
 * @param type 匹配类型
 * @param cells 元素列表
 */
export const matchSize = (type: "width" | "height" | "auto", cells: Cell[]) => {
  const nodes = cells?.filter((item) => item.isNode());
  const maxWidth = nodes?.reduce((pre, cur) => {
    return Math.max(pre, cur.size().width);
  }, 0);
  const maxHeight = nodes?.reduce((pre, cur) => {
    return Math.max(pre, cur.size().height);
  }, 0);
  nodes?.forEach((node) => {
    const { width, height } = node.size();
    if (type === "width") {
      node.setSize(maxWidth || width, height);
    } else if (type === "height") {
      node.resize(width, maxHeight || height);
    } else {
      node.resize(maxWidth || width, maxHeight || height);
    }
  });
};

/**
 * 设置元素层级
 * @param type 移动类型
 * @param cells 元素列表
 */
export const setCellZIndex = (
  type: "top" | "bottom" | "up" | "down",
  cells: Cell[]
) => {
  // todo 重新调整全部层级
  cells?.forEach((cell) => {
    switch (type) {
      case "top":
        cell.toFront();
        break;
      case "bottom":
        cell.setZIndex(0);
        break;
      case "up": {
        const index = cell.getZIndex() || 0;
        cell.setZIndex(index + 1);
        break;
      }
      case "down": {
        const index = cell.getZIndex() || 0;
        if (index <= 0) return;
        cell.setZIndex(index - 1);
        break;
      }
    }
  });
};

/**
 * 组合
 * @param graph
 * @param cells
 */
export const handleGroup = (graph: Graph, cells: Cell[]) => {
  const xPoint: number[] = [];
  const yPoint: number[] = [];
  cells.forEach((cell) => {
    if (cell.isNode()) {
      const position = cell.position();
      xPoint.push(position.x, position.x + cell.size().width);
      yPoint.push(position.y, position.y + cell.size().height);
    }
    if (cell.isEdge()) {
      const sourcePoint = cell.getSourcePoint();
      const targetPoint = cell.getTargetPoint();
      xPoint.push(sourcePoint.x, targetPoint.x);
      yPoint.push(sourcePoint.y, targetPoint.y);
    }
  });
  const minX = Math.min(...xPoint);
  const minY = Math.min(...yPoint);
  const maxX = Math.max(...xPoint);
  const maxY = Math.max(...yPoint);
  const parent = graph.addNode({
    x: minX,
    y: minY,
    width: maxX - minX,
    height: maxY - minY,
    attrs: {
      body: {
        fill: "transparent",
        strokeWidth: 0,
      },
    },
    data: {
      isGroup: true,
      ...defaultData,
    },
  });
  cells?.forEach((cell) => parent.addChild(cell));
  graph.select(parent);
  graph.createTransformWidget(parent);
};

/**
 * 解组合
 * @param graph
 */
export const handleUnGroup = (graph: Graph, cells?: Cell[]) => {
  // const cells = graph.getSelectedCells();
  cells = cells || graph.getSelectedCells();
  cells?.forEach((cell) => {
    if (cell.data?.isGroup) {
      const children = cell.getChildren();
      cell.setChildren(null);
      children?.forEach((child) => {
        child.setParent(null);
        graph.addCell(child);
      });
      graph.removeCell(cell.id);
    }
  });
};

/**
 * 移动图形
 * @param graph
 * @param direction 移动方向x or y
 * @param distance 移动距离
 */
export const handleMove = (
  graph: Graph,
  direction: "x" | "y",
  distance: number
) => {
  const cells = graph.getSelectedCells();
  cells?.forEach((cell) => {
    if (cell.isNode()) {
      const position = cell.position();
      cell.setPosition({
        ...position,
        [direction]: position[direction] + distance,
      });
    }
    if (cell.isEdge()) {
      const source = cell.getSource();
      const sourcePoint = cell.getSourcePoint();
      const target = cell.getTarget();
      const targetPoint = cell.getTargetPoint();
      cell.setSource({
        ...source,
        ...sourcePoint,
        [direction]: sourcePoint[direction] + distance,
      });
      cell.setTarget({
        ...target,
        ...targetPoint,
        [direction]: targetPoint[direction] + distance,
      });
    }
  });
};

/**
 * 锁定
 * @param graph
 */
export const handleLock = (graph: Graph) => {
  const cells = graph.getSelectedCells();
  cells?.forEach((cell) => {
    cell.setData({
      lock: true,
    });
  });
  graph.cleanSelection();
  graph.clearTransformWidgets();
};

/**
 * 解锁
 * @param graph
 * @param cell
 */
export const handleUnLock = (graph: Graph, cell?: Cell) => {
  if(cell) {
    cell.setData({
      lock: false,
    });
    graph.select([cell]);
    if(cell.isNode()) {
      graph.createTransformWidget(cell)
    }
  } else {
    const cells = graph.getCells();
    cells.forEach((cell) => {
      if(cell.data?.lock) {
        cell.setData({
          lock: false,
        });
      }
    });
  }
};

/**
 * 删除
 * @param graph
 */
export const handleDelete = (graph: Graph) => {
  const cells = graph.getSelectedCells();
  graph.removeCells(cells);
};

/**
 * 设置连线样式
 * @param edge 
 * @param style 
 */
export const handleSetEdgeStyle = (edge: Cell, style: ConnectorType, jumpover: boolean) => {
  if(!edge.isEdge()) return;
  switch(style) {
    case ConnectorType.Rounded: {
      edge.setRouter("manhattan");
      edge.setConnector(jumpover ? "jumpover" : "normal")
      break;
    }
    case ConnectorType.Smooth: {
      edge.setRouter("manhattan");
      edge.setConnector("smooth")
      break;
    }
    case ConnectorType.Normal: {
      edge.setRouter("normal");
      edge.setConnector("normal");
      break;
    }
  }
}
