import { type Ref, inject } from 'vue'
// import {
//   Modal,
//   Message
// } from 'ant-design-vue'

import {
  getSnowflake,
  uuid,
  pointToGrid,
  equals,
  dist2d,
  angle,
  getNearestCoord,
  pointToFootDist,
  pointInSegments,
  filterPointInSegments,
  getSlope,
  collinear3Points,
  intersects,
  lineIntersect
} from './algorithm'

import nodesDefault from './nodesDefault'
import type { INodes } from './INodes'
import * as variables from '../Hooks/variables'

const {
  nodeConfig,
  actives,
  nodeConfigSnapshots,
  nodeConfigSnapshotsIndex
} = variables

// const actives = inject<Ref<string[]>>('actives')! // 节点数据快照
// const nodeConfig = inject<Ref<INodes[]>>('nodeConfig')! // 节点数据快照
// const nodeConfigSnapshots = inject<Ref<INodes[][]>>('nodeConfigSnapshots')! // 节点数据快照
// const nodeConfigSnapshotsIndex = inject<Ref<number>>('nodeConfigSnapshotsIndex')! // 当前快照索引

export {
  getSnowflake,
  uuid,
  pointToGrid,
  dist2d,
  angle,
  getNearestCoord,
  pointToFootDist,
  pointInSegments,
  filterPointInSegments,
  getSlope,
  collinear3Points,
  intersects,
  lineIntersect
} from './algorithm' // 默认节点属性对象

/**
 * 创建新节点
 * @author 谁改填谁
 * @param {Object} anonymous node节点对象属性
 * @returns {Object} node节点对象
 */
export function createNode({
  id = getSnowflake(), // 节点唯一标识id
  nodeType = '0',
  nodeCode = uuid(), // 用户可编辑节点code
  nodeName = '流程开始', // 节点名称
  inputNodeCode = [],
  outputNodeCode = [],
  from = [], // 输入节点id
  to = [], // 输出节点id
  paths = [],
  isParallel = '0',
  position = {
    x: 300,
    y: 20
  },
  size = {
    width: 40,
    height: 40
  }
} = {}, params = {}) {
  return {
    'id': id,
    'nodeCode': nodeCode,
    'nodeType': nodeType,
    'nodeName': nodeName,
    'inputNodeCode': [], // '123123,321312321'
    'outputNodeCode': [], // '123,321'
    'userTypeParams': '', // 审批类型参数，此处拓展可自定义参数，由流程推给业务，业务返回审批人员
    'userTypeSelectIds': '', // 审批选择ids，逗号分隔 1标签/角色(id)，2部门(id), 3协同部门(id), 4指定审核人(id;user_name)，逗号分隔
    'conditionParams': '', // 条件参数，js表达式方式 ex:$price$ > 21
    'userType': '1', // 1角色 2部门 3协同部门 4指定审核人
    'signType': '2', // 1会签 2或签
    'callbackFlag': '0', // 节点是否存在监听（也就是回调）0否1是，默认0
    'isSubProcess': '0', // 是否关联子流程（0否，1是）默认0
    'isParallel': isParallel, // 是否在并行审批节点中（0否，1是）默认0  非用户操作，必传（需要前端判断当前节点是否属于并行网关子节点）
    'isPostParent': '0', // 是否直属上级
    'approveTimeLimitType': '1', // 审批时限类型（1小时，2天）默认1
    'approveTimeLimit': 0, // 审批时限值
    'applicationId': '', // 对应业务系统ID(应用ID)（不必填）
    'applicationTodoUrl': '', // 业务系统的待办地址（不必填）
    'authConfig': null,
    'nodeButtonConfig': null, // 按钮
    'nodeMonitorConfig': [], // 节点监听
    'nodeSubprocessesConfig': [], // 子流程
    'nodePath': {
      from: from, // 输入节点id数组
      to: to, // 输出节点id数组
      position: position,
      size: size,
      /**
       * 开始节点, 结束节点 nodePath
       * demo 实际数据自己修改
       */
      // paths: createPath({
      //   position: {x: 292, y: 20},
      //   size: {width: 32, height: 32}
      // }, {
      //   position: {x: 360, y: 20},
      //   size: {width: 32, height: 32}
      // })
      paths: paths
    },
    ...params
  }
}

/**
 * 获取节点基础属性
 * @param {Object} node
 * @returns {Object} x,y,width,height,top,bottom,left,right
 */
export function getNodeBasic(node) {
  const { x, y } = node.nodePath.position
  const width = node.nodePath.size.width
  const height = node.nodePath.size.height
  return {
    x,
    y,
    width,
    height,
    top: y - height / 2,
    bottom: y + height / 2,
    left: x - width / 2,
    right: x + width / 2
  }
}

/**
 * 创建2个节点之间的连线
 * @author sunidea
 * @param {Object} node1 开始节点
 * @param {Object} node2 结束节点
 * @param {Array} p1 开始节点的计算坐标（非必传，默认position x,y）
 * @param {Array} p2 结束节点的计算坐标（非必传，默认position x,y）
 * @returns {Object} path
 */
export function createPath(node1, node2, p1?, p2?) {
  const space = 20
  let points: number[][] = []
  const { x: x1, y: y1, width: width1, height: height1, top: top1, bottom: bottom1, left: left1, right: right1 } = getNodeBasic(node1)
  const { x: x2, y: y2, width: width2, height: height2, top: top2, bottom: bottom2, left: left2, right: right2 } = getNodeBasic(node2)
  if (!p1) p1 = [x1, y1]
  if (!p2) p2 = [x2, y2]
  points = createPathZ(node1, node2, p1, p2) // 生成Z形连接线
  if (!points.length) {
    // 生成L形连线
    points = createPathL(node1, node2, p1, p2)
    if (!points.length) {
      // 生成U形连线
      points = createPathU(node1, node2, p1, p2)
      // 默认直接连线
      // points = [[x1, y1], [x2, y2]]
    }
  }
  // 返回path对象
  return {
    id: getSnowflake(), // 节点唯一标识id
    from: {
      originX: p1[0],
      originY: p1[1],
      id: node1.id
    },
    to: {
      originX: p2[0],
      originY: p2[1],
      id: node2.id
    },
    type: 1,
    points: points.map(item => pointToGrid(item))
  }
}

