import { isObject } from '@/utils/is'
import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router'
// import useClipboard from 'vue-clipboard3'
import { isEqual } from 'lodash'
import { DomainTree } from '@/types/domain'
import { Message } from '@arco-design/web-vue'
import { PhaseItem, PhaseList, TaskStatus, TaskStatusList } from '@/enums/api'

export interface VerifyHttpParams {
  ver: string
  app_id: string
  token?: string
  timestamp: number
}

export function getRawRoute(
  route: RouteLocationNormalized
): RouteLocationNormalized {
  if (!route) return route
  const { matched, ...opt } = route
  return {
    ...opt,
    matched: (matched
      ? matched.map(item => ({
          meta: item.meta,
          name: item.name,
          path: item.path
        }))
      : undefined) as RouteRecordNormalized[]
  }
}

export function deepMerge<T = any>(src: any = {}, target: any = {}): T {
  //   let key: string
  Object.keys(target).map(key => {
    src[key] = isObject(src[key])
      ? deepMerge(src[key], target[key])
      : (src[key] = target[key])
    return null
  })
  return src
}

/**
 * Add the object as a parameter to the URL
 * @param baseUrl url
 * @param obj
 * @returns {string}
 * eg:
 *  let obj = {a: '3', b: '4'}
 *  setObjToUrlParams('www.baidu.com', obj)
 *  ==>www.baidu.com?a=3&b=4
 */
export function setObjToUrlParams(baseUrl: string, obj: any): string {
  let parameters = ''
  Object.keys(obj).map(key => {
    parameters += `${key}=${encodeURIComponent(obj[key])}&`
    return null
  })
  parameters = parameters.replace(/&$/, '')
  return /\?$/.test(baseUrl)
    ? baseUrl + parameters
    : baseUrl.replace(/\/?$/, '?') + parameters
}

// const { toClipboard } = useClipboard()

// /**
//  * copy函数
//  * @param value
//  */
// export async function copyVaule(value: string) {
//   try {
//     await toClipboard(value)
//     // ElMessage({ message: '已复制！', type: 'success' })
//   } catch (e) {
//     // console.error(e)
//   }
// }

type TargetContext = '_self' | '_parent' | '_blank' | '_top'

export const openWindow = (
  url: string,
  opts?: { target?: TargetContext; [key: string]: any }
) => {
  const { target = '_blank', ...others } = opts || {}
  window.open(
    url,
    target,
    Object.entries(others)
      .reduce((preValue: string[], curValue) => {
        const [key, value] = curValue
        return [...preValue, `${key}=${value}`]
      }, [])
      .join(',')
  )
}

export const regexUrl = new RegExp(
  '^(?!mailto:)(?:(?:http|https|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$',
  'i'
)

export interface Tree {
  id: number // 域id
  memo?: string
  key: string
  name: string
  title: string // 域名
  children?: Array<Tree>
  icon?: any
}

/**
 * 删除节点
 * @param tree
 * @param id
 * @returns
 */
export const removeNode = <T extends Array<Tree>>(tree: T, id: number): T => {
  tree.map((item: Tree, index: number): T => {
    if (item.id === id) {
      tree.splice(index, 1)
    }
    if (item.children) {
      removeNode(item.children, id)
    }
    return tree
  })
  return tree
}

/**
 * 在某节点下新增节点
 * @param tree
 * @param id
 * @param node
 * @returns
 */
export const appendNode = <T extends Array<Tree>>(
  tree: T,
  id: number,
  node: Tree
): T => {
  tree.map((item: Tree): T => {
    if (item.id === id) {
      item.children!.push(node)
    }
    if (item.children) {
      appendNode(item.children, id, node)
    }
    return tree
  })
  return tree
}

/**
 * 修改节点信息
 * @param tree
 * @param id
 * @param node
 * @returns
 */
export const modifyNode = <T extends Array<Tree>>(
  tree: T,
  id: number,
  node: Tree
): T => {
  tree.map((item: Tree): T => {
    if (item.id === id) {
      item.name = node.name
      item.title = node.title
      item.memo = node.memo
    }
    if (item.children) {
      modifyNode(item.children, id, node)
    }
    return tree
  })
  return tree
}

/**
 * 验证数组中电话号码是否符合规则
 * @param value
 * @param callback
 */
export const validateArrayPhone = (value: string[], callback: any) => {
  if (value === undefined) {
    callback('不能未空')
  } else if (value.length !== 0) {
    const have = value.find(item => {
      const Reg1 = /^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/
      const Reg2 = /^0\d{2,3}-[1-9]\d{6,7}$/
      const Reg3 = /^[1-9]\d{6,7}$/
      return Reg1.test(item) || Reg2.test(item) || Reg3.test(item)
    })
    if (!have) {
      callback('存在号码格式不正确')
    }
  }
  callback()
}

export function getObjectDiff(originalObject: any, modifiedObject: any): any {
  const diff: any = {}
  Object.keys(modifiedObject).map(key => {
    if (typeof modifiedObject[key] === 'object') {
      const nestedDiff = getObjectDiff(originalObject[key], modifiedObject[key])
      if (Object.keys(nestedDiff).length > 0) {
        diff[key] = nestedDiff
      }
    } else if (!isEqual(originalObject[key], modifiedObject[key])) {
      diff[key] = modifiedObject[key]
    }
    return key
  })
  return diff
}

