import { ElUpload, ElIcon, ElProgress } from 'element-plus'
import { SuccessFilled, CircleCloseFilled, Paperclip } from '@element-plus/icons-vue'
import './index.less'
import { toRefs, defineComponent, computed } from 'vue'
import CipButton from '@cip/components/cip-button'

export default defineComponent({
  name: 'CipUpload',
  props: {
    uploadFile: { // 文件上传
      type: Function,
      default: (info) => {}
    },
    accept: { // 可选择文件类型控制
      type: String,
      default: '' // 所有
    },
    beforeRemove: Function, // 删除文件之前的钩子
    onRemove: Function, // 文件列表移除文件时的钩子
    beforeUpload: Function, // 上传文件之前的钩子
    onError: Function, // 文件上传失败时的钩子
    onSuccess: Function, // 文件上传成功时的钩子
    onPreview: Function, // 点击文件列表中已上传的文件时的钩子
    fileList: { type: Array, default: () => [] }, // 默认上传文件
    multiple: Boolean, // 是否允许多个
    disabled: Boolean, // 禁用状态
    drag: Boolean, // 是否拖拽上传
    action: String, // 上传地址
    limit: Number, // 上传数量限制
    showFileList: { // 是否展示默认，后期考虑不用默认的
      type: Boolean,
      default: true
    },
    itemStyle: { // 文件列表的行内样式
      type: Object,
      default: () => ({})
    },
    listType: { // 展示形式
      type: String,
      default: 'text'
    }
  },
  emits: ['update:fileList'],
  inheritAttrs: false,
  setup (props, { slots, emit, attrs }) {
    const { fileList } = toRefs(props)
    const uploadDisabled = computed(() => props.disabled || props.limit <= fileList.value.length)
    function genDefault () {
      if (props.drag) { // 拖拽
        return <div class="cip-upload-drag-trigger">
          <i class="el-icon-upload" style="font-size: 50px"></i>
          <div>
            点击或将文件拖拽到这里上传
          </div>
          <div class={'el-upload__tip'}>{slots.tip?.()}</div>
        </div>
      } else if (props.listType === 'picture-card') { // 缩略图
        return uploadDisabled.value || <div class="cip-upload-picture-trigger" style={ props.itemStyle }>
          <i class="el-icon-plus"></i>
          <div>上传</div>
        </div>
      } else { // 默认
        return <CipButton buttonType="upload" disabled={uploadDisabled.value}></CipButton>
      }
    }

    async function deleteItem (index) {
      const uploadFiles = fileList.value.concat()
      const file = uploadFiles.splice(index, 1)[0]
      let flag
      try {
        flag = await props.beforeRemove?.(file, uploadFiles)
      } catch (err) {
        flag = props.beforeRemove?.(file, uploadFiles)
      }
      // 如果beforeRemove函数不存在 或者 返回值为true
      if (flag || !props.beforeRemove) {
        emit('update:fileList', uploadFiles)
        props.onRemove?.(file, uploadFiles)
      }
    }
    function genUpload (slots) {
      return <ElUpload
        {...attrs}
        fileList={props.fileList}
        onUpdate:fileList={list => emit('update:fileList', list)}
        class={'cip-upload-content'}
        action={props.action}
        httpRequest={httpRequest}
        beforeUpload={props.beforeUpload}
        multiple={props.multiple}
        disabled={props.disabled}
        accept={props.accept}
        drag={props.drag}
        show-file-list={false}
      >
        {{
          // 1. default或者trigger存在，不渲染默认；渲染对应的default或者trigger；trigger在下面一行渲染
          default: () => slots.default?.() || (slots.trigger ? undefined : genDefault()),
          // 这个trigger要这么写，如果给它赋值函数，会出bug
          trigger: slots.trigger ? () => slots.trigger() : undefined,
          tip: () => props.drag || <div class={'el-upload__tip'} style={{ marginLeft: props.listType === 'picture-card' ? '0' : '12px' }}>{slots.tip?.()}</div>
        }}
      </ElUpload>
    }

    function httpRequest (opts) {
      function setStatus (status, uploadFile) {
        const uid = opts.file.uid
        const index = fileList.value.findIndex(file => file.uid === uid)
        if (status === 'error') {
          Object.assign(fileList.value[index], { status, opts })
        } else if (status === 'success') {
          Object.assign(fileList.value[index], { status, ...uploadFile, opts: undefined })
        }
        emit('update:fileList', fileList.value.concat())
      }

      props.uploadFile(opts)?.then(file => {
        setStatus('success', file)
        props.onSuccess?.(file, opts.file, fileList.value.concat())
      }).catch((err) => {
        setStatus('error')
        props.onError?.(err, opts.file, fileList.value.concat())
      })
    }

    function reUpload (item) {
      item.status = 'ready'
      httpRequest(item.opts)
    }

    function genItems () {
      return <>
        {genUpload(slots)}
        { fileList.value?.length === 0
          ? undefined
          : <ul class="el-upload-list el-upload-list--text">
          {
            fileList.value.map((item, index) => <li style={ props.itemStyle } class={['el-upload-list__item', `is-${item.status}`]} key={item.name + index} onClick={() => props.onPreview?.(item)}>
              <div class="el-upload-list__item-name">
                <ElIcon><Paperclip /></ElIcon>
                <span class="el-upload-list__item-file-name">{item.name}</span>
              </div>
              <div class="el-upload-list__item-label">
                {item.status === 'error' && <i class="el-icon-refresh-right" onClick={() => reUpload(item)}></i>}
                <ElIcon class="upload--success"><SuccessFilled /></ElIcon>
                <i class="el-icon-close upload--close" onClick={() => deleteItem(index)}></i>
              </div>
              {item.status === 'ready' && <ElProgress stroke-width={2} indeterminate percentage={72} />}
            </li>)
          }
        </ul>}
      </>
    }

    function genPictureCard () {
      return <>
        <ul class="el-upload-list el-upload-list--picture-card">
          {
            fileList.value.map((item, index) => <li class="el-upload-list__item" style={ props.itemStyle } key={item.name + index} onClick={() => props.onPreview?.(item)}>
              {item.status === 'success' && <img src={item.url} />}
              <div class="upload--close">
                <ElIcon onClick={() => deleteItem(index)}><CircleCloseFilled /></ElIcon>
              </div>
              {item.status === 'ready' && <ElProgress stroke-width={4} style="top:50%;width:80%" indeterminate percentage={72} />}
            </li>)
          }
          {uploadDisabled.value || <li class="el-upload el-upload--picture-card" style={ props.itemStyle }>{genUpload({ trigger: slots.trigger, default: slots.default })}</li>}
        </ul>
        <div class={'el-upload__tip'}>{slots.tip?.()}</div>
      </>
    }

    function genPicture () {
      return <>
        {genUpload(slots)}
        { fileList.value?.length === 0
          ? undefined
          : <ul class="el-upload-list el-upload-list--picture">
          {
            fileList.value.map((item, index) => <li key={item.name + index} onClick={() => props.onPreview?.(item)}>
              {['jpeg', 'jpg', 'png', 'gif', 'svg'].includes(item.name?.split('.').pop())
                ? <img src={item.url} />
                : <i class="picture-icon"></i>}
              <div class="picture-info">
                <div class="item-name">{item.name}</div>
                <span class="item-size">{item.size}</span>
              </div>
              <div class="upload--close">
                <ElIcon onClick={() => deleteItem(index)}><CircleCloseFilled /></ElIcon>
              </div>
            </li>)
          }
        </ul>}
      </>
    }

    const renderTypeMap = {
      text: genItems,
      'picture-card': genPictureCard,
      picture: genPicture
    }

    return () => <div class="cip-upload">
      { props.showFileList ? (renderTypeMap[props.listType]?.()) : genUpload(slots) }
    </div>
  }
})