/**
 * 创建2个节点之间的Z形连线
 * @author sunidea
 * @param {Object} node1 开始节点
 * @param {Object} node2 结束节点
 * @param {Array} p1 开始节点的计算坐标（非必传，默认position x,y）
 * @param {Array} p2 结束节点的计算坐标（非必传，默认position x,y）
 * @returns {Array} points
 */
export function createPathZ(node1, node2, p1, p2) {
  const space = 40
  const { x: x1, y: y1, width: width1, height: height1, top: top1, bottom: bottom1, left: left1, right: right1 } = getNodeBasic(node1)
  const { x: x2, y: y2, width: width2, height: height2, top: top2, bottom: bottom2, left: left2, right: right2 } = getNodeBasic(node2)
  if (!p1) p1 = [x1, y1]
  if (!p2) p2 = [x2, y2]
  const center = {
    x: x2 - (x2 - x1) / 2,
    y: y2 - (y2 - y1) / 2
  }
  let dx1 = 0
  let dy1 = 0
  let dx2 = 0
  let dy2 = 0
  const bend2 = [0, 0]
  const bend3 = [0, 0]
  if (top2 - bottom1 >= space) {
    console.log('node1在上')
    // node1在上
    center.y = top2 + (bottom1 - top2) / 2
    dx1 = p1[0]
    dy1 = bottom1
    dx2 = p2[0]
    dy2 = top2
    bend2[0] = dx1
    bend2[1] = center.y
    bend3[0] = dx2
    bend3[1] = center.y
    return [[dx1, dy1], [bend2[0], bend2[1]], [bend3[0], bend3[1]], [dx2, dy2]]
  } else if (top1 - bottom2 >= space) {
    console.log('node1在下')
    // node1在下
    center.y = top1 + (bottom2 - top1) / 2
    dx1 = p1[0]
    dy1 = top1
    dx2 = p2[0]
    dy2 = bottom2
    bend2[0] = dx1
    bend2[1] = center.y
    bend3[0] = dx2
    bend3[1] = center.y
    return [[dx1, dy1], [(bend2[0]), bend2[1]], [bend3[0], bend3[1]], [dx2, dy2]]
  } else if (left2 - right1 >= space) {
    console.log('node1在左')
    // node1在左
    center.x = right1 + (left2 - right1) / 2
    dx1 = right1
    dy1 = p1[1]
    dx2 = left2
    dy2 = p2[1]
    bend2[0] = center.x
    bend2[1] = dy1
    bend3[0] = center.x
    bend3[1] = dy2
    return [[dx1, dy1], [bend2[0], bend2[1]], [bend3[0], bend3[1]], [dx2, dy2]]
  } else if (left1 - right2 >= space) {
    console.log('node1在右')
    // node1在右
    center.x = right2 + (left1 - right2) / 2
    dx1 = left1
    dy1 = p1[1]
    dx2 = right2
    dy2 = p2[1]
    bend2[0] = center.x
    bend2[1] = dy1
    bend3[0] = center.x
    bend3[1] = dy2
    return [[dx1, dy1], [bend2[0], bend2[1]], [bend3[0], bend3[1]], [dx2, dy2]]
  }
  return []
}

/**
 * 创建2个节点之间的L形连线
 * @author sunidea
 * @param {Object} node1 开始节点
 * @param {Object} node2 结束节点
 * @param {Array} p1 开始节点的计算坐标（非必传，默认position x,y）
 * @param {Array} p2 结束节点的计算坐标（非必传，默认position x,y）
 * @returns {Array} points
 */
export function createPathL(node1, node2, p1, p2) {
  const space = 40
  const { x: x1, y: y1, width: width1, height: height1, top: top1, bottom: bottom1, left: left1, right: right1 } = getNodeBasic(node1)
  const { x: x2, y: y2, width: width2, height: height2, top: top2, bottom: bottom2, left: left2, right: right2 } = getNodeBasic(node2)
  if (!p1) p1 = [x1, y1]
  if (!p2) p2 = [x2, y2]
  // space = 40
  const bend1 = [p2[0], p1[1]]
  const bend2 = [p1[0], p2[1]]
  if (!inRect(bend1, node1) && !inRect(bend1, node2)) {
    console.log('生成L形连线 拐点不在节点内')
    const point1 = getNearestIntersectPoint([p1[0], p1[1]], bend1, node1)
    const point2 = getNearestIntersectPoint([p2[0], p2[1]], bend1, node2)
    return [[point1[0], point1[1]], [bend1[0], bend1[1]], [point2[0], point2[1]]]
  } else if (!inRect(bend2, node1) && !inRect(bend2, node2)) {
    console.log('生成L形连线 拐点不在节点内')
    const point1 = getNearestIntersectPoint([p1[0], p1[1]], bend2, node1)
    const point2 = getNearestIntersectPoint([p2[0], p2[1]], bend2, node2)
    return [[point1[0], point1[1]], [bend2[0], bend2[1]], [point2[0], point2[1]]]
  }
  return []
}

/**
 * 创建2个节点之间的U形连线
 * @author sunidea
 * @param {Object} node1 开始节点
 * @param {Object} node2 结束节点
 * @param {Array} p1 开始节点的计算坐标（非必传，默认position x,y）
 * @param {Array} p2 结束节点的计算坐标（非必传，默认position x,y）
 * @returns {Array} points
 */
