/*
 * @Author: libo
 * @Date: 2024-11-19 20:41:53
 * @LastEditors: libo
 * @LastEditTime: 2024-11-20 14:17:05
 * @FilePath: \wangEditor-plugin-upload-pdf-main\src\module\menu\helper.ts
 * @Description:
 */
/**
 * @description helper fns
 * @author wangfupeng
 */

import Uppy, { UppyFile } from '@uppy/core'
import { IDomEditor } from '@wangeditor-next/editor'
import { createUploader } from '@wangeditor-next/editor'
import { PDFElement } from '../custom-types'
import { IUploadConfigForPDF } from './config'

function getUploadPDFMenuConfig(editor: IDomEditor): IUploadConfigForPDF {
  // 获取配置，见 `./config.js`
  return editor.getMenuConfig('uploadPDF') as IUploadConfigForPDF
}

/**
 * 插入 attachment 节点
 * @param fileName fileName
 * @param link link
 */
export function insertPDF(editor: IDomEditor, src: string, shortcode: string) {
  if (!src || !shortcode) return

  // 还原选区
  editor.restoreSelection()

  // 插入节点
  const attachmentElem: PDFElement = {
    type: 'importPdf',
    src,
    shortcode,
    children: [{ text: '' }],
  }
  editor.insertNode(attachmentElem)
  editor.move(1)

  // 回调
  const { onInsertedPDF } = getUploadPDFMenuConfig(editor)
  if (onInsertedPDF) onInsertedPDF(attachmentElem)
}

/**
 * 上传附件文件
 * @param editor editor
 * @param files files
 */
export async function uploadPDF(editor: IDomEditor, files: FileList | null) {
  if (files == null) return
  const fileList = Array.prototype.slice.call(files)
  // 获取菜单配置
  const { customUpload } = getUploadPDFMenuConfig(editor)

  // 按顺序上传
  for await (const file of fileList) {
    // 上传
    if (customUpload) {
      // 自定义上传
      await customUpload(file, (fileName: string, link: string) => {
        insertPDF(editor, link, fileName)
      })
    } else {
      // 默认上传
      await uploadFile(editor, file)
    }
  }
}

/**
 * 上传文件
 * @param editor editor
 * @param file file
 */
async function uploadFile(editor: IDomEditor, file: File) {
  const uppy = getUppy(editor)

  const { name, type, size } = file
  uppy.addFile({
    name,
    type,
    size,
    data: file,
  })
  await uppy.upload()
}

// 存储 editor uppy 的关系 - 缓存 uppy ，不重复创建
const EDITOR_TO_UPPY_MAP = new WeakMap<IDomEditor, Uppy>()

/**
 * 获取 uppy 实例（并通过 editor 缓存）
 * @param editor editor
 */
function getUppy(editor: IDomEditor): Uppy {
  // 从缓存中获取
  let uppy = EDITOR_TO_UPPY_MAP.get(editor)
  if (uppy != null) return uppy

  const menuConfig = getUploadPDFMenuConfig(editor)
  const { onSuccess, onProgress, onFailed, customInsert, onError } = menuConfig

  // 上传完成之后
  const successHandler = (file: UppyFile, res: any) => {
    // 预期 res 格式：
    // 成功：{ errno: 0, data: { url } }
    // 失败：{ errno: !0, message: '失败信息' }

    if (customInsert) {
      // 用户自定义插入文件，此时 res 格式可能不符合预期
      customInsert(res, file, (fileName: string, link: string) => insertPDF(editor, link, fileName))
      return
    }
    console.log('res', res)
    const { errno = 1, data = {} } = res
    if (errno !== 0) {
      console.error(`'${file.name}' upload failed`, res)

      // failed 回调
      onFailed(file, res)
      return
    }

    const { url = '' } = data[0]
    insertPDF(editor, url, file.name)

    // success 回调
    onSuccess(file, res)
  }

  // progress 显示进度条
  const progressHandler = (progress: number) => {
    editor.showProgressBar(progress)

    // 回调函数
    onProgress && onProgress(progress)
  }

  // onError 提示错误
  const errorHandler = (file: any, err: any, res: any) => {
    const fileName = file.name
    console.error(`'${fileName} upload error`, err, res)

    // 回调函数
    onError && onError(file, err, res)
  }

  // 创建 uppy
  uppy = createUploader({
    ...menuConfig,
    onProgress: progressHandler,
    onSuccess: successHandler,
    onError: errorHandler,
  })
  // 缓存 uppy
  EDITOR_TO_UPPY_MAP.set(editor, uppy)

  return uppy
}
