import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
import { baseProps, makeArrayProp, makeBooleanProp, makeNumberProp, makeStringProp } from '../common/props'
import type { LoadingType } from '../wd-loading/types'
import type { ImageMode } from '../wd-img/types'

export interface ChooseFileOption {
  // 是否支持多选文件
  multiple: boolean
  // 所选的图片的尺寸
  sizeType?: UploadSizeType[]
  // 选择文件的来源
  sourceType: UploadSourceType[]
  // 最大允许上传个数
  maxCount: number
  // 接受文件类型
  accept: UploadFileType
  /**
   * 是否压缩视频，当 accept 为 video 时生效。
   */
  compressed: boolean
  /**
   * 拍摄视频最长拍摄时间，当 accept 为 video | media 时生效，单位秒。
   */
  maxDuration: number
  /**
   * 使用前置或者后置相机，当 accept 为 video | media 时生效，可选值为：back｜front。
   */
  camera: UploadCameraType
}

export type UploadFileItem = {
  [key: string]: any
  // 	当前上传文件在列表中的唯一标识
  uid: number
  // 缩略图地址
  thumb?: string
  // 当前文件名称，仅h5支持
  name?: string
  // 上传状态。若自定义了status-key，应取对应字段
  status?: UploadStatusType
  // 文件大小
  size?: number
  // 上传图片/视频的本地地址
  url: string
  // 上传进度
  percent?: number
  // 后端返回的内容，可能是对象，也可能是字符串
  response?: string | Record<string, any>
}

export interface ChooseFile {
  path: string // 上传临时地址
  size?: number // 上传大小
  name?: string // 当前文件名称，仅h5支持
  type: 'image' | 'video' | 'file' // 上传类型
  duration?: number // 上传时间
  thumb?: string // 缩略图地址
}

export type UploadSourceType = 'album' | 'camera'
export type UploadSizeType = 'original' | 'compressed'
export type UploadFileType = 'image' | 'video' | 'media' | 'all' | 'file'
export type UploadCameraType = 'front' | 'back'
export type UploadStatusType = 'pending' | 'loading' | 'success' | 'fail'

export type UploadBeforePreviewOption = {
  file: UploadFileItem
  index: number
  imgList: string[]
  fileList: UploadFileItem[]
  resolve: (isPass: boolean) => void
}
export type UploadBeforePreview = (option: UploadBeforePreviewOption) => void

export type UploadOnPreviewFailOption = {
  index: number
  imgList: string[]
}
export type UploadOnPreviewFail = (option: UploadOnPreviewFailOption) => void

export type UploadBeforeRemoveOption = {
  file: UploadFileItem
  index: number
  fileList: UploadFileItem[]
  resolve: (isPass: boolean) => void
}
export type UploadBeforeRemove = (option: UploadBeforeRemoveOption) => void

export type UploadBeforeChooseOption = {
  fileList: UploadFileItem[]
  resolve: (isPass: boolean) => void
}
export type UploadBeforeChoose = (option: UploadBeforeChooseOption) => void

export type UploadBeforeUploadOption = {
  files: Record<string, any>[]
  fileList: UploadFileItem[]
  resolve: (isPass: boolean) => void
}
export type UploadBeforeUpload = (options: UploadBeforeUploadOption) => void

export type UploadFormData = Record<string, any>

export type UploadBuildFormDataOption = {
  file: UploadFileItem
  formData: UploadFormData
  resolve: (formData: Record<string, any>) => void
}
export type UploadBuildFormData = (options: UploadBuildFormDataOption) => void

export type UploadFile = Partial<UploadFileItem> & { url: string }