export function createPathU(node1: INodes, node2: INodes, p1: number[], p2: number[]) {
  const space = 40
  const { x: x1, y: y1, width: width1, height: height1, top: top1, bottom: bottom1, left: left1, right: right1 } = getNodeBasic(node1)
  const { x: x2, y: y2, width: width2, height: height2, top: top2, bottom: bottom2, left: left2, right: right2 } = getNodeBasic(node2)
  if (!p1) p1 = [x1, y1]
  if (!p2) p2 = [x2, y2]
  const diffX = Math.abs(x2 - x1)
  const diffY = Math.abs(y2 - y1)
  const bend1: number[] = []
  const bend2: number[] = []
  // space = 40
  if (diffX > diffY) {
    console.log('生成4点冂形连线', diffX, diffY, diffX > diffY)
    bend1[0] = p1[0]
    bend1[1] = Math.min(top1 - space, top2 - space)
    bend2[0] = p2[0]
    bend2[1] = Math.min(top1 - space, top2 - space)
    return [[p1[0], top1], [bend1[0], bend1[1]], [bend2[0], bend2[1]], [p2[0], top2]]
  }
  console.log('生成4点冂形连线', diffX > diffY, p1[0] - space)
  bend1[0] = Math.min(left1 - space, left2 - space)
  bend1[1] = p1[1]
  bend2[0] = Math.min(left1 - space, left2 - space)
  bend2[1] = p2[1]
  return [[left1, p1[1]], [bend1[0], bend1[1]], [bend2[0], bend2[1]], [left2, p2[1]]]
}


/**
 * 新增节点后创建连线
 * @param {Object} node1 上一节点数据
 * @param {Object} node2 下一节点数据
 * @returns {Object} 连线数据
 */
export function addNodeCreateLine(node1: INodes, node2: INodes) {
  const { x: x1 } = node1.nodePath.position
  const { x: x2 } = node2.nodePath.position
  let { y: y1 } = node1.nodePath.position
  let { y: y2 } = node2.nodePath.position
  y1 = y1 + node1.nodePath.size.height / 2
  y2 = y2 - node2.nodePath.size.height / 2
  const center = {
    x: x2 - (x2 - x1) / 2,
    y: y2 - (y2 - y1) / 2
  }
  const obj = {
    type: 1,
    id: getSnowflake(),
    // from: node1.id,
    to: node2.id,
    points: [
      [
        pointToGrid(x1),
        pointToGrid(y1)
      ],
      [
        pointToGrid(x1),
        pointToGrid(center.y)
      ],
      [
        pointToGrid(x2),
        pointToGrid(center.y)
      ],
      [
        pointToGrid(x2),
        pointToGrid(y2)
      ]
    ]
  }
  return obj
}


/**
 * 根据节点id 获取 上级节点 当前节点 下级节点
 * @param {Array<INodes>} nodeConfig
 * @param {string|number} id
 * @returns {last: Array<INodes>; current: INodes | undefined; next: Array<INodes>}
 */
export function getLastCurrentNextNodeById(nodeConfig: INodes[], id: string) {
  const nodeObj = {
    last: [] as INodes[],
    current: undefined as INodes | undefined,
    next: [] as INodes[]
  }
  // 容错 如果没有节点
  if (!nodeConfig || !nodeConfig.length) return nodeObj
  // 获取当前节点
  nodeObj.current = nodeConfig.find(item => item.id === id)

  // 开始节点没有上级节点
  if (nodeObj.current?.nodeType === '1') {
    nodeObj.last = []

    if (nodeObj.current.nodePath.to.length > 0) {
      nodeObj.next = nodeConfig.filter(item => item.nodePath.from.filter(x => x === id).length > 0)
    }

    if (nodeObj.current.nodePath.to.length === 0) {
      nodeObj.next = []
    }
  } else {
    // 结束节点没有下级节点
    if (nodeObj.current?.nodeType === '2') {
      nodeObj.next = []

      if (nodeObj.current.nodePath.from.length > 0) {
        nodeObj.last = nodeConfig.filter(item => item.nodePath.to.filter(x => x === id).length > 0)
      }
      if (nodeObj.current.nodePath.from.length === 0) {
        nodeObj.last = []
      }
    } else {
      if (nodeObj.current?.nodePath.to?.length) {
        nodeObj.next = nodeConfig.filter(item => item.nodePath.from.filter(x => x === id).length > 0)
      }

      if (nodeObj.current?.nodePath.from.length) {
        nodeObj.last = nodeConfig.filter(item => item.nodePath.to.filter(x => x === id).length > 0)
      }
      if (nodeObj.current?.nodePath.from.length === 0) {
        nodeObj.last = []
      }
      if (nodeObj.current?.nodePath.to.length === 0) {
        nodeObj.next = []
      }


      return nodeObj
    }
  }

  return nodeObj
}

/**
 * 修改 选中节点的nodeCode 以及修改 上级节点的 outputNodeCode 和 下级节点的 inputNodeCode
 * @param {Array} nodeConfig 原数组
 * @param {String} activeId 当前节点id
 * @param {String} newNodeCode 修改的nodeCode
 */
export function updataNodeCode(nodeConfig, activeId, newNodeCode) {
  const oldNode = nodeConfig.find(item => item.id === activeId)
  const oldNodeCode = JSON.parse(JSON.stringify(oldNode.nodeCode))

  nodeConfig.forEach((item, index) => {
    const inputIndex = item.inputNodeCode.indexOf(oldNodeCode)
    const outIndex = item.outputNodeCode.indexOf(oldNodeCode)
    if (inputIndex > -1) {
      item.inputNodeCode.splice(inputIndex, 1, newNodeCode)
    } else if (outIndex > -1) {
      item.outputNodeCode.splice(outIndex, 1, newNodeCode)
    }
  })
  oldNode.nodeCode = newNodeCode
}
/**
 * 拖拽节点
 * 将虚拟节点x,y回写到nocdConfig
 * @param {Array} nodeConfig 所有节点
 * @param {Array} dragNodes 拖拽中的节点
 * @returns {Object} {left,top}
 */
