/*
 * ✨ 常用辅助工具类函数 ✨
 * */

import req from '@/request'

/**
 * 自动取消请求构造器
 * @description 创建一个带有自动取消功能的请求函数，该函数会在新请求发起之前自动取消前一个未完成的请求。
 * @param {Object | string} config - 请求配置对象或URL字符串，配置对象可参考axios请求配置项。
 * @returns {Function} 返回一个用于发起请求的函数，并附带：取消或查看请求状态等功能。
 * @example
 * const request = createAutoCancelRequest('/api/data')
 * request({ id: 123 }).then(response => console.log(response))
 * console.log(request.isRequestPending()) // 是否有未完成的请求
 * request.cancel() // 取消当前请求
 *
 * // 也可以单独给接口函数指定一个唯一标识符
 * // 以避免同一实例接口函数被用于不同位置调用，造成取消冲突及误取消。
 * request({ id: 123 },'default').then(response => console.log(response))
 * console.log(request.isRequestPending('default'))
 * request.cancel(callback ,'default')
 * */
export function createAutoCancelRequest(config) {
  // 参数归一化处理
  let newConfig = {
    method: 'GET',
    ...(typeof config === 'string' ? {url: config} : config)
  }

  // 根据请求方法决定参数存储的 key ('data' 或 'params')
  const _methodsKey = ['POST', 'PUT', 'PATCH'].includes(
    newConfig.method?.toUpperCase()
  )
    ? 'data'
    : 'params'

  // 使用 Map 存储请求的中断控制器
  const _abortControllerMap = new Map()

  /**
   * 发起新的请求
   * @param {Object | Function} [reqConfig={}] - 请求的参数数据，也可以传入一个函数
   * @param {string} [identifier='default'] - 请求标识符，用于区分不同的请求
   * @returns {Promise} - 返回请求的结果
   */
  const sendRequest = async (reqConfig = {}, identifier = 'default') => {
    // 取消之前同标识符的请求
    if (_abortControllerMap.has(identifier))
      _abortControllerMap.get(identifier).abort()

    // 创建并存储新的中断控制器
    const abortController = new AbortController()
    _abortControllerMap.set(identifier, abortController)

    // eslint-disable-next-line no-useless-catch
    try {
      const data = await req.$http({
        ...newConfig,
        ...(typeof reqConfig === 'function'
          ? reqConfig(newConfig)
          : {[_methodsKey]: reqConfig}),
        signal: abortController.signal
      })

      _abortControllerMap.delete(identifier) // 请求成功时移除控制器
      return data
    } catch (err) {
      if (err?.message === 'canceled' || err?.name === 'AbortError') {
        // 如果是手动取消的请求，不清理控制器，让 isRequestPending 正常工作
        throw err
      }
      // 其他错误情况清理控制器
      _abortControllerMap.delete(identifier)
      throw err // 再次抛出错误供外部处理
    }
  }

  /**
   * 检查是否有未完成的请求
   * @param {string} [identifier='default'] - 请求标识符
   * @returns {boolean} - 如果请求正在进行且未被中断或失败，返回 true
   */
  sendRequest.isRequestPending = (identifier = 'default') => {
    return _abortControllerMap.has(identifier)
  }

  /**
   * 取消指定标识符的请求
   * @param {Function} [callback] - 取消请求后的回调函数
   * @param {string} [identifier='default'] - 请求标识符
   */
  sendRequest.cancel = (callback, identifier = 'default') => {
    if (sendRequest.isRequestPending(identifier))
      _abortControllerMap.get(identifier).abort()
    callback && callback()
  }

  return sendRequest
}

/**
 * 判断一个值是否非空。
 * 空的定义包括：null、undefined、空字符串、空数组和空对象。
 *
 * @param {*} value - 需要判断的值。
 * @returns {boolean} 如果值非空，则返回 true；否则返回 false。
 */
export function isNotEmpty(value) {
  // 检查是否为 null 或 undefined
  if (value === null || value === undefined) {
    return false
  }

  // 检查字符串是否为空（去除空白字符后）
  if (typeof value === 'string') {
    if (value.trim() === '') {
      return false
    }
  }

  // 检查数组是否为空
  if (Array.isArray(value)) {
    if (value.length === 0) {
      return false
    }
  }

  // 检查对象是否为空
  if (typeof value === 'object' && !Array.isArray(value)) {
    // 获取对象的所有可枚举属性名
    const keys = Object.keys(value)
    if (keys.length === 0) {
      return false
    }
  }

  return true
}
