<template>
  <ul class="file-list" v-if="readonly">
    <accessory-item
      :key="accessory.accessoryId"
      v-for="accessory in accessoryList"
      :accessory="accessory"
      :disabled="true"
      @on-download="downloadFile"
    ></accessory-item>
  </ul>
  <el-upload
    v-else
    ref="uploadRef"
    :action="uploadUrl"
    :data="uploadData"
    :accept="accept"
    :auto-upload="true"
    :multiple="true"
    :disabled="isDisabled"
    :limit="uploadRemain"
    :show-file-list="false"
    v-model:file-list="uploadingFiles"
    :on-change="onUploadChange"
    class="uploader"
  >
    <template #trigger>
      <el-button size="small" type="primary" :disabled="isDisabled" class="uploader-add">
        <el-icon>
          <Plus />
        </el-icon>
        <span>添加文件 {{ uploadingText }}</span>
      </el-button>
    </template>
    <ul class="file-list cacp-mt-m" v-if="accessoryList.length > 0 || uploadingFiles.length > 0">
      <accessory-item
        :key="accessory.accessoryId"
        v-for="accessory in accessoryList"
        :accessory="accessory"
        @on-delete="onDelete"
        @on-sort="onSort"
        @on-download="downloadFile"
        :disabled="props.disabled"
      ></accessory-item>
      <upload-file-item
        v-for="file in uploadingFiles"
        :key="file.uid"
        :file="file"
        @on-abort="onAbort"
        :disabled="props.disabled"
      ></upload-file-item>
    </ul>
  </el-upload>
</template>
<script setup lang="ts">
import { ref, computed, provide } from 'vue'
import {
  type UploadFile,
  type UploadFiles,
  type UploadUserFile,
  type UploadProps,
  type UploadContentInstance,
  ElMessage,
  ElMessageBox
} from 'element-plus'
import { max, min } from 'lodash-es'
import { accessoryInjectionKey, SortOrder } from './constants'
import { SuccessResultCode, type Result, type Accessory, type AccessoryDirection, type UploadData } from '@cacp/ui'
import UploadFileItem from './UploadFileItem.vue'
import AccessoryItem from './AccessoryItem.vue'
import * as apis from '@/apis/accessory'

const props = withDefaults(
  defineProps<{
    modelValue?: Array<Accessory>
    category: string
    bizId?: string
    bizTag?: string
    relId?: string
    persisted?: boolean
    previewable?: boolean
    readonly?: boolean
    limit?: number
    accept?: string
    tooltip?: string
    ellipsis?: number
    direction?: AccessoryDirection
    disabled?: boolean
  }>(),
  {
    modelValue: () => [],
    previewable: true,
    persisted: false,
    readonly: false,
    limit: 0,
    direction: 'horizontal',
    disabled: false
  }
)
const emits = defineEmits<{
  (e: 'update:modelValue', value: Array<Accessory>): void
}>()

const uploadRef = ref<UploadContentInstance>()

const uploadUrl = apis.getUploadUrl()
const uploadingFiles = ref<Array<UploadUserFile>>([])
const uploadData = ref<UploadData>({
  category: props.category,
  bizId: props.bizId ?? '',
  bizTag: props.bizTag ?? '',
  relId: props.relId ?? '',
  fileName: '',
  persisted: props.persisted
})
const downloadingList = ref<Array<string>>([])

const isDisabled = computed<boolean>(() => {
  return props.disabled || !canUpload.value
})

const modelList = computed<Array<Accessory>>(() => {
  return props.modelValue ?? []
})
// ref<Array<Accessory>>(_.cloneDeep(props.modelValue))
const accessoryList = computed<Array<Accessory>>(() => {
  if (props.bizTag) {
    return modelList.value
      .filter((a) => !a.deleted && a.bizTag === props.bizTag)
      .sort((a, b) => a.sortOrder - b.sortOrder)
  }
  return modelList.value.filter((a) => !a.deleted).sort((a, b) => a.sortOrder - b.sortOrder)
})
const uploadingText = computed<string>(() => {
  return props.limit ? `(${accessoryList.value.length + uploadingFiles.value.length}/${props.limit})` : ''
})
const canUpload = computed<boolean>(() => {
  return !props.limit || (!!props.limit && accessoryList.value.length + uploadingFiles.value.length < props.limit)
})
const uploadRemain = computed<number | undefined>(() => {
  if (!props.limit) {
    return undefined
  }
  const count = props.limit - accessoryList.value.length
  return count < 1 ? 0 : count
})