// export function onDropPoint (nodeConfig, dragPoint) {
//   for (const dragNode of dragNodes) {
//     const node = nodeConfig.find(node => node.id === dragNode.id)
//     node.nodePath.position.x = dragNode.nodePath.position.x
//     node.nodePath.position.y = dragNode.nodePath.position.y
//   }
// }

/**
 * 拖拽节点
 * 将虚拟节点x,y回写到nocdConfig
 * @param {Array} nodeConfig 所有节点
 * @param {Array} dragNodes 拖拽中的节点
 * @returns {Object} {left,top}
 */
export function onDropNodes(nodeConfig, dragNodes) {
  for (const dragNode of dragNodes) {
    const node = nodeConfig.find(node => node.id === dragNode.id)
    node.nodePath.position.x = dragNode.nodePath.position.x
    node.nodePath.position.y = dragNode.nodePath.position.y
  }
}

/**
 * 重新设置线
 * 将虚拟节点x,y回写到nocdConfig
 * @param {Array} nodeConfig 所有节点
 * @param {Array} dragNodes 拖拽中的节点
 * @returns {Object} {left,top}
 */
export function resetDropNodesPolyline(nodeConfig, dragNodes) {
  for (const dragNode of dragNodes) {
    const diffX = dragNode.nodePath.position.x - dragNode.nodePath.position.lastX
    const diffY = dragNode.nodePath.position.y - dragNode.nodePath.position.lastY
    // from找到当前节点所有父级
    const fromNodes = nodeConfig.filter(item => dragNode.nodePath.from.includes(item.id))
    fromNodes.forEach(fromNode => {
      // 引用上一节点连线
      const path = fromNode.nodePath.paths.find(path => path.to.id === dragNode.id)
      path.to.originX += diffX
      path.to.originY += diffY
      // 修改连线末点，计算偏移值
      // const point = path.points[path.points.length - 1]
      const diff = [diffX, diffY]
      resetPolylineFirstLast('to', path, fromNode, dragNode, diff)
      filterPointInSegments(path.points)
    })
    // to修改连线首点，计算偏移值
    dragNode.nodePath.paths.forEach(path => {
      // 引用nodeConfig节点对象
      const fromNode = nodeConfig.find(item => item.id === dragNode.id)
      const toNode = nodeConfig.find(item => item.id === path.to.id)
      // 引用连线
      const fromPath = fromNode.nodePath.paths.find(path => path.to.id === toNode.id)
      fromPath.from.originX += diffX
      fromPath.from.originY += diffY
      // const point = path.points[0]
      const diff = [diffX, diffY]
      resetPolylineFirstLast('from', fromPath, fromNode, toNode, diff)
      filterPointInSegments(fromPath.points)
    })
  }
}

/**
 * 计算连线首尾，垂直/水平
 * @param {String} type 计算方向 from首 to尾
 * @param {Array} path nodePath.path[n]
 * @param {Object} from 起始节点
 * @param {Object} to 结束节点
 * @param {Array} diff [100, 100]
 */
