export * from './params'
export * from './copy'
export * from './diff'
export * from './el'
// export * from './test'
export * from './meta'

export const throttle = <Args extends any[]>(
  fn: (...args: Args) => void,
  deley: number
) => {
  let valib = false
  let lastCtx: { self: any; args: Args } | null = null

  return function (this: any, ...args: Args) {
    lastCtx = {
      args,
      self: this
    }
    if (valib) {
      return
    }
    const currentCtx = lastCtx
    valib = true

    setTimeout(() => {
      fn.apply(currentCtx.self, currentCtx.args)
      currentCtx !== lastCtx && fn.apply(lastCtx!.self, lastCtx!.args)
      valib = false
    }, deley)
  }
}

type BatchAsyncFn<Args extends any[] = any[], Result = any> = (
  ...args: Args
) => Promise<Result>

export const batchFetchPick = (max: number) => {
  const tasks: (Promise<any> | null)[] = []
  let workTaskCount = 0

  return <Args extends any[], Result>(
    fetchFunction: BatchAsyncFn<Args, Result>
  ) => {
    return function fetch(this: any, ...args: Args): Promise<Result> {
      if (workTaskCount >= max) {
        const getResult = () => fetch.apply(this, args)
        return Promise.race(tasks).then(getResult).catch(getResult)
      } else {
        workTaskCount = tasks.length + 1
        const result = fetchFunction.apply(this, args)
        const pickResult = result.finally(() => {
          const currentIndex = tasks.indexOf(pickResult)
          ~currentIndex && tasks.splice(currentIndex, 1)
          workTaskCount = tasks.length
        })
        tasks.push(pickResult)
        return result
      }
    }
  }
}

export const jsonToForm = (data: { [key in string]: any }) => {
  const formData = new FormData()
  for (const [key, val] of Object.entries(data)) {
    formData.append(key, val)
  }
  return formData
}
