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

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',
    baseURL: window.context.portal,
    ...(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} [reqData={}] - 请求的参数数据
   * @param {string} [identifier='default'] - 请求标识符，用于区分不同的请求
   * @returns {Promise} - 返回请求的结果
   */
  const sendRequest = async (reqData = {}, identifier = 'default') => {
    // 取消之前同标识符的请求
    if (_abortControllerMap.has(identifier))
      _abortControllerMap.get(identifier).abort()

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

    try {
      // 发起请求
      const {data} = await req.$http({
        ...newConfig,
        [_methodsKey]: reqData,
        signal: abortController.signal
      })

      // 请求成功完成后移除对应的中断控制器
      _abortControllerMap.delete(identifier)
      return data
    } catch (err) {
      // 错误情况下不移除中断控制器，便于后续处理
      throw err
    }
  }

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

  /**
   * 取消指定标识符的请求
   * @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
}