export function resetPolylineFirstLast(type, path, from, to, diff) {
  const points = path.points
  const { x: x1, y: y1, width: width1, height: height1, top: top1, bottom: bottom1, left: left1, right: right1 } = getNodeBasic(from)
  const { x: x2, y: y2, width: width2, height: height2, top: top2, bottom: bottom2, left: left2, right: right2 } = getNodeBasic(to)
  // 重算连线
  const resetPath = () => {
    const pathTemp = createPath(from, to, [path.from.originX, path.from.originY], [path.to.originX, path.to.originY])
    points.splice(0, points.length, ...pathTemp.points)
  }
  // 判断是否水平或垂直临界2个点
  if (type === 'from') {
    const len = points.length
    const p0 = JSON.parse(JSON.stringify(points[0]))
    filterInRectFrom(type, path, from, to, diff)
    // 斜线 前2点是否斜线
    if (points.length > 1 && points[0][0] !== points[1][0] && points[0][1] !== points[1][1]) {
      // 第一个点相同坐标
      console.log(p0, points[0])
      if (equals(p0, points[0])) {
        console.log('第一个点相同坐标')
        const intersectPoint = getNearestIntersectPoint(points[1], [path.from.originX, path.from.originY], from)
        points.splice(0, 1, pointToGrid(intersectPoint))
      } else {
        // 从其它点开始,说明已过滤原起始点
        // if (inRectAdsorb(points[0], from)) {
        points.splice(0, 1)
        // }
        // 只剩2个点，1条线，重画
        if (points.length <= 1) {
          resetPath()
          return
        }
        console.log('从其它点开始', points[0], [path.from.originX, path.from.originY])
        const intersectPoint = getNearestIntersectPoint(points[0], [path.from.originX, path.from.originY], from)
        points.splice(0, 0, pointToGrid(intersectPoint))
      }
    }
    if (points.length <= 1 || len < 3 && points.length <= 2) {
      console.log('重算连线', points.length)
      resetPath()
      return
    }
    if (points[0][0] === points[1][0]) {
      // x相等
      console.log('x相等', points.length)
      points[1].splice(0, 1, path.from.originX)
      // 第2个点是否在from节点的投影内
      if (points[1][1] >= top1 - 10 && points[1][1] <= bottom1 + 10) {
        if (points[2] && isVertical(points[1], points[2])) {
          points[2].splice(1, 1, path.from.originY)
        }
        points[1].splice(1, 1, path.from.originY)
      }
      const p2 = !inRectAdsorb(points[1], from) ? points[1] : (points[2] || points[1])
      console.log('y相等 p2', p2)
      const intersectPoint = getNearestIntersectPoint(p2, [path.from.originX, path.from.originY], from)
      console.log('y相等 intersectPoint', intersectPoint)
      points.splice(0, 1, intersectPoint)
      // 是否x都相同
      if (points.reduce((a, b) => a[0] === b[0] ? a : false)) {
        resetPath()
        return
      }
      // 是否L形只有1个拐点
      if (points.length === 3) {
        // 节点-拐点 或 拐点-终点 与节点相交
        if (inRect(points[1], to)) {
          resetPath()
          return
        }
        const bend2IntersectPoint = getNearestIntersectPoint(points[2], points[1], to)
        // 拐点-终点与节点相交
        if (bend2IntersectPoint.length) {
          points.splice(2, 1, bend2IntersectPoint)
        }
      }
    } else if (points[0][1] === points[1][1]) {
      // y相等
      console.log('y相等', points.length)
      points[1].splice(1, 1, path.from.originY)
      // 第2个点是否在from节点的投影内
      if (points[1][0] >= left1 - 10 && points[1][0] <= right1 + 10) {
        if (points[2] && isVertical(points[1], points[2])) {
          points[2].splice(0, 1, path.from.originX)
        }
        points[1].splice(0, 1, path.from.originX)
      }
      const p2 = !inRectAdsorb(points[1], from) ? points[1] : (points[2] || points[1])
      console.log('y相等 p2', p2)
      const intersectPoint = getNearestIntersectPoint(p2, [path.from.originX, path.from.originY], from)
      console.log('y相等 intersectPoint', intersectPoint)
      points.splice(0, 1, intersectPoint)
      // 是否y都相同
      if (points.reduce((a, b) => a[1] === b[1] ? a : false)) {
        resetPath()
        return
      }
      // 是否L形只有1个拐点
      if (points.length === 3) {
        // 拐点 在节点内(包括边框)
        if (inRect(points[1], to)) {
          resetPath()
          return
        }
        const bend2IntersectPoint = getNearestIntersectPoint(points[2], points[1], to)
        // 拐点-终点与节点相交
        if (bend2IntersectPoint.length) {
          points.splice(2, 1, bend2IntersectPoint)
        }
      }
    }
  } else if (type === 'to') {
    const len = points.length
    const p0 = JSON.parse(JSON.stringify(points[points.length - 1]))
    filterInRectTo(type, path, from, to, diff)
    // 斜线 前2点是否斜线
    if (points.length > 1 && points[points.length - 1][0] !== points[points.length - 2][0] && points[points.length - 1][1] !== points[points.length - 2][1]) {
      // 第一个点相同坐标
      if (equals(p0, points[points.length - 1])) {
        console.log('第一个点相同坐标')
        const intersectPoint = getNearestIntersectPoint(points[points.length - 2], [path.to.originX, path.to.originY], to)
        points.splice(-1, 1, pointToGrid(intersectPoint))
      } else {
        // 从其它点开始,说明已过滤原起始点
        // if (inRectAdsorb(points[0], from)) {
        points.splice(-1, 1)
        // }
        // 只剩2个点，1条线，重画
        if (points.length <= 1) {
          resetPath()
          return
        }
        console.log('从其它点开始', points[points.length - 1], [path.to.originX, path.to.originY])
        const intersectPoint = getNearestIntersectPoint(points[points.length - 1], [path.to.originX, path.to.originY], to)
        points.push(pointToGrid(intersectPoint))
      }
    }
    if (points.length <= 1 || len < 3 && points.length <= 2) {
      console.log('重算连线', points.length)
      resetPath()
      return
    }
    if (points[points.length - 1][0] === points[points.length - 2][0]) {
      // x相等
      console.log('x相等', points.length)
      points[points.length - 2].splice(0, 1, path.to.originX)
      // 第2个点是否在to节点的投影内
      if (points[points.length - 2][1] >= top2 - 10 && points[points.length - 2][1] <= bottom2 + 10) {
        if (points[points.length - 3] && isVertical(points[points.length - 2], points[points.length - 3])) {
          points[points.length - 3].splice(1, 1, path.to.originY)
        }
        points[points.length - 2].splice(1, 1, path.to.originY)
      }
      const p2 = !inRectAdsorb(points[points.length - 2], to) ? points[points.length - 2] : (points[points.length - 3] || points[points.length - 2])
      console.log('y相等 p2', p2)
      const intersectPoint = getNearestIntersectPoint(p2, [path.to.originX, path.to.originY], to)
      console.log('y相等 intersectPoint', intersectPoint)
      points.splice(points.length - 1, 1, intersectPoint)
      // 是否x都相同
      if (points.reduce((a, b) => a[0] === b[0] ? a : false)) {
        resetPath()
        return
      }
      // 是否L形只有1个拐点
      if (points.length === 3) {
        // 节点-拐点 或 拐点-终点 与节点相交
        if (inRect(points[points.length - 2], from)) {
          resetPath()
          return
        }
        const bend2IntersectPoint = getNearestIntersectPoint(points[points.length - 3], points[points.length - 2], from)
        // 拐点-终点与节点相交
        if (bend2IntersectPoint.length) {
          points.splice(points.length - 3, 1, bend2IntersectPoint)
        }
      }
    } else if (points[points.length - 1][1] === points[points.length - 2][1]) {
      // y相等
      console.log('y相等', points.length)
      points[points.length - 2].splice(1, 1, path.to.originY)
      // 第2个点是否在to节点的投影内
      if (points[points.length - 2][0] >= left2 - 10 && points[points.length - 2][0] <= right2 + 10) {
        if (points[points.length - 3] && isVertical(points[points.length - 2], points[points.length - 3])) {
          points[points.length - 3].splice(0, 1, path.to.originX)
        }
        points[points.length - 2].splice(0, 1, path.to.originX)
      }
      const p2 = !inRectAdsorb(points[points.length - 2], to) ? points[points.length - 2] : (points[points.length - 3] || points[points.length - 2])
      console.log('y相等 p2', p2)
      const intersectPoint = getNearestIntersectPoint(p2, [path.to.originX, path.to.originY], to)
      console.log('y相等 intersectPoint', intersectPoint)
      points.splice(points.length - 1, 1, intersectPoint)
      // 是否y都相同
      if (points.reduce((a, b) => a[1] === b[1] ? a : false)) {
        resetPath()
        return
      }
      // 是否L形只有1个拐点
      if (points.length === 3) {
        // 拐点 在节点内(包括边框)
        if (inRect(points[points.length - 2], from)) {
          resetPath()
          return
        }
        const bend2IntersectPoint = getNearestIntersectPoint(points[points.length - 3], points[points.length - 2], from)
        // 拐点-终点与节点相交
        if (bend2IntersectPoint.length) {
          points.splice(points.length - 3, 1, bend2IntersectPoint)
        }
      }
    }
  }
  filterPointInSegments(points)
  if (points.length <= 2) resetPath()
}

