import { nodeDataNoStylePropList } from "../constants/constant"
import { lineStyleProps, ThemeConfig } from "../theme"
import { createUid } from "./Number"
import { isUndef } from "./Object"
import { FontOptions, joinFontStr } from "./Theme"
import { Node } from "../types"

// 判断一个字段是否是节点数据中的样式字段
export const checkIsNodeStyleDataKey = (key: string): boolean => {
  // 用户自定义字段
  if (/^_/.test(key)) return false
  // 不在节点非样式字段列表里，那么就是样式字段
  if (!nodeDataNoStylePropList.includes(key)) {
    return true
  }
  return false
}

// 判断一个对象是否不需要触发节点重新创建
export const isNodeNotNeedRenderData = (config: Record<string, any>): boolean => {
  const list: string[] = [...lineStyleProps] // 节点连线样式
  const keys = Object.keys(config)
  for (let i = 0; i < keys.length; i++) {
    if (!list.includes(keys[i])) {
      return false
    }
  }
  return true
}


// 从节点实例列表里找出顶层的节点
export const getTopAncestorsFomNodeList = (list: Node[]): Node[] => {
  let res: Node[] = []
  list.forEach(node => {
    if (
      !list.find(item => {
        return item.uid !== node.uid && item.isAncestor(node)
      })
    ) {
      res.push(node)
    }
  })
  return res
}

// 从给定的节点实例列表里判断是否存在上下级关系
export const checkHasSupSubRelation = (list: Node[]): boolean => {
  for (let i = 0; i < list.length; i++) {
    const cur = list[i]
    if (
      list.find(item => {
        return item.uid !== cur.uid && cur.isAncestor(item)
      })
    ) {
      return true
    }
  }
  return false
}

interface GeneralizationNode {
  node: Node
  range?: [number, number]
}

// 解析要添加概要的节点实例列表
export const parseAddGeneralizationNodeList = (list: Node[]): GeneralizationNode[] => {
  const cache: Record<string, Array<{ node: Node, index: number }>> = {}
  const uidToParent: Record<string, Node> = {}
  list.forEach(node => {
    const parent = node.parent
    if (parent) {
      const pUid = parent.uid
      uidToParent[pUid] = parent
      const index = node.getIndexInBrothers()
      const data = {
        node,
        index
      }
      if (cache[pUid]) {
        if (
          !cache[pUid].find(item => {
            return item.index === data.index
          })
        ) {
          cache[pUid].push(data)
        }
      } else {
        cache[pUid] = [data]
      }
    }
  })
  const res: GeneralizationNode[] = []
  Object.keys(cache).forEach(uid => {
    if (cache[uid].length > 1) {
      const rangeList = cache[uid]
        .map(item => {
          return item.index
        })
        .sort((a, b) => {
          return a - b
        })
      res.push({
        node: uidToParent[uid],
        range: [rangeList[0], rangeList[rangeList.length - 1]]
      })
    } else {
      res.push({
        node: cache[uid][0].node
      })
    }
  })
  return res
}

// 给指定的节点列表树数据添加附加数据，会修改原数据
export const addDataToAppointNodes = (appointNodes: Node[], data: Record<string, any> = {}): Node[] => {
  data = { ...data }
  const alreadyIsRichText = data && data.richText
  // 如果指定的数据就是富文本格式，那么不需要重新创建
  if (alreadyIsRichText && data.resetRichText) {
    delete data.resetRichText
  }
  const walk = (list: Node[]) => {
    list.forEach(node => {
      node.data = {
        ...node.data,
        ...data
      }
      if (node.children && node.children.length > 0) {
        walk(node.children)
      }
    })
  }
  walk(appointNodes)
  return appointNodes
}

// 给指定的节点列表树数据添加uid，会修改原数据
export const createUidForAppointNodes = (
  appointNodes: Node[],
  createNewId: boolean = false,
  handle: ((node: Node) => void) | null = null
): Node[] => {
  const walk = (list: Node[]) => {
    list.forEach(node => {
      if (!node.data) {
        node.data = {}
      }
      if (createNewId || isUndef(node.data.uid)) {
        node.data.uid = createUid()
      }
      handle && handle(node)
      if (node.children && node.children.length > 0) {
        walk(node.children)
      }
    })
  }
  walk(appointNodes)
  return appointNodes
}

// 获取节点在同级里的位置索引
// 获取节点在同级里的位置索引
export const getNodeDataIndex = (node: Node): number => {
  if (!node?.parent?.nodeData?.children) return -1
  return node.parent.nodeData.children.findIndex(item => {
    return item.data.uid === node.uid
  })
}
// 从一个节点列表里找出某个节点的索引
export const getNodeIndexInNodeList = (node: Node, nodeList: Node[]): number => {
  return nodeList.findIndex(item => {
    return item.uid === node.uid
  })
}

// 从节点的父节点的nodeData.children列表中移除该节点的数据
export const removeFromParentNodeData = (node: Node | null): void => {
  // 检查 node 和 parent 是否存在
  if (!node?.parent?.nodeData?.children) return
  const index = getNodeDataIndex(node)
  if (index === -1) return
  node.parent.nodeData.children.splice(index, 1)
}

interface TextMetrics {
  width: number
  height: number
}

//计算节点的文本长宽
let measureTextContext: CanvasRenderingContext2D | null = null
export const measureText = (text: string, { italic, bold, fontSize, fontFamily }: FontOptions): TextMetrics => {
  const font = joinFontStr({
    italic,
    bold,
    fontSize,
    fontFamily
  })
  if (!measureTextContext) {
    const canvas = document.createElement('canvas')
    measureTextContext = canvas.getContext('2d')
  }
  // 先进行空值检查
  if (!measureTextContext) {
    throw new Error('Failed to get 2D context')
  }
  measureTextContext?.save()
  measureTextContext.font = font
  const { width, actualBoundingBoxAscent, actualBoundingBoxDescent } =
    measureTextContext.measureText(text)
  measureTextContext.restore()
  const height = actualBoundingBoxAscent + actualBoundingBoxDescent
  return { width, height }
}