import { StructureType, MindmapConnectorType, TopicType } from "@/enum";
import { TopicItem } from "@/types";
import { Edge, Graph, Path } from "@antv/x6";
import { getTheme } from "./theme";
import { caclculateX } from "@/utils/hierarchy/rightFishbone";

// 曲线
Graph.registerConnector(
  "curve-branch-connector",
  (sourcePoint, targetPoint, routerPoints, options) => {
    const midX = sourcePoint.x;
    const ctrX = (targetPoint.x - midX) / 5 + midX;
    const ctrY = targetPoint.y;
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     Q ${ctrX} ${ctrY} ${targetPoint.x} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);
Graph.registerConnector(
  "curve-sub-connector",
  (sourcePoint, targetPoint, routerPoints, options) => {
    const midX = sourcePoint.x + (sourcePoint.x < targetPoint.x ? 10 : -10);
    const midY = sourcePoint.y;
    const ctrX = (targetPoint.x - midX) / 5 + midX;
    const ctrY = targetPoint.y;
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     L ${midX} ${midY}
     Q ${ctrX} ${ctrY} ${targetPoint.x} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);
// 直线
Graph.registerConnector(
  "straight-branch-connector",
  function (sourcePoint, targetPoint, routerPoints, options) {
    const halfWidth = this.sourceBBox.width / 2;
    const midX =
      sourcePoint.x +
      (sourcePoint.x < targetPoint.x ? halfWidth + 10 : -halfWidth - 10);
    const midY = sourcePoint.y;
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     L ${midX} ${midY}
     L ${targetPoint.x} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);
Graph.registerConnector(
  "straight-sub-connector",
  function (sourcePoint, targetPoint, routerPoints, options) {
    const midX = sourcePoint.x + (sourcePoint.x < targetPoint.x ? 10 : -10);
    const midY = sourcePoint.y;
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     L ${midX} ${midY}
     L ${targetPoint.x} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);
// 圆角折线
Graph.registerConnector(
  "rounded-branch-connector",
  function (sourcePoint, targetPoint, routerPoints, options) {
    const halfWidth = this.sourceBBox.width / 2;
    const midX =
      sourcePoint.x +
      (sourcePoint.x < targetPoint.x ? halfWidth + 10 : -halfWidth - 10);
    const midY = sourcePoint.y;
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     L ${midX} ${midY}
     L ${midX} ${targetPoint.y + (targetPoint.y < sourcePoint.y ? 5 : targetPoint.y === sourcePoint.y ? 0 : -5)}
     Q ${midX} ${targetPoint.y} ${midX + (targetPoint.x < sourcePoint.x ? -5 : 5)} ${targetPoint.y}
     L ${targetPoint.x} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);
Graph.registerConnector(
  "rounded-sub-connector",
  (sourcePoint, targetPoint, routerPoints, options) => {
    const midX =
      sourcePoint.x < targetPoint.x ? sourcePoint.x + 10 : sourcePoint.x - 10;
    const midY = sourcePoint.y;
    // 可能存在误差
    const deviationY = Math.abs(targetPoint.y - sourcePoint.y);
    const pathData =
      deviationY < 10
        ? `M ${sourcePoint.x} ${sourcePoint.y}
        L ${targetPoint.x} ${targetPoint.y}
      `
        : `
     M ${sourcePoint.x} ${sourcePoint.y}
     L ${midX} ${midY}
     L ${midX} ${targetPoint.y + (targetPoint.y < sourcePoint.y ? 5 : -5)}
     Q ${midX} ${targetPoint.y} ${midX + (targetPoint.x < sourcePoint.x ? -5 : 5)} ${targetPoint.y}
     L ${targetPoint.x} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);
// 折线
Graph.registerConnector(
  "poly-branch-connector",
  function (sourcePoint, targetPoint, routerPoints, options) {
    const halfWidth = this.sourceBBox.width / 2;
    const midX =
      sourcePoint.x +
      (sourcePoint.x < targetPoint.x ? halfWidth + 10 : -halfWidth - 10);
    const midY = sourcePoint.y;
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     L ${midX} ${midY}
     L ${midX} ${targetPoint.y}
     L ${targetPoint.x} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);
Graph.registerConnector(
  "poly-sub-connector",
  function (sourcePoint, targetPoint, routerPoints, options) {
    const midX = sourcePoint.x + (sourcePoint.x < targetPoint.x ? 10 : -10);
    const midY = sourcePoint.y;
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     L ${midX} ${midY}
     L ${midX} ${targetPoint.y}
     L ${targetPoint.x} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);

// 树形
Graph.registerConnector(
  "tree-branch-connector",
  function (sourcePoint, targetPoint, routerPoints, options) {
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     L ${sourcePoint.x} ${sourcePoint.y + 10}
     L ${targetPoint.x} ${sourcePoint.y + 10}
     L ${targetPoint.x} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);
Graph.registerConnector(
  "tree-sub-connector",
  function (sourcePoint, targetPoint, routerPoints, options) {
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     L ${sourcePoint.x} ${targetPoint.y}
     L ${targetPoint.x} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);

// 组织结构
Graph.registerConnector(
  "organization-branch-connector",
  function (sourcePoint, targetPoint, routerPoints, options) {
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     L ${sourcePoint.x} ${sourcePoint.y + 10}
     L ${targetPoint.x} ${sourcePoint.y + 10}
     L ${targetPoint.x} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);
Graph.registerConnector(
  "organization-sub-connector",
  function (sourcePoint, targetPoint, routerPoints, options) {
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     L ${sourcePoint.x} ${sourcePoint.y + 10}
     L ${targetPoint.x} ${sourcePoint.y + 10}
     L ${targetPoint.x} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);

// 括号
Graph.registerConnector(
  "bracket-branch-connector",
  function (sourcePoint, targetPoint, routerPoints, options) {
    const midX = sourcePoint.x + (sourcePoint.x < targetPoint.x ? 20 : -20);
    const midY = sourcePoint.y;
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     Q ${midX} ${midY} ${midX} ${sourcePoint.y + (sourcePoint.y < targetPoint.y ? 20 : -20)}
     L ${midX} ${targetPoint.y + (targetPoint.y < sourcePoint.y ? 20 : targetPoint.y === sourcePoint.y ? 0 : -20)}
     Q ${midX} ${targetPoint.y} ${midX + (targetPoint.x < sourcePoint.x ? -20 : 20)} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);
Graph.registerConnector(
  "bracket-sub-connector",
  function (sourcePoint, targetPoint, routerPoints, options) {
    const midX = sourcePoint.x + (sourcePoint.x < targetPoint.x ? 10 : -10);
    const midY = sourcePoint.y;
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     Q ${midX} ${midY} ${midX} ${sourcePoint.y + (sourcePoint.y < targetPoint.y ? 10 : -10)}
     L ${midX} ${targetPoint.y + (targetPoint.y < sourcePoint.y ? 10 : targetPoint.y === sourcePoint.y ? 0 : -10)}
     Q ${midX} ${targetPoint.y} ${midX + (targetPoint.x < sourcePoint.x ? -10 : 10)} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);

// 一个子项的括号
Graph.registerConnector(
  "bracket-one-branch-connector",
  function (sourcePoint, targetPoint, routerPoints, options, edgeView) {
    const targetCell = edgeView.targetView?.cell;
    let height = 0;
    if (targetCell?.isNode()) {
      height = targetCell.getBBox().height;
    }
    const targetTop = targetPoint.y - height / 2 - 3;
    const targetBottom = targetPoint.y + height / 2 + 3;
    const offset = 10;
    const midX =
      sourcePoint.x + (sourcePoint.x < targetPoint.x ? offset : -offset);
    const midY = sourcePoint.y;
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     Q ${midX} ${midY} ${midX} ${sourcePoint.y - offset}
     L ${midX} ${targetTop + offset}
     Q ${midX} ${targetTop} ${midX + offset} ${targetTop}
     M ${sourcePoint.x} ${sourcePoint.y}
     Q ${midX} ${midY} ${midX} ${sourcePoint.y + offset}
     L ${midX} ${targetBottom - offset}
     Q ${midX} ${targetBottom} ${midX + offset} ${targetBottom}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);
Graph.registerConnector(
  "bracket-one-sub-connector",
  function (sourcePoint, targetPoint, routerPoints, options, edgeView) {
    const targetCell = edgeView.targetView?.cell;
    let height = 0;
    if (targetCell?.isNode()) {
      height = targetCell.getBBox().height;
    }
    const targetTop = targetPoint.y - height / 2 + 3;
    const targetBottom = targetPoint.y + height / 2 - 3;
    const offset = 5;
    const midX =
      sourcePoint.x + (sourcePoint.x < targetPoint.x ? offset : -offset);
    const midY = sourcePoint.y;
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     Q ${midX} ${midY} ${midX} ${sourcePoint.y - offset}
     L ${midX} ${targetTop + offset}
     Q ${midX} ${targetTop} ${midX + offset} ${targetTop}
     M ${sourcePoint.x} ${sourcePoint.y}
     Q ${midX} ${midY} ${midX} ${sourcePoint.y + offset}
     L ${midX} ${targetBottom - offset}
     Q ${midX} ${targetBottom} ${midX + offset} ${targetBottom}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);

// 树形图
Graph.registerConnector(
  "tree-shape-connector",
  function (sourcePoint, targetPoint, routerPoints, options) {
    const pathData = `
     M ${sourcePoint.x} ${sourcePoint.y}
     L ${sourcePoint.x} ${targetPoint.y}
     L ${targetPoint.x} ${targetPoint.y}
    `;
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);

// 右侧鱼骨图
Graph.registerConnector(
  "fishbone-branch-right-connector",
  function (sourcePoint, targetPoint, routerPoints, options, edgeView) {
    const direction = sourcePoint.y > targetPoint.y ? "up" : "down";
    const node = edgeView.targetView?.cell;
    let targetY = targetPoint.y;
    if (node?.isNode() && direction === "down") {
      targetY -= node.size().height;
    }
    const midX = caclculateX(
      { x: targetPoint.x, y: targetY },
      sourcePoint.y,
      "right",
      direction
    );
    let pathData = "";
    if (direction === "up") {
      pathData = `
     M ${targetPoint.x} ${targetPoint.y}
     L ${midX} ${sourcePoint.y}
     L ${sourcePoint.x} ${sourcePoint.y}
    `;
    } else {
      pathData = `
      M ${targetPoint.x} ${targetY}
      L ${midX} ${sourcePoint.y}
      L ${sourcePoint.x} ${sourcePoint.y}
     `;
    }

    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);
Graph.registerConnector(
  "fishbone-sub-right-connector",
  function (sourcePoint, targetPoint, routerPoints, options, edgeView) {
    const sourceNode = edgeView.sourceView?.cell;
    const direction = sourcePoint.y < targetPoint.y ? "up" : "down";
    let midX = caclculateX(sourcePoint, targetPoint.y, "right", direction);
    if (direction === "down" && sourceNode?.isNode()) {
      midX = caclculateX(
        { x: sourcePoint.x, y: sourcePoint.y - sourceNode.size().height },
        targetPoint.y,
        "right",
        direction
      );
    }

    let pathData = "";
    if (sourceNode?.isNode() && sourceNode.data.type === TopicType.sub) {
      const size = sourceNode.size();
      const sourceP = {
        x: sourcePoint.x + size.width / 2,
        y: sourcePoint.y - size.height / 2,
      };
      pathData = `
       M ${sourceP.x} ${sourceP.y}
       L ${sourceP.x + 10} ${sourceP.y}
       L ${sourceP.x + 10} ${targetPoint.y}
       L ${targetPoint.x} ${targetPoint.y}
      `;
    } else {
      pathData = `
        M ${midX} ${targetPoint.y}
        L ${targetPoint.x} ${targetPoint.y}
        `;
    }
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);

// 左侧鱼骨图
Graph.registerConnector(
  "fishbone-branch-left-connector",
  function (sourcePoint, targetPoint, routerPoints, options, edgeView) {
    const direction = sourcePoint.y > targetPoint.y ? "up" : "down";
    const node = edgeView.targetView?.cell;
    let targetY = targetPoint.y;
    if (node?.isNode() && direction === "down") {
      targetY -= node.size().height;
    }
    const midX = caclculateX(
      { x: targetPoint.x, y: targetY },
      sourcePoint.y,
      "left",
      direction
    );
    let pathData = "";
    if (direction === "up") {
      pathData = `
     M ${targetPoint.x} ${targetPoint.y}
     L ${midX} ${sourcePoint.y}
     L ${sourcePoint.x} ${sourcePoint.y}
    `;
    } else {
      pathData = `
      M ${targetPoint.x} ${targetY}
      L ${midX} ${sourcePoint.y}
      L ${sourcePoint.x} ${sourcePoint.y}
     `;
    }

    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);
Graph.registerConnector(
  "fishbone-sub-left-connector",
  function (sourcePoint, targetPoint, routerPoints, options, edgeView) {
    const sourceNode = edgeView.sourceView?.cell;

    let pathData = "";
    // 子主题到子主题
    if (sourceNode?.isNode() && sourceNode.data.type === TopicType.sub) {
      const size = sourceNode.size();
      const sourceP = {
        x: sourcePoint.x - size.width,
        y: sourcePoint.y,
      };
      pathData = `
       M ${sourceP.x} ${sourceP.y}
       L ${sourceP.x - 10} ${sourceP.y}
       L ${sourceP.x - 10} ${targetPoint.y}
       L ${targetPoint.x} ${targetPoint.y}
      `;
    } else {
      // 分支子主题到子主题
      const direction = sourcePoint.y < targetPoint.y ? "up" : "down";
      const size = sourceNode?.isNode()
        ? sourceNode.size()
        : { width: 0, height: 0 };
      let midX = caclculateX(
        {
          x: sourcePoint.x - size.width / 2,
          y: sourcePoint.y + size.height / 2,
        },
        targetPoint.y,
        "left",
        direction
      );
      if (direction === "down") {
        midX = caclculateX(
          {
            x: sourcePoint.x - size.width / 2,
            y: sourcePoint.y - size.height / 2,
          },
          targetPoint.y,
          "left",
          direction
        );
      }
      pathData = `
        M ${midX} ${targetPoint.y}
        L ${targetPoint.x} ${targetPoint.y}
        `;
    }
    return options.raw ? Path.parse(pathData) : pathData;
  },
  true
);
const getConnector = (
  structure: StructureType,
  theme: string,
  type: TopicType,
  options?: Record<string, any>
) => {
  // 树状结构图
  if (structure === StructureType.tree) {
    return `tree-${type}-connector`;
  }
  // 组织结构图
  if (structure === StructureType.organization) {
    return `organization-${type}-connector`;
  }
  // 时间图
  if (
    [
      StructureType.upwardTime,
      StructureType.downwardTime,
      StructureType.horizontalTime,
    ].includes(structure)
  ) {
    return `poly-${type}-connector`;
  }
  // 括号图
  if (
    [StructureType.leftBracket, StructureType.rightBracket].includes(structure)
  ) {
    if (options?.onlyOneChild) {
      return `bracket-one-${type}-connector`;
    }
    return `bracket-${type}-connector`;
  }
  // 树形图
  if (
    [
      StructureType.leftTreeShape,
      StructureType.rightTreeShape,
      StructureType.treeShape,
    ].includes(structure)
  ) {
    return `tree-shape-connector`;
  }
  // 鱼骨
  if (structure === StructureType.leftFishbone) {
    return `fishbone-${type}-left-connector`;
  }
  if (structure === StructureType.rightFishbone) {
    return `fishbone-${type}-right-connector`;
  }
  const themeObj = getTheme(theme);
  if (type === TopicType.branch) {
    return `${themeObj.branchConnector}-${type}-connector`;
  } else {
    return `${themeObj.subConnector}-${type}-connector`;
  }
};

const getSourceAnchor = (
  type: TopicType,
  structure: StructureType,
  options?: Record<string, any>
) => {
  switch (structure) {
    case StructureType.left: {
      return type === TopicType.branch
        ? {
            name: "center",
          }
        : {
            name: "left",
          };
    }
    case StructureType.right: {
      return type === TopicType.branch
        ? {
            name: "center",
          }
        : {
            name: "right",
          };
    }
    case StructureType.leftRight: {
      return type === TopicType.branch
        ? "center"
        : options?.direction === "left"
          ? "left"
          : "right";
    }
    case StructureType.tree: {
      return type === TopicType.branch
        ? {
            name: "bottom",
            args: {
              dy: -5,
            },
          }
        : {
            name: "bottomLeft",
            args: {
              dx: 10,
            },
          };
    }
    case StructureType.organization: {
      return {
        name: "bottom",
      };
    }
    case StructureType.leftBracket: {
      return {
        name: "left",
        args: {
          dx: -10,
        },
      };
    }
    case StructureType.rightBracket: {
      return {
        name: "right",
        args: {
          dx: 10,
        },
      };
    }
    case StructureType.upwardTime:
    case StructureType.downwardTime:
    case StructureType.horizontalTime: {
      return {
        name: "center",
      };
    }
    case StructureType.leftFishbone: {
      return {
        name: type === TopicType.branch ? "left" : "right",
      };
    }
    case StructureType.rightFishbone:
      return {
        name: type === TopicType.branch ? "right" : "bottom",
      };
    case StructureType.leftTreeShape:
    case StructureType.rightTreeShape:
    case StructureType.treeShape: {
      return "bottom";
    }
  }
  return {
    name: "center",
  };
};

const getTargetAnchor = (
  type: TopicType,
  structure: StructureType,
  options?: Record<string, any>
) => {
  switch (structure) {
    case StructureType.left: {
      return {
        name: "right",
      };
    }
    case StructureType.right: {
      return {
        name: "left",
      };
    }
    case StructureType.leftRight: {
      return options?.direction === "left" ? "right" : "left";
    }
    case StructureType.tree: {
      return type === TopicType.branch
        ? {
            name: "top",
          }
        : {
            name: "left",
          };
    }
    case StructureType.organization: {
      return {
        name: "top",
      };
    }
    case StructureType.leftBracket: {
      return {
        name: "right",
        args: {
          dx: 10,
        },
      };
    }
    case StructureType.rightBracket: {
      return {
        name: "left",
        args: {
          dx: 10,
        },
      };
    }
    case StructureType.upwardTime:
    case StructureType.downwardTime:
    case StructureType.horizontalTime: {
      return {
        name: "left",
      };
    }
    case StructureType.leftFishbone: {
      return {
        name: type === TopicType.branch ? "bottom" : "right",
      };
    }
    case StructureType.rightFishbone:
      return {
        name: type === TopicType.branch ? "bottom" : "left",
      };
    case StructureType.leftTreeShape:
    case StructureType.rightTreeShape:
    case StructureType.treeShape: {
      return "left";
    }
  }
  return {
    name: "center",
    args: {
      dx: "25%",
    },
  };
};

/**
 * 创建连线
 * @param graph
 * @param sourceId
 * @param item
 * @param structure
 * @param theme
 * @returns
 */
export const createEdge = (
  graph: Graph,
  sourceId: string,
  item: { id: string; data: TopicItem },
  structure: StructureType,
  theme: string,
  options: Record<string, any> = {}
): Edge => {
  return graph.createEdge({
    id: item.id + "-edge",
    inherit: "edge",
    connector: {
      name: getConnector(structure, theme, item.data.type, options),
    },
    zIndex: 0,
    source: {
      cell: sourceId,
      anchor: getSourceAnchor(item.data.type, structure, options),
    },
    target: {
      cell: item.id,
      anchor: getTargetAnchor(item.data.type, structure, options),
    },
    attrs: {
      line: {
        targetMarker: "",
        stroke: item.data.edge?.color || "#A2B1C3",
        strokeWidth: item.data?.edge?.width || 3,
      },
    },
  });
};
