function list2map(list: any[], valueKey: string, labelKey?: string): any {
  if (!list?.length) return {}
  const map: Record<string, any> = {}
  for (const item of list) {
    map[item[valueKey]] = labelKey ? item[labelKey] : item
  }
  return map
}

function options2map(list: any[]): any {
  return list2map(list, 'value', 'label')
}

function toJSON(json: string) {
  try {
    return JSON.parse(json)
  } catch {
    return undefined
  }
}

function toNestedToFlattenJSON(json: string) {
  return nestedToFlatten(toJSON(json))
}

function nestedToFlatten(nestedObj: any, prefix: string = '') {
  if (!nestedObj) return nestedObj
  if (Array.isArray(nestedObj)) return nestedObj
  let result = {} as any
  for (const [key, value] of Object.entries(nestedObj)) {
    const newKey = prefix ? `${prefix}.${key}` : key
    if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
      // 如果是对象，递归处理
      const flattened = nestedToFlatten(value, newKey)
      result = { ...result, ...flattened }
    } else {
      // 如果是字符串，直接赋值
      result[newKey] = value
    }
  }
  return result
}

function flattenToNested(flatObj: any) {
  const result = {} as any

  for (const [path, value] of Object.entries(flatObj)) {
    const keys = path.split('.')
    let currentLevel = result as any

    for (let i = 0; i < keys.length; i++) {
      const key = keys[i] as any

      if (i === keys.length - 1) {
        // 最后一个键，设置值
        currentLevel[key] = value
      } else {
        // 不是最后一个键，确保有嵌套对象
        if (!currentLevel[key]) {
          currentLevel[key] = {}
        }
        currentLevel = currentLevel[key] as any
      }
    }
  }

  return result
}

function toJSONString(obj: any) {
  return JSON.stringify(obj)
}

function toFlattenToNestedJSONString(obj: any) {
  return toJSONString(flattenToNested(obj))
}

function map2options(map: Record<number, string>) {
  // 将map转换成options
  const arr = []
  for (const value in map) {
    arr.push({
      value,
      label: map[value],
    })
  }
  return arr
}

// 只赋值dst中存在的属性
function assignExits(dst: any, src: any) {
  for (const key in dst) {
    dst[key] = src[key]
  }
}

// 只提取指定的属性
function filterKeys(obj: any, keys: string[]) {
  const newObj: any = {}
  for (const key of keys) {
    newObj[key] = obj[key]
  }
  return newObj
}

// 是否没有值
function isNullOrUndefined(obj: any) {
  return obj === null || obj === undefined
}

function isEqualIgnoreNumberString(obj1: any, obj2: any) {
  return isEqual(obj1, obj2, { ignoreNumberString: true })
}

function isEqual(
  obj1: any,
  obj2: any,
  options?: {
    ignoreNumberString?: boolean
  },
) {
  if (obj1 === obj2) {
    return true
  }

  // 忽略数字、字符串的比较
  if (
    options?.ignoreNumberString &&
    (typeof obj1 === 'number' || typeof obj1 === 'string') &&
    (typeof obj2 === 'number' || typeof obj2 === 'string')
  ) {
    return `${obj1}` === `${obj2}`
  }

  if (
    typeof obj1 !== 'object' ||
    obj1 === null ||
    typeof obj2 !== 'object' ||
    obj2 === null
  ) {
    return false
  }

  const keys1 = Object.keys(obj1)
  const keys2 = Object.keys(obj2)

  if (keys1.length !== keys2.length) return false

  for (const key of keys1) {
    if (!keys2.includes(key)) return false
    if (!isEqual(obj1[key], obj2[key], options)) {
      return false
    }
  }
  return true
}

function isKeyValueObject(obj: any) {
  return (
    obj !== null &&
    typeof obj === 'object' &&
    !Array.isArray(obj) &&
    !(obj instanceof Date) &&
    !(obj instanceof RegExp) &&
    !(obj instanceof Map) &&
    !(obj instanceof Set)
  )
}

function coverNullProps(dst: any, src: any) {
  return cover(dst, src, {
    onlyNullProps: true,
  })
}

// 覆盖属性
function cover(
  dst: any,
  src: any,
  options?: {
    onlyNullProps?: boolean
  },
) {
  if (!isKeyValueObject(dst) || !isKeyValueObject(src)) {
    return dst
  }
  const onlyNull = options?.onlyNullProps
  // 合并所有的key
  const keys = [...new Set([...Object.keys(dst), ...Object.keys(src)])]
  for (const key of keys) {
    // 跳过
    if (!(key in src)) continue
    // 来源值
    const srcVal = src[key]
    // 目标值
    const dstVal = dst[key]
    if (onlyNull && dstVal !== undefined && dstVal !== null) {
      continue
    }
    if (Array.isArray(srcVal)) {
      // 如果是数组
      dst[key] = Array.isArray(dstVal) ? [...dstVal, ...srcVal] : [...srcVal]
    } else if (isKeyValueObject(srcVal) && isKeyValueObject(dstVal)) {
      // 如果是对象类型
      dst[key] = cover(dstVal, srcVal)
    } else {
      // 如果是非对象类型
      dst[key] = srcVal
    }
  }
  return dst
}

function getAllMethods(obj: any): Record<string, any> {
  const methods: Record<string, any> = {}
  let current = obj

  while (current && current !== Object.prototype) {
    const proto = Object.getPrototypeOf(current)
    Object.getOwnPropertyNames(proto)
      .filter(
        (name) => name !== 'constructor' && typeof proto[name] === 'function',
      )
      .forEach((name) => {
        // 这个判断很重要，优先返回自己的属性，不希望被父类的属性覆盖
        if (methods[name]) return
        methods[name] = proto[name]
      })
    current = proto
  }

  return methods
}

function snowflakeId(workerId: number = 1): string {
  // 自定义起始时间
  const timestamp = BigInt(Date.now())
  const workerBits = BigInt(workerId) << 12n
  const sequenceBits = BigInt(Math.floor(Math.random() * 4096))
  return `${(timestamp << 22n) | workerBits | sequenceBits}`
}

function joinObjs<T>(...args: T[]) {
  let list = [] as any
  for (const item of args) {
    if (!item) continue
    if (Array.isArray(item)) {
      // 如果是数组
      list = [...list, ...item]
    } else if (typeof item === 'object') {
      list.push(item)
    }
  }
  return list
}

// 深度优先搜索
function _findParentIds(items: any, itemId: any, pids: any) {
  for (const item of items) {
    if (item.id === itemId) {
      return item
    }
    if (item.children) {
      pids.push(item.id)
      const res = _findParentIds(item.children, itemId, pids) as any
      if (res) {
        return res
      }
    }
    // 删除回退的父节点
    pids.pop()
  }
}

function findParentIds(items: any, itemId: any) {
  const pids = [] as any[]
  return _findParentIds(items, itemId, pids) ? pids : []
}

function hasDefinedValue(val: any) {
  if (typeof val !== 'object') return false
  for (const key in val) {
    if (val[key] !== undefined) return true
  }
  return false
}

export default {
  findParentIds,
  joinObjs,
  list2map,
  options2map,
  map2options,
  assignExits,
  filterKeys,
  isEqual,
  isEqualIgnoreNumberString,
  cover,
  hasDefinedValue,
  coverNullProps,
  isKeyValueObject,
  isNullOrUndefined,
  getAllMethods,
  snowflakeId,
  toJSON,
  toNestedToFlattenJSON,
  toJSONString,
  nestedToFlatten,
  flattenToNested,
  toFlattenToNestedJSONString,
}
