import { NodeData, TreeNode } from "../types"

// 获取一个数据的类型
export const getType = (data: any): string => {
  return Object.prototype.toString.call(data).slice(8, -1)
}

// 判断一个数据是否是null和undefined和空字符串
export const isUndef = (data: any): boolean => {
  return data === null || data === undefined || data === ''
}

// 获取对象改变了的的属性
export const getObjectChangedProps = (oldObject: Record<string, any>, newObject: Record<string, any>): Record<string, any> => {
  const res: Record<string, any> = {}
  Object.keys(newObject).forEach(prop => {
    const oldVal = oldObject[prop]
    const newVal = newObject[prop]
    if (getType(oldVal) !== getType(newVal)) {
      res[prop] = newVal
      return
    }
    if (getType(oldVal) === 'Object') {
      if (JSON.stringify(oldVal) !== JSON.stringify(newVal)) {
        res[prop] = newVal
        return
      }
    } else {
      if (oldVal !== newVal) {
        res[prop] = newVal
        return
      }
    }
  })
  return res
}

// 判断两个对象是否相同，只处理对象或数组
export const isSameObject = (a: any, b: any): boolean => {
  const type = getType(a)
  if (type !== getType(b)) return false
  if (type === 'Object') {
    const keysa = Object.keys(a)
    const keysb = Object.keys(b)
    if (keysa.length !== keysb.length) return false
    for (let i = 0; i < keysa.length; i++) {
      const key = keysa[i]
      if (!keysb.includes(key)) return false
      const isSame = isSameObject(a[key], b[key])
      if (!isSame) {
        return false
      }
    }
    return true
  } else if (type === 'Array') {
    if (a.length !== b.length) return false
    for (let i = 0; i < a.length; i++) {
      const itema = a[i]
      const itemb = b[i]
      const typea = getType(itema)
      const typeb = getType(itemb)
      if (typea !== typeb) return false
      const isSame = isSameObject(itema, itemb)
      if (!isSame) {
        return false
      }
    }
    return true
  } else {
    return a === b
  }
}

// 传入一个数据，如果该数据是数组，那么返回该数组，否则返回一个以该数据为成员的数组
export const formatDataToArray = <T>(data: T | T[]): T[] => {
  if (!data) return []
  return Array.isArray(data) ? data : [data]
}

// 极简的深拷贝
export const simpleDeepClone = <T>(data: T): T | null => {
  try {
    return JSON.parse(JSON.stringify(data))
  } catch (error) {
    return null
  }
}


interface ObjectNode {
  isRoot: boolean;
  data: NodeData;
  children: string[];
}

const _findParentUid = (data: Record<string, ObjectNode>, targetUid: string): string => {
  const uids = Object.keys(data)
  let res = ''
  uids.forEach(uid => {
    const children = data[uid].children
    const isParent = children.findIndex(childUid => childUid === targetUid) !== -1
    if (isParent) {
      res = uid
    }
  })
  return res
}

export const transformTreeDataToObject = (data: TreeNode): Record<string, ObjectNode> => {
  const res: Record<string, ObjectNode> = {}
  const walk = (root: TreeNode, parent: ObjectNode | null) => {
    const uid = root.data.uid
    if (parent) {
      parent.children.push(uid)
    }
    res[uid] = {
      isRoot: !parent,
      data: {
        ...root.data
      },
      children: []
    }
    if (root.children && root.children.length > 0) {
      root.children.forEach(item => {
        walk(item, res[uid])
      })
    }
  }
  walk(data, null)
  return res
}

export const transformObjectToTreeData = (data: Record<string, ObjectNode>): TreeNode | null => {
  const uids = Object.keys(data)
  if (uids.length <= 0) return null
  const rootKey = uids.find(uid => data[uid].isRoot)
  if (!rootKey || !data[rootKey]) return null

  const res: TreeNode = {
    data: simpleDeepClone(data[rootKey].data) as TreeNode['data'],
    children: []
  }
  const map: Record<string, TreeNode> = {}
  map[rootKey] = res

  uids.forEach(uid => {
    const parentUid = _findParentUid(data, uid)
    const cur = data[uid]
    const node: TreeNode = map[uid] || {
      data: simpleDeepClone(cur.data) as TreeNode['data'],
      children: []
    }
    if (!map[uid]) {
      map[uid] = node
    }
    if (parentUid) {
      const index = data[parentUid].children.findIndex(item => item === uid)
      if (!map[parentUid]) {
        map[parentUid] = {
          data: simpleDeepClone(data[parentUid].data) as TreeNode['data'],
          children: []
        }
      }
      map[parentUid].children[index] = node
    }
  })
  return res
}