import { omit } from '../_utils'
import type { AcceptType, FileType, SizeType } from './type'
import type { UploaderProps } from './uploader'

interface UniChooseFileSuccessCallbackResult {
  /**
   * 本地文件路径列表
   */
  tempFilePaths?: string[]
  /**
   * 本地文件列表，每一项是一个 File 对象
   */
  tempFiles: ({
    path: string
    size: number
    name: string
    type: string
  } & File)[]
}

interface UniChooseImageSuccessCallbackResult extends UniChooseFileSuccessCallbackResult {

}

interface UniChooseVideoSuccessCallbackResult {
  /**
   * 本地文件路径
   */
  tempFilePath?: string
  /**
   * 本地文件，一个 File 对象
   */
  tempFile: ({
    path: string
    size: number
    name: string
    type: string
  } & File)
  /**
   * 选定视频的时间长度，单位为s
   */
  duration: number
  /**
   * 选定视频的数据量大小
   */
  size: number
  /**
   * 返回选定视频的高
   */
  height: number
  /**
   * 返回选定视频的宽
   */
  width: number
  /**
   * 包含扩展名的文件名称
   */
  name: string
}

export interface ChooseFile {
  size: number
  type?: FileType
  fileType?: FileType
  originalFileObj?: any
  tempFilePath?: string
  thumbTempFilePath?: string
  path?: string
  name: string
  thumb?: string
  url?: string
  [k: string]: unknown
}

function omitProps<T>(obj: T, keys: string[]) {
  if (!['[object Object]', '[object File]'].includes(Object.prototype.toString.call(obj)))
    return {}

  return omit(obj as unknown as Record<string, unknown>, keys)
}

function formatImage(res: UniChooseImageSuccessCallbackResult): ChooseFile[] {
  return res.tempFiles.map(item => ({
    ...omitProps(item, ['path']),
    type: 'image',
    url: item.path,
    thumb: item.path,
    size: item.size,
    name: item.name || 'image',
  }))
}

function formatVideo(res: UniChooseVideoSuccessCallbackResult): ChooseFile[] {
  return [{
    ...omitProps(res.tempFile, ['path']),
    type: 'video',
    url: res.tempFilePath,
    thumb: res.tempFilePath,
    size: res.tempFile.size,
    name: res.tempFile.name || 'video',
  }]
}

function formatMedia(res: UniApp.ChooseMediaSuccessCallbackResult & { name?: string }): ChooseFile[] {
  return res.tempFiles.map(item => ({
    ...omitProps(item, ['fileType', 'thumbTempFilePath', 'tempFilePath']),
    type: res.type as FileType,
    url: item.tempFilePath,
    thumb: res.type === 'video' ? item.thumbTempFilePath : item.tempFilePath,
    size: item.size,
    name: res?.name || 'media',
  }))
}

export interface ChooseFileOptions {
  accept: AcceptType
  multiple: boolean
  capture: boolean
  maxDuration: number
  sizeType: SizeType[]
  camera?: 'back' | 'front'
  maxCount: number
}

export function chooseFile({
  accept,
  multiple,
  maxDuration,
  sizeType,
  camera,
}: ChooseFileOptions, props: UploaderProps, fileList: any[]): Promise<ChooseFile[] | ChooseFile> {
  return new Promise((resolve, reject) => {
    // chooseMedia 目前只支持微信小程序原生，其余端全部使用 chooseImage API
    // #ifdef MP-WEIXIN

    uni.chooseMedia({
      /** 最多可以选择的文件个数 */
      count: multiple ? Number(props.maximum) * 1 - fileList.length : 1,
      /** 文件类型 */
      mediaType: props.mediaType,
      /** 图片和视频选择的来源 */
      sourceType: props.sourceType,
      /** 拍摄视频最长拍摄时间，单位秒。时间范围为 3s 至 30s 之间 */
      maxDuration,
      /** 仅对 mediaType 为 image 时有效，是否压缩所选文件 */
      sizeType,
      /** 仅在 sourceType 为 camera 时生效，使用前置或后置摄像头 */
      camera,
      /** 接口调用失败的回调函数 */
      fail: reject,
      /** 接口调用成功的回调函数 */
      success: res => resolve(formatMedia(res)),
    })
    // #endif

    // #ifndef MP-WEIXIN
    if (accept === 'image') {
      uni.chooseImage({
        // 选择数量
        count: props.multiple ? (props.maximum as number) * 1 - props.fileList.length : 1,
        // 可以指定是原图还是压缩图，默认二者都有
        sizeType,
        sourceType: props.sourceType,
        success: (res) => {
          resolve(formatImage(res as UniChooseFileSuccessCallbackResult))
        },
        fail: reject,
      })
    }
    else if (accept === 'video') {
      uni.chooseVideo({
        sourceType: props.sourceType,
        success: (res) => {
          resolve(formatVideo(res as UniChooseVideoSuccessCallbackResult))
        },
        fail: reject,
      })
    }
    else if (accept === 'all') {
      uni.chooseFile({
        type: 'all',
        // 选择数量
        count: props.multiple ? (props.maximum as number) * 1 - props.fileList.length : 1,
        // 可以指定是原图还是压缩图，默认二者都有
        sizeType,
        sourceType: props.sourceType,
        success: (res) => {
          resolve(formatImage(res as UniChooseFileSuccessCallbackResult))
        },
        fail: reject,
      })
    }

    // #endif
  })
}

export type OnProgressUpdateResult = UniApp.OnProgressUpdateResult
export type UploadFileSuccessCallbackResult = UniApp.UploadFileSuccessCallbackResult
export type GeneralCallbackResult = UniApp.GeneralCallbackResult

export type UploadOptions = UniNamespace.UploadFileOption & {
  xhrState?: number
  onStart?: (option: UploadOptions) => void
  onProgress?: (result: UniApp.OnProgressUpdateResult, option: UploadOptions) => void
  onSuccess?: (result: UniApp.UploadFileSuccessCallbackResult, option: UploadOptions) => void
  onFailure?: (result: UniApp.GeneralCallbackResult | UniApp.UploadFileSuccessCallbackResult, option: UploadOptions) => void
}

export function createUploader(options: UploadOptions) {
  const upload = () => {
    const uploadTask = uni.uploadFile({
      url: options.url,
      fileType: options.fileType,
      file: options.file,
      filePath: options.filePath,
      name: options.name,
      header: options.header,
      timeout: options.timeout,
      formData: options.formData,
      success: (result) => {
        if (options.xhrState === result.statusCode)
          options.onSuccess?.(result, options)
        else
          options.onFailure?.(result, options)
      },
      fail: (result) => {
        options.onFailure?.(result, options)
      },
    })

    options.onStart?.(options)

    uploadTask.onProgressUpdate((event) => {
      options.onProgress?.(event, options)
    })
  }

  return { upload }
}