export function filterInRectFrom(type, path, from, to, diff) {
  const points = path.points
  for (let i = points.length - 1; i >= 0; i--) {
    const point = points[i]
    if (inRectAdsorb(point, from)) {
      // 删除与node重合的point
      points.splice(0, i)
      break
    }
    if (points[i - 1]) {
      const intersectPoint = getNearestIntersectPoint(point, points[i - 1], from)
      if (intersectPoint.length) {
        points.splice(0, i - 1)
        break
      }
    }
  }
  console.log('过滤from', JSON.stringify(points))
}
export function filterInRectTo(type, path, from, to, diff) {
  const points = path.points
  const len = points.length
  for (let i = 0; i < points.length; i++) {
    const point = points[i]
    if (insideRect(point, to)) {
      // console.log('找到to i', i, point)
      // 记录前2个点
      points.splice(i + 1, len)
      break
    }
    if (points[i + 1]) {
      const intersectPoint = getNearestIntersectPoint(point, points[i + 1], to)
      if (intersectPoint.length) {
        // console.log('过滤to i', i, len)
        points.splice(i + 2, len)
        break
      }
    }
  }
  console.log('过滤to', JSON.stringify(points))
}

/**
 * 判断点是否在矩形内
 * @param {Array} point [100,100]
 * @param {Object} node
 * @returns {Boolean}
 */
export function inRect(point, node) {
  const { 0: x, 1: y } = point
  const { position, size } = node.nodePath
  let { x: x1, y: y1 } = position
  x1 = x1 - size.width / 2
  y1 = y1 - size.height / 2
  const x2 = x1 + node.nodePath.size.width
  const y2 = y1 + node.nodePath.size.height
  return x >= x1 && x <= x2 && y >= y1 && y <= y2
}
// 不包含边框
export function insideRect(point, node) {
  const { 0: x, 1: y } = point
  const { position, size } = node.nodePath
  let { x: x1, y: y1 } = position
  x1 = x1 - size.width / 2
  y1 = y1 - size.height / 2
  const x2 = x1 + node.nodePath.size.width
  const y2 = y1 + node.nodePath.size.height
  return x > x1 && x < x2 && y > y1 && y < y2
}
// 增加额外吸附距离
export function inRectAdsorb(point, node) {
  const adsorb = 10 * 2
  const { 0: x, 1: y } = point
  const { position, size } = node.nodePath
  let { x: x1, y: y1 } = position
  const halfWidth = (size.width + adsorb) / 2
  const halfHeight = (size.height + adsorb) / 2
  const x2 = x1 + halfWidth
  const y2 = y1 + halfHeight
  x1 = x1 - halfWidth
  y1 = y1 - halfHeight
  return x >= x1 && x <= x2 && y >= y1 && y <= y2
}

// 2个点是否在水平线或垂直线上
export function isVertical(p1, p2) {
  const { 0: x1, 1: y1 } = p1
  const { 0: x2, 1: y2 } = p2
  return x1 === x2 || y1 === y2
}

// 拖拽节点线动
export const moveNodeAndLine = (lastNode: INodes[], currentNode: INodes, nextNode: INodes[]) => { // 重新画线拖动时和抬起时set
  const pathArr = [] as {
    type: number
    id: string
    to: string
    points: any[][]
  }[]
  for (let i = 0; i < lastNode.length; i++) {
    const topObj = addNodeCreateLine(lastNode[i], currentNode)
    pathArr.push(topObj)
  }
  for (let j = 0; j < nextNode.length; j++) {
    const bottomObj = addNodeCreateLine(currentNode, nextNode[j])
    pathArr.push(bottomObj)
  }
  return pathArr
}

/**
 * 获取线与线相交最近的点，返回点坐标
 * @param {Array} currentPoint 鼠标经过画布的坐标
 * @param {Array|String} nearPoint 如果是起始点，则传下一点，如果是结束点，反之
 * @param {Object} mouseoverNode 拖拽点过程中，经过的节点对象
 * @returns {Object} 点坐标 {x:100,y:100}
 */
export function getNearestIntersectPoint(currentPoint, nearPoint, mouseoverNode) {
  const { size } = nodesDefault[mouseoverNode.nodeType]
  const { x: posX, y: posY } = mouseoverNode.nodePath.position
  const p1 = [posX - size.width / 2, posY - size.height / 2]
  const p2 = [posX + size.width / 2, posY - size.height / 2]
  const p3 = [posX + size.width / 2, posY + size.height / 2]
  const p4 = [posX - size.width / 2, posY + size.height / 2]
  const segmentPoints = [p1, p2, p3, p4, JSON.parse(JSON.stringify(p1))]
  const intersect = lineIntersect([JSON.parse(JSON.stringify(nearPoint)), JSON.parse(JSON.stringify(currentPoint))], segmentPoints)
  // console.log('intersect', intersect)
  let dist
  let intersectPoint: number[] = []
  for (const i in intersect) {
    const coords = intersect[i].coords
    const distCoords = dist2d(JSON.parse(JSON.stringify(nearPoint)), coords)
    if (!dist) {
      dist = distCoords
      intersectPoint = coords
    }
    if (distCoords < dist) {
      dist = distCoords
      intersectPoint = coords
    }
  }
  // console.log('获取线与线相交最近的点，返回点坐标', intersectPoint)
  return intersectPoint
}