async function downloadFile(accessory: Accessory): Promise<void> {
  downloadingList.value.push(accessory.accessoryId)
  await apis.downloadFile(accessory.accessoryId, accessory.fileName)
  const idx = downloadingList.value.indexOf(accessory.accessoryId)
  downloadingList.value.splice(idx, 1)
}

async function onDelete(accessory: Accessory, isTemp: boolean): Promise<void> {
  if (isTemp) {
    accessory.deleted = true
  } else {
    try {
      await ElMessageBox.confirm('删除该文件，是否继续？', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      })
      accessory.deleted = true
    } catch {
      // 捕获点击取消时候的错误，避免抛出
    }
  }
}

function onSort(accessory: Accessory, sortOrder: SortOrder) {
  if (sortOrder === SortOrder.left) {
    onSortLeft(accessory)
  } else {
    onSortRight(accessory)
  }
}

function onAbort(file: UploadUserFile): void {
  uploadRef.value.abort(file as UploadFile)
  uploadingFiles.value = uploadingFiles.value.filter((uploadFile) => uploadFile !== file)
}

const onUploadChange: UploadProps['onChange'] = (file: UploadFile, files: UploadFiles): void => {
  if (file.status === 'ready') {
    uploadData.value.fileName = file.name
  } else if (file.status === 'success' || file.status === 'fail') {
    uploadData.value.fileName = ''
    const uindex = uploadingFiles.value.findIndex((f) => f.uid === file.uid)
    if (uindex > -1) {
      uploadingFiles.value.splice(uindex, 1)
    }
    if (file.status === 'success' && file.response) {
      const res = file.response as Result<Accessory>
      if (res.code === SuccessResultCode && res.data) {
        const accessory: Accessory = res.data
        const sortOrder = max(modelList.value.map((a) => a.sortOrder))
        accessory.sortOrder = (sortOrder ?? 0) + 1
        modelList.value.push(accessory)
        emits('update:modelValue', modelList.value)
      } else {
        ElMessage.error({
          message: `文件【${file.name}】上传失败:${res.message}`,
          showClose: true
        })
      }
    } else {
      ElMessage.error({
        message: `文件【${file.name}】上传失败:${file.status}`,
        showClose: true
      })
    }
  }
}

function onSortLeft(accessory: Accessory): void {
  const sortOrder = accessory.sortOrder
  const maxValue =
    max(accessoryList.value.filter((a) => !a.deleted && a.sortOrder < sortOrder).map((a) => a.sortOrder)) ?? 0
  if (maxValue < 1) {
    return
  }
  for (const item of accessoryList.value.filter((a) => a.sortOrder === maxValue)) {
    item.sortOrder = sortOrder
  }
  accessory.sortOrder = maxValue
  emits('update:modelValue', modelList.value)
}

function onSortRight(accessory: Accessory): void {
  const sortOrder = accessory.sortOrder
  const minValue =
    min(accessoryList.value.filter((a) => !a.deleted && a.sortOrder > sortOrder).map((a) => a.sortOrder)) ?? 0
  console.log(minValue)
  if (minValue < 1) {
    return
  }
  for (const item of accessoryList.value.filter((a) => a.sortOrder === minValue)) {
    item.sortOrder = sortOrder
  }
  accessory.sortOrder = minValue
  emits('update:modelValue', modelList.value)
}

provide(accessoryInjectionKey, {
  downloadingList,
  accessoryList
})
</script>

<style lang="less" scoped>
.uploader {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  &-tag {
    &-inner {
      a {
        cursor: pointer;

        &:hover {
          text-decoration: underline;
        }
      }
    }
  }
}
.file-list {
  width: 100%;
}
</style>
