/**
 * 公共跳转方法
 * @author lxx
 * @date 2023-08-15 14:17
 * @param { string } url 跳转路径
 * @param { "navigateTo" | "redirectTo" | "reLaunch" | "switchTab" } [mode=navigateTo] 跳转模式
 * @param { object } params 跳转传参
 * @example
 * goToPage({ url: 'pages/index/index', mode: 'navigateTo', params: {'id': 1} })
 * @returns { void }
 */
export const goToPage = ({ url, mode = 'navigateTo', params = {} }: goToPageInt): void => {
  if (!url || url.length === 0) {
    throw Error('"url" is a required parameter')
  }

  const urlEncode = (params: any = {}) => {
    const result = []
    for (const k in params) {
      if (!params[k]) continue
      result.push(k + '=' + params[k])
    }

    return result.join('&')
  }

  const queryStr = !isEmpty(params) ? '?' + urlEncode(params) : ''
  const obj = { url: `/${url}${queryStr}` }
  console.log('obj', obj)
  switch (mode) {
    case 'navigateTo':
      uni.navigateTo(obj)
      break
    case 'redirectTo':
      uni.redirectTo(obj)
      break
    case 'reLaunch':
      uni.reLaunch(obj)
      break
    case 'switchTab':
      uni.switchTab(obj)
      break
    default:
      throw Error(`${mode} does not exist`)
  }
}

/**
 * 判断是否为空对象
 * @author shenname <shenname@163.com>
 * @license MIT
 * @param {*} object 源对象
 * @returns { boolean }
 */
export const isEmptyObject = (object: any): boolean => {
  return Object.keys(object).length === 0
}

/**
 * 判断是否为对象
 * @param {*} object
 */
/**
 * 判断是否为对象
 * @author shenname <shenname@163.com>
 * @license MIT
 * @param {*} object 源对象
 * @returns { boolean }
 */
export const isObject = (object: any): boolean => {
  return Object.prototype.toString.call(object) === '[object Object]'
}

/**
 * 判断是否为数组
 * @author shenname <shenname@163.com>
 * @license MIT
 * @param {*} object 源对象
 * @returns { boolean }
 */
export const isArray = (object: any): boolean => {
  return Object.prototype.toString.call(object) === '[object Array]'
}

/**
 * 判断是否为空
 * @author shenname <shenname@163.com>
 * @license MIT
 * @param {*} value 源对象
 * @returns { boolean }
 */
export const isEmpty = (value: any): boolean => {
  if (isArray(value)) {
    return value.length === 0
  }
  if (isObject(value)) {
    return isEmptyObject(value)
  }
  return !value
}

/**
 * 获取组件类型
 * @author shenname <shenname@163.com>
 * @license MIT
 * @param { Component } _comp 组件实例
 * @example
 * useCompRef(Header)
 */
export const useCompRef = <T extends abstract new (...args: any) => any>(_comp: T) => {
  return ref<InstanceType<T>>()
}

/**
 * 格式化时间戳（多格式）
 * @author shenname <shenname@163.com>
 * @license MIT
 * @param { number } time 长度为 10 | 13 的时间戳
 * @param { string } [format=yyyy-MM-dd] format 转换格式
 * @example
 * formatTime(1691744378556, 'yyyy-MM-dd HH:mm:ss')
 * @returns { string }
 */

export const formatTime = (time: number, format: string = 'yyyy-MM-dd HH:mm:ss'): string => {
  const len = time.toString().trim().length
  if (len !== 10 && len !== 13) {
    throw Error('"time" is a error parameter')
  }

  time = len !== 13 ? time * 1000 : time

  if (!time) return ''
  const date = new Date(time)
  const M = (date.getMonth() + 1).toString()
  const d = date.getDate().toString()
  const H = date.getHours().toString()
  const m = date.getMinutes().toString()
  const s = date.getSeconds().toString()
  const timeObject: {
    [n: string]: string
  } = {
    yyyy: date.getFullYear().toString(),
    MM: M.padStart(2, '0'),
    dd: d.padStart(2, '0'),
    HH: H.padStart(2, '0'),
    mm: m.padStart(2, '0'),
    ss: s.padStart(2, '0'),
    M: M,
    d: d,
    H: H,
    m: m,
    s: s
  }
  const reg = new RegExp(Object.keys(timeObject).join('|'), 'g')
  const res = format.replace(reg, (k) => {
    return timeObject[k]
  })
  return res
}

/**
 * 防抖函数
 * @author shenname <shenname@163.com>
 * @license MIT
 * @param {function} fn
 * @param {umber} [wait=1000] wait
 * @returns { void }
 */
export const debounce = <T extends (...args: any[]) => any>(fn: T, wait: number = 1000): ((...args: Parameters<T>) => void) => {
  let timer: number | null

  return function (this: any, ...args: Parameters<T>) {
    if (timer) clearTimeout(timer)

    timer = setTimeout(() => {
      fn.apply(this, args)
    }, wait)
  }
}

/**
 * 节流函数
 * @author shenname <shenname@163.com>
 * @license MIT
 * @param { function } fn
 * @param { number } [wait=1000] wait
 */