/**
 * 删除线和修改父子节点数据
 * @param {*} nodeConfig
 * @param {*} lineId
 */
export function deleteLineUpdateData(nodeConfig, lineId) {
  // 获取当前线属于的节点
  const node = nodeConfig.find(item => item.nodePath.paths.filter(lineItem => lineItem.id === lineId))
  const nodeIndex = nodeConfig.findIndex(item => item.nodePath.paths.filter(lineItem => lineItem.id === lineId))
  // 获取当前线是该节点的第index条线
  const lineIndex = node.nodePath.paths.findIndex(item => item.id === lineId)
  // 第index条线，就说明 应该从该节点的to，outputNodeCode中删除第index项   子节点from,intputNodeCode中删除第index项

  const childId = node.nodePath.to[lineIndex]
  const childIndex = nodeConfig.find(item => item.id === childId)

  nodeConfig[childIndex].nodePath.from.splice(lineIndex, 1)
  nodeConfig[childIndex].intputNodeCode.splice(lineIndex, 1)

  nodeConfig[nodeIndex].nodePath.to.splice(lineIndex, 1)
  nodeConfig[nodeIndex].outputNodeCode.splice(lineIndex, 1)
  nodeConfig[nodeIndex].nodePath.paths.splice(lineIndex, 1)
}

/**
 * actives多选，选中状态处理
 * 主要用在组合按键，Shift+鼠标点击
 * @param {Array} actives actives原型数组
 * @param {String} id 点击节点id
 */
export function checkActives(actives, id) {
  const index = actives.indexOf(id)
  if (index > -1) {
    actives.splice(index, 1)
  } else {
    actives.push(id)
  }
}

/**
 * 计算画布中坐标
 * @param {Number} pageX e.pageX
 * @param {Number} pageY e.pageX
 * @param {Number} oldPageX mousedown的pageX
 * @param {Number} oldPageY mousedown的pageY
 * @param {Number} x 画布的水平偏移
 * @param {Number} y 画布的垂直偏移
 * @param {Number} oldX mousedown的this.x
 * @param {Number} oldY mousedown的this.y
 * @param {Number} scale this.scale
 * @param {Number} oldScale mousedown时的this.scale
 * @param {Number} diffX 补x
 * @param {Number} diffY 补y
 */
export function getMovingPoint({
  pageX = 0,
  pageY = 0,
  oldPageX = 0,
  oldPageY = 0,
  x = 0,
  y = 0,
  oldX = 0,
  oldY = 0,
  scale = 1,
  oldScale = 1,
  diffX = 0,
  diffY = 0
} = {}) {
  return [
    pointToGrid((pageX - oldPageX - (x - oldX)) / scale + diffX),
    pointToGrid((pageY - oldPageY - (y - oldY)) / scale + diffY)
  ]
}

/**
 * 计算默认节点在画布中的中心坐标
 * @param {Array} nodeConfig
 * @param {Number} x
 * @param {Number} y
 * @returns {Object} {x,y}
 */
export function getCenterCoords(nodeConfig, svgWrap, x, y) {
  if (x !== 0) {
    x = 0
  }
  if (y !== 0) {
    y = 0
  }
  const startNodesX = nodeConfig.find(item => item.nodeType === '1').nodePath.position.x
  const startNodesY = nodeConfig.find(item => item.nodeType === '1').nodePath.position.y
  const pageOffsetWidth = svgWrap.width.baseVal.value
  return {
    x: x + 0.5 * pageOffsetWidth - startNodesX,
    y: y + 80 - startNodesY
  }
}


/**
 * 画布相对所有节点中心点
 * @param {Array} nodeConfig 数据
 * @returns {Object} center {scale,x,y}
 */
export function getCenter(nodeConfig: INodes[], svgWrap) {
  const pageOffsetWidth = svgWrap.width.baseVal.value
  const pageOffsetHeight = svgWrap.height.baseVal.value
  const coordsX: number[] = []
  const coordsY: number[] = []
  nodeConfig.forEach((item: INodes) => {
    const position = item.nodePath.position
    const size = item.nodePath.size
    const paths = item.nodePath.paths
    coordsX.push(position.x - size.width / 2)
    coordsX.push(position.x + size.width / 2)
    coordsY.push(position.y - size.height / 2)
    coordsY.push(position.y + size.height / 2)
    paths.forEach(path => {
      path.points.forEach(point => {
        coordsX.push(point[0])
        coordsY.push(point[1])
      })
    })
  })
  const minX = Math.min.apply(null, coordsX)
  const minY = Math.min.apply(null, coordsY)
  const maxX = Math.max.apply(null, coordsX)
  const maxY = Math.max.apply(null, coordsY)
  const width = maxX - minX
  const height = maxY - minY
  const center = {
    x: maxX - width / 2,
    y: maxY - height / 2
  }
  const scale = Math.min((pageOffsetWidth - 40) / width, (pageOffsetHeight - 40) / height) // 各边留20px
  if (scale > 1) {
    const startNodesY = nodeConfig.find(item => item.nodeType === '1')?.nodePath.position.y ?? 0
    return {
      scale: 1,
      x: 0.5 * pageOffsetWidth - center.x,
      y: 80 - startNodesY
    }
  }
  return {
    scale,
    // x: pageOffsetWidth / 2 + (width / 2 - center.x) * scale - width / 2 * scale,
    // y: pageOffsetHeight / 2 + (height / 2 - center.y) * scale - height / 2 * scale
    x: (pageOffsetWidth) / 2 - (minX + width / 2) * scale,
    y: (pageOffsetHeight) / 2 - (minY + height / 2) * scale
  }
}