export function objSort(obj: { [key: string]: any }) {
  const newObj: {
    [key: string]: any
  } = {}
  // 遍历对象，并将key进行排序
  Object.keys(obj)
    .sort()
    .map(key => {
      newObj[key] = obj[key]
      return key
    })
  // 将排序好的数组转成字符串
  return JSON.stringify(newObj)
}

export function unique(arr: { [key: string]: any }[]) {
  const set = new Set()
  for (let i = 0; i < arr.length; i += 1) {
    const str = objSort(arr[i])
    set.add(str)
  }
  // 将数组中的字符串转回对象
  arr = [...set].map((item: any) => {
    return JSON.parse(item)
  })
  return arr
}

export function orderProperties(properties: string[], order: string[]) {
  if (!Array.isArray(order)) {
    return properties
  }

  const arrayToHash = (arr: string[]) =>
    arr.reduce((prev: any, curr: any) => {
      prev[curr] = true
      return prev
    }, {})
  const errorPropList = (arr: any) =>
    arr.length > 1 ? `properties '${arr.join("', '")}'` : `property '${arr[0]}'`

  const propertyHash = arrayToHash(properties)
  const orderFiltered = order.filter(prop => prop === '*' || propertyHash[prop])
  const orderHash = arrayToHash(orderFiltered)

  const rest = properties.filter((prop: string) => !orderHash[prop])
  const restIndex = orderFiltered.indexOf('*')
  if (restIndex === -1) {
    if (rest.length) {
      throw new Error(
        `uiSchema order list does not contain ${errorPropList(rest)}`
      )
    }
    return orderFiltered
  }
  if (restIndex !== orderFiltered.lastIndexOf('*')) {
    throw new Error('uiSchema order list contains more than one wildcard item')
  }

  const complete = [...orderFiltered]
  complete.splice(restIndex, 1, ...rest)
  return complete
}

/**
 * 递归获取ng-tree需要的结构体
 * @param domains 接口返回的树状数组
 */

export const getNodesTree = (domains: DomainTree): DomainTree => {
  domains.key = domains.id.toString()
  domains.title = domains.name
  if (domains.children && domains.children.length > 0) {
    domains.children.map(res => getNodesTree(res))
  }
  return domains
}

/**
 * 获取当前项目阶段信息
 * @param phase
 */
export const selectedPhase = (
  phase: PhaseItem,
  phaseList: { id: string; name: string; color: string }[]
) => {
  return phaseList.filter(item => item.id === phase)
}

/**
 * 获取当前任务状态信息
 * @param status
 */
export const selectedTaskStatus = (status?: TaskStatus) => {
  return TaskStatusList.filter(item => item.value === status)
}

/**
 * * JSON序列化，支持函数和 undefined
 * @param data
 */
export const JSONStringify = <T>(data: T) => {
  return JSON.stringify(
    data,
    (key, val) => {
      // 处理函数丢失问题
      if (typeof val === 'function') {
        return `${val}`
      }
      // 处理 undefined 丢失问题
      if (typeof val === 'undefined') {
        return null
      }
      return val
    },
    2
  )
}

/**
 * 将二进制文件转base54
 * @param file 二进制文件
 */
export const getBase64 = (file: File): Promise<string> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    let base64File = ''
    reader.readAsDataURL(file)
    reader.onload = () => {
      base64File = reader.result as string
    }
    reader.onerror = (error: any) => {
      Message.error(`文件转Base64失败-${error}!`)
      return reject(error)
    }
    reader.onloadend = () => {
      return resolve(base64File)
    }
  })
}

// eslint-disable-next-line no-script-url
const prefix = 'javascript:'
// 对输入字符进行转义处理
export const translateStr = (target: string | object) => {
  if (typeof target === 'string') {
    if (target.startsWith(prefix)) {
      const funcStr = target.split(prefix)[1]
      let result
      try {
        // eslint-disable-next-line no-new-func
        result = new Function(`${funcStr}`)()
      } catch (error) {
        console.log(error)
        // window.$message.error('js内容解析有误！');
      }
      return result
    }
    return target
  }
  // target.
  Object.keys(target).map(key => {
    if (Object.prototype.hasOwnProperty.call(target, key)) {
      const subTarget = (target as any)[key]
      ;(target as any)[key] = translateStr(subTarget)
    }
    return key
  })
  return target
}

/**
 * * 生成一个不重复的ID
 * @param { Number } randomLength
 */
export const getUUID = (randomLength = 10) => {
  return Number(
    Math.random().toString().substring(2, randomLength) + Date.now()
  ).toString(36)
}

export function areObjectsEqual<T>(obj1: T, obj2: T): boolean {
  return JSON.stringify(obj1) === JSON.stringify(obj2)
}

export function formatBytesOptimized(bytes?: number) {
  if (bytes !== undefined) {
    const BYTES_PER_UNIT = 1024
    const units = ['B', 'KB', 'MB', 'GB']
    let value = bytes
    let unitIndex = 0

    while (value >= BYTES_PER_UNIT && unitIndex < units.length - 1) {
      value /= BYTES_PER_UNIT
      // eslint-disable-next-line no-plusplus
      unitIndex++
    }

    return `${value.toFixed(2)} ${units[unitIndex]}`
  }
  return bytes
}