export const throttle = <T extends (...args: any[]) => any>(fn: T, wait: number = 1000) => {
  let timer: number = Date.now()
  return function (this: any, ...args: Parameters<T>) {
    if (Date.now() - timer >= wait) {
      fn.apply(this, args)
      timer = Date.now()
    }
  }
}

/**
 * 获取文件相对路径、URL
 * @author shenname <shenname@163.com>
 * @license MIT
 * @param { string } fileName 文件名称 | 相对路径
 * @param { string } [filePath=images] filePath 文件在 /static 下的路径 获取URL时不传
 * @example
 * imgUrl('a.png')
 * imgUrl('a.png', '/public/')
 * imgUrl('/upload/images/img.png')
 * @returns {string}
 */
export const fileUrl = (fileName: string, filePath: string = 'images'): string => {
  if (/[ `!@#$%^&*()_+\-=\[\]{};':"\\|,<>\/?~]/.test(fileName)) {
    return import.meta.env.VITE_APP_BASE_URL + fileName
  } else {
    return `/static/${filePath}/${fileName}`
  }
}

// 存储数据到PUBLIC_DOWNLOADS目录
export const saveDataToLocal = (fileName: any, data: any) => {
  plus.io.requestFileSystem(
    plus.io.PUBLIC_DOWNLOADS, // 公共下载目录
    (fs: any) => {
      fs.root.getFile(
        fileName,
        { create: true }, // 文件不存在则创建
        (fileEntry: any) => {
          fileEntry.createWriter(
            (writer: any) => {
              writer.write(JSON.stringify(data))
              uni.showToast({ title: '保存成功' })
            },
            (err: any) => console.error('写入失败:', err)
          )
        },
        (err: any) => console.error('获取文件失败:', err)
      )
    },
    (err: any) => console.error('请求文件系统失败:', err)
  )
}

// 读取PUBLIC_DOWNLOADS目录下的文件
export const readDataFromFile = (fileName: any) => {
  return new Promise((resolve, reject) => {
    plus.io.requestFileSystem(
      plus.io.PUBLIC_DOWNLOADS,
      (fs: any) => {
        fs.root.getFile(
          fileName,
          { create: false },
          (fileEntry: any) => {
            fileEntry.file(
              (file: any) => {
                const reader = new plus.io.FileReader()
                reader.onloadend = (e: any) => resolve(e.target.result)
                reader.onerror = (e: any) => reject(e)
                reader.readAsText(file, 'utf-8')
              },
              (err: any) => reject(err)
            )
          },
          (err: any) => reject(err)
        )
      },
      (err) => reject(err)
    )
  })
}

//使用plus.io.requestFileSystem检查文件是否存在：

export const checkConfigFileExists = (filePath: any, configFileName: any) => {
  return new Promise((resolve, reject) => {
    plus.io.requestFileSystem(
      plus.io.PUBLIC_DOWNLOADS, // 或 PRIVATE_DOC
      (fs: any) => {
        fs.root.getFile(
          configFileName,
          { create: false }, // 不创建文件
          (fileEntry: any) => resolve(true), // 文件存在
          (err: any) => {
            // if (err.code === 1) resolve(false) // 文件不存在
            // else reject(err) // 其他错误
            resolve(false)
          }
        )
      },
      (err) => reject(err)
    )
  })
}
// 读取配置文件
export const readConfigFile = (filePath: any, configFileName: any) => {
  return new Promise((resolve, reject) => {
    plus.io.requestFileSystem(
      plus.io.PUBLIC_DOWNLOADS, // 或 PRIVATE_DOC
      (fs: any) => {
        fs.root.getFile(
          configFileName,
          { create: false },
          (fileEntry: any) => {
            fileEntry.file((file: any) => {
              const reader = new plus.io.FileReader()
              reader.onloadend = () => resolve(JSON.parse(reader.result))
              reader.onerror = reject
              reader.readAsText(file, 'utf-8')
            }, reject)
          },
          reject
        )
      },
      reject
    )
  })
}

//生成默认配置文件

export const createDefaultConfig = (filePath: any, configFileName: any, jsondata: any) => {
  return new Promise((resolve, reject) => {
    plus.io.requestFileSystem(
      plus.io.PUBLIC_DOWNLOADS, // 或 PRIVATE_DOC
      (fs: any) => {
        fs.root.getFile(
          configFileName,
          { create: true, exclusive: false }, // 创建文件（不覆盖已有文件）
          (fileEntry: any) => {
            fileEntry.createWriter(
              (writer: any) => {
                const defaultConfig = jsondata
                writer.write(JSON.stringify(defaultConfig))
                resolve(defaultConfig)
              },
              (err: any) => reject(err)
            )
          },
          (err: any) => reject(err)
        )
      },
      reject
    )
  })
}

export default {
  goToPage,
  formatTime,
  debounce,
  throttle,
  fileUrl,
  saveDataToLocal,
  readDataFromFile,
  checkConfigFileExists,
  readConfigFile,
  createDefaultConfig
}