export type UploadMethod = (
  uploadFile: UploadFileItem,
  formData: UploadFormData,
  options: {
    action: string
    header: Record<string, any>
    name: string
    fileName: string
    fileType: 'image' | 'video' | 'audio'
    statusCode: number
    onSuccess: (res: UniApp.UploadFileSuccessCallbackResult, file: UploadFileItem, formData: UploadFormData) => void
    onError: (res: UniApp.GeneralCallbackResult, file: UploadFileItem, formData: UploadFormData) => void
    onProgress: (res: UniApp.OnProgressUpdateResult, file: UploadFileItem) => void
  }
) => void | Promise<void>

export const uploadProps = {
  ...baseProps,
  /**
   * 上传的文件列表,例如:[{name:'food.jpg',url:'https://xxx.cdn.com/xxx.jpg'}]
   * 类型：array
   * 默认值：[]
   */
  fileList: makeArrayProp<UploadFile>(),
  /**
   * 必选参数，上传的地址
   * 类型：string
   * 默认值：''
   */
  action: makeStringProp(''),
  /**
   * 设置上传的请求头部
   * 类型：object
   * 默认值：{}
   */
  header: { type: Object as PropType<Record<string, any>>, default: () => ({}) },
  /**
   * 是否支持多选文件
   * 类型：boolean
   * 默认值：false
   */
  multiple: makeBooleanProp(false),
  /**
   * 是否禁用
   * 类型：boolean
   * 默认值：false
   */
  disabled: makeBooleanProp(false),
  /**
   * 最大允许上传个数
   * 类型：number
   * 默认值：无
   */
  limit: Number,
  /**
   * 限制上传个数的情况下，是否展示当前上传的个数
   * 类型：boolean
   * 默认值：true
   */
  showLimitNum: makeBooleanProp(true),
  /**
   * 文件大小限制，单位为byte
   * 类型：number
   * 默认值：Number.MAX_VALUE
   */
  maxSize: makeNumberProp(Number.MAX_VALUE),
  /**
   * 选择图片的来源，chooseImage接口详细参数，查看官方手册
   * 类型：array
   * 默认值：['album','camera']
   */
  sourceType: {
    type: Array as PropType<UploadSourceType[]>,
    default: () => ['album', 'camera']
  },
  /**
   * 所选的图片的尺寸，chooseImage接口详细参数，查看官方手册
   * 类型：array
   * 默认值：['original','compressed']
   */
  sizeType: {
    type: Array as PropType<UploadSizeType[]>,
    // #ifndef MP-DINGTALK
    default: () => ['original', 'compressed']
    // #endif
  },
  /**
   * 文件对应的key，开发者在服务端可以通过这个key获取文件的二进制内容，uploadFile接口详细参数，查看官方手册
   * 类型：string
   * 默认值：'file'
   */
  name: makeStringProp('file'),
  /**
   * HTTP请求中其他额外的formdata，uploadFile接口详细参数，查看官方手册
   * 类型：object
   * 默认值：{}
   */
  formData: { type: Object as PropType<UploadFormData>, default: () => {} },
  /**
   * 预览失败执行操作
   * 类型：function({index,imgList})
   * 默认值：-
   */
  onPreviewFail: Function as PropType<UploadOnPreviewFail>,
  /**
   * 上传文件之前的钩子，参数为上传的文件和文件列表，若返回false或者返回Promise且被reject，则停止上传。
   * 类型：function({files,fileList,resolve})
   * 默认值：-
   */
  beforeUpload: Function as PropType<UploadBeforeUpload>,
  /**
   * 选择图片之前的钩子，参数为文件列表，若返回false或者返回Promise且被reject，则停止上传。
   * 类型：function({fileList,resolve})
   * 默认值：-
   */
  beforeChoose: Function as PropType<UploadBeforeChoose>,
  /**
   * 删除文件之前的钩子，参数为要删除的文件和文件列表，若返回false或者返回Promise且被reject，则停止上传。
   * 类型：function({file,fileList,resolve})
   * 默认值：-
   */
  beforeRemove: Function as PropType<UploadBeforeRemove>,
  /**
   * 图片预览前的钩子，参数为预览的图片下标和图片列表，若返回false或者返回Promise且被reject，则停止上传。
   * 类型：function({index,imgList,resolve})
   * 默认值：-
   */
  beforePreview: Function as PropType<UploadBeforePreview>,
  /**
   * 构建上传formData的钩子，参数为上传的文件、待处理的formData，返回值为处理后的formData，若返回false或者返回Promise且被reject，则停止上传。
   * 类型：function({file,formData,resolve})
   * 默认值：-
   * 最低版本：0.1.61
   */
  buildFormData: Function as PropType<UploadBuildFormData>,
  /**
   * 加载中图标类型
   * 类型：string
   * 默认值：'ring'
   */
  loadingType: makeStringProp<LoadingType>('ring'),
  /**
   * 加载中图标颜色
   * 类型：string
   * 默认值：'#ffffff'
   */
  loadingColor: makeStringProp('#ffffff'),
  /**
   * 文件类型，可选值：'image' | 'video' | 'media' | 'all' | 'file'
   * 默认值：image
   * 描述：'media'表示同时支持'image'和'video'，'file'表示支持除'image'和'video'外的所有文件类型，'all'标识支持全部类型文件
   * 'media'和'file'仅微信支持，'all'仅微信和H5支持
   */
  accept: makeStringProp<UploadFileType>('image'),
  /**
   * file 数据结构中，status 对应的 key
   * 类型：string
   * 默认值：'status'
   */
  statusKey: makeStringProp('status'),
  /**
   * 加载中图标尺寸
   * 类型：string
   * 默认值：'24px'
   */
  loadingSize: makeStringProp('24px'),
  /**
   * 是否压缩视频，当 accept 为 video 时生效。
   * 类型：boolean
   * 默认值：true
   */
  compressed: makeBooleanProp(true),
  /**
   * 拍摄视频最长拍摄时间，当 accept 为 video | media 时生效，单位秒。
   * 类型：number
   * 默认值：60
   */
  maxDuration: makeNumberProp(60),
  /**
   * 使用前置或者后置相机，当 accept 为 video | media 时生效，可选值为：back｜front。
   * 类型：UploadCameraType
   * 默认值：'back'
   */
  camera: makeStringProp<UploadCameraType>('back'),
  /**
   * 预览图片的mode属性
   */
  imageMode: makeStringProp<ImageMode>('aspectFit'),
  /**
   * 接口响应的成功状态（statusCode）值
   */
  successStatus: makeNumberProp(200),
  /**
   * 自定义上传按钮样式
   * 类型：string
   */
  customEvokeClass: makeStringProp(''),
  /**
   * 自定义预览图片列表样式
   * 类型：string
   */
  customPreviewClass: makeStringProp(''),
  /**
   * 是否选择文件后自动上传
   * 类型：boolean
   */
  autoUpload: makeBooleanProp(true),
  /**
   * 点击已上传时是否可以重新上传
   * 类型：boolean
   * 默认值：false
   */
  reupload: makeBooleanProp(false),
  /**
   * 自定义上传文件的请求方法
   * 类型：UploadMethod
   * 默认值：-
   */
  uploadMethod: Function as PropType<UploadMethod>
}

export type UploadProps = ExtractPropTypes<typeof uploadProps>

export type UploadExpose = {
  /**
   * 手动触发上传
   */
  submit: () => void
}

export type UploadErrorEvent = {
  error: any
  file: UploadFileItem
  formData: UploadFormData
}

export type UploadChangeEvent = {
  fileList: UploadFileItem[]
}

export type UploadSuccessEvent = {
  file: UploadFileItem
  fileList: UploadFileItem[]
  formData: UploadFormData
}

export type UploadProgressEvent = {
  response: UniApp.OnProgressUpdateResult
  file: UploadFileItem
}

export type UploadOversizeEvent = {
  file: ChooseFile
}

export type UploadRemoveEvent = {
  file: UploadFileItem
}

export type UploadInstance = ComponentPublicInstance<UploadProps, UploadExpose>
