// 定义一个数组来存储所有的回调函数，以便在脚本加载完成后依次调用它们。
let callbacks = []

/**
 * 检查是否已成功加载TinyMCE编辑器。
 *
 * @returns {boolean} 如果window对象存在tinymce属性，则返回true，表示TinyMCE已加载；否则返回false。
 */
function loadedTinymce() {
  // 解决 https://github.com/PanJiaChen/vue-element-admin/issues/2144 的问题
  // 检查是否成功下载了脚本
  return window.tinymce !== undefined
}

/**
 * 动态加载指定URL的脚本文件，并在加载完成或发生错误时调用提供的回调函数。
 *
 * @param {string} src - 脚本文件的URL。
 * @param {Function} [callback] - 可选参数，当脚本加载完成或出错时将被调用的回调函数。
 */
const dynamicLoadScript = (src, callback) => {
  const existingScript = document.getElementById(src)
  const cb = callback || function () {} // 如果没有提供回调，则创建一个空函数作为默认值

  if (!existingScript) {
    // 创建新的<script>元素，并设置其src属性为传入的src参数。
    const script = document.createElement('script')
    script.src = src
    script.id = src // 使用src作为ID以避免重复加载同一脚本
    document.body.appendChild(script) // 将新创建的<script>元素添加到DOM中
    callbacks.push(cb) // 将回调添加到callbacks数组中，等待脚本加载完成后再执行

    // 根据浏览器支持选择合适的事件监听方式
    const onEnd = 'onload' in script ? stdOnEnd : ieOnEnd
    onEnd(script)
  }

  if (existingScript && cb) {
    // 如果脚本已经存在于页面中并且提供了回调
    if (loadedTinymce()) {
      // 如果TinyMCE已加载，则立即调用回调
      cb(null, existingScript)
    } else {
      // 否则将回调添加到队列中，等待TinyMCE加载完成
      callbacks.push(cb)
    }
  }

  /**
   * 处理标准浏览器中的脚本加载结束事件（包括成功和失败）。
   *
   * @param {HTMLScriptElement} script - 当前的<script>元素。
   */
  function stdOnEnd(script) {
    script.onload = function () {
      // 在IE9及以下版本中，this.onerror = this.onload = null 是必要的
      this.onerror = this.onload = null
      for (const cb of callbacks) {
        cb(null, script)
      }
      callbacks = null // 清除回调列表以释放内存
    }
    script.onerror = function () {
      document.body.removeChild(script) // 移除加载失败的脚本元素
      this.onerror = this.onload = null
      cb(new Error('Failed to load ' + src), script) // 执行回调并传递错误信息
    }
  }

  /**
   * 处理IE8等不支持onload事件的旧版浏览器中的脚本加载结束事件。
   *
   * @param {HTMLScriptElement} script - 当前的<script>元素。
   */
  function ieOnEnd(script) {
    script.onreadystatechange = function () {
      if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
      this.onreadystatechange = null
      for (const cb of callbacks) {
        cb(null, script) // IE8中无法捕获加载错误
      }
      callbacks = null // 清除回调列表以释放内存
    }
  }
}

export default dynamicLoadScript