/**
 * 更新节点数据快照
 * @param {Object} vm 组件实例
 */
export function updateNodeConfigSnapshots() {
  console.log('nodeConfig.value')
  nodeConfigSnapshots.value.splice(nodeConfigSnapshotsIndex.value + 1, nodeConfigSnapshots.value.length, JSON.parse(JSON.stringify(nodeConfig.value)))
  console.log('nodeConfig.value')
  nodeConfigSnapshotsIndex.value++
}

/**
 * 快捷键
 * @param {Object} e 原生keyup event
 * @param {Array} nodeConfig 节点数据
 * @param {Array<string>} actives 操作id
 */
export function shortcutKeyup(e) {
  e.preventDefault()
  console.log(e)
  if ([8, 46].includes(e.keyCode)) {
    // Backspace & Delete
    onKeyupDelete()
  } else if (e.composed && e.ctrlKey && !e.shiftKey && e.keyCode === 90) {
    // undo CTRL + Z
    onKeyupUndo()
  } else if (e.composed && e.ctrlKey && e.shiftKey && e.keyCode === 90 || e.composed && e.ctrlKey && e.keyCode === 89) {
    // redo CTRL + SHIFT + Z || CTRL + Y
    onKeyupRedo()
  }
}

/**
 * 撤销
 */
export function onKeyupUndo() {
  if (nodeConfigSnapshotsIndex.value <= 0 || !nodeConfigSnapshots.value[nodeConfigSnapshotsIndex.value - 1]) return
  nodeConfigSnapshotsIndex.value--
  nodeConfig.value.splice(0, nodeConfig.value.length, ...JSON.parse(JSON.stringify(nodeConfigSnapshots.value[nodeConfigSnapshotsIndex.value])))
}

/**
 * 重做
 */
export function onKeyupRedo() {
  if (!nodeConfigSnapshots.value[nodeConfigSnapshotsIndex.value + 1]) return
  nodeConfigSnapshotsIndex.value++
  nodeConfig.value.splice(0, nodeConfig.value.length, ...JSON.parse(JSON.stringify(nodeConfigSnapshots.value[nodeConfigSnapshotsIndex.value])))
}

// function showConfirmDelete () {
//   return new Promise((resolve, reject) => {
//     Modal.confirm({
//       title: '确定删除？',
//       onOk: () => {
//         resolve()
//       },
//       onCancel: () => {
//         reject()
//       }
//     })
//   })
// }

export function onKeyupDelete() {
  if (nodeConfig.value.some(item => actives.value.includes(item.id) && item.nodeType === '1')) {
    // Message.warning('包含开始节点,请重新选择')
    console.warn('包含开始节点,请重新选择')
    return
  }
  nodeConfig.value.forEach((nodeItem, nodeIndex) => {
    // 处理连线
    if (nodeItem.nodePath.paths.some(path => actives.value.includes(path.id))) {
      for (let i = 0; i < nodeItem.nodePath.paths.length; i++) {
        // 记录当前path
        const path = nodeItem.nodePath.paths[i]
        const id = nodeItem.nodePath.to[i] // 记录id，查询子节点
        if (actives.value.includes(path.id)) {
          // outputNodeCode转为数组，并删除对应的nodeCode
          nodeItem.outputNodeCode.splice(i, 1)
          // 找到连线的子节点（下一个节点）
          const toNode = nodeConfig.value.find(node => node.id === id)
          if (!toNode) continue
          toNode.nodePath.from = toNode.nodePath.from.filter(from => from !== nodeItem.id)
          toNode.inputNodeCode = toNode.inputNodeCode.filter(input => input !== nodeItem.nodeCode)

          // 删除本节点to中找到的id
          nodeItem.nodePath.to.splice(i, 1)
          console.log(i, nodeItem.outputNodeCode)

          actives.value.splice(0, actives.value.length, ...actives.value.filter(active => active !== path.id))
          nodeItem.nodePath.paths.splice(i, 1)
          --i
        }
      }
    }
    // 处理节点
    if (actives.value.includes(nodeItem.id)) {
      // 处理父节点们
      const fromNodes = nodeConfig.value.filter(parentNode => nodeItem.nodePath.from.includes(parentNode.id))
      const childIndexList: number[] = []
      console.log('fromNodes', fromNodes)
      for (const node of fromNodes) {
        childIndexList.push(node.nodePath.to.findIndex(i => i === nodeItem.id))
      }
      console.log('childIndexList', childIndexList)
      fromNodes.forEach((parentItem, parentIndex) => {
        parentItem.nodePath.paths.splice(childIndexList[parentIndex], 1)
        parentItem.outputNodeCode.splice(childIndexList[parentIndex], 1)
        parentItem.nodePath.to.splice(childIndexList[parentIndex], 1)
      })
      // 处理子节点们
      const childNodeArry = nodeConfig.value.filter(childNode => nodeItem.nodePath.to.includes(childNode.id))
      const parentIndexList: number[] = []
      for (const child of childNodeArry) {
        parentIndexList.push(child.nodePath.from.findIndex(i => i === nodeItem.id))
      }
      childNodeArry.forEach((childItem, childIndex) => {
        childItem.inputNodeCode.splice(parentIndexList[childIndex], 1)
        childItem.nodePath.from.splice(childIndexList[childIndex], 1)
      })
    }
  })
  // 过滤actives未匹配节点
  // nodeConfig.splice(0, nodeConfig.length, ...nodeConfig.filter(item => !actives.includes(item.id)))
  for (let i = 0; i < nodeConfig.value.length; i++) {
    if (actives.value.includes(nodeConfig[i].id)) {
      nodeConfig.value.splice(i, 1)
      --i
    }
  }

  actives.value.splice(0, actives.value.length) // 清空
  updateNodeConfigSnapshots()
}