<template>
<div class="upload-container">
  <el-upload
    action="#"
    :headers="headers"
    :file-list="uploadFileList"
    :accept="realAccept"
    :before-upload="beforeUpload"
    :on-success="handleSuccess"
    :on-error="handleError"
    :on-remove="handleRemove"
    :on-exceed="handleExceed"
    :http-request="handlePostFile"
    :list-type="listType"
    :auto-upload="autoUpload"
    :limit="limit"
    :show-file-list="false"
    :multiple="multiple"
  >
    <slot name="trigger">
      <el-button :type="buttonType" :bg="false" :disabled="disabled">
        <el-icon v-if="showButtonIcon"><Upload /></el-icon>
        {{buttonText}}
      </el-button>
    </slot>
    <template #tip v-if="showTips">
      <div class="el-upload__tip">
        支持扩展名：{{ fileExtensions }}
        <span v-if="maxSize > 0">，单个文件大小不超过 {{ formatFileSize(maxSize) }}</span>
      </div>
    </template>
  </el-upload>

  <!-- 已上传文件列表 -->
  <div v-if="processedFileList.length > 0" class="uploaded-files-section">
    <div class="files-header">
      <span class="files-title">已上传文件 ({{ processedFileList.length }})</span>
    </div>
    <div class="uploaded-files">
      <div v-for="file in processedFileList" :key="file.uid || file.url" class="custom-file-item">
        <div class="file-info">
          <!-- 文件图标或预览 -->
          <div class="file-preview" @click="handlePreview(file)">
            <el-image
              v-if="isImage(file)"
              :src="file.url"
              fit="cover"
              style="width: 40px; height: 40px; border-radius: 4px; cursor: pointer;"
              :preview-src-list="[]"
              hide-on-click-modal
            />
            <el-icon v-else-if="isVideo(file)" size="40" class="video-icon" style="color: #409EFF;">
              <VideoPlay />
            </el-icon>
            <el-icon v-else-if="isDocumentFile(file)" size="40" class="doc-icon">
              <Document />
            </el-icon>
            <el-icon v-else size="40" class="file-icon">
              <Document />
            </el-icon>
          </div>

          <!-- 文件名称和操作 -->
          <div class="file-content">
            <div class="file-name" :title="file.name">
              {{ file.name }}
            </div>
            <div class="file-actions">
              <div
                v-if="isImage(file)" 
                class="detail-btn"
                @click="openImagePreview(file)"
              >
                预览
              </div>
              <div
                v-if="isVideo(file)" 
                class="detail-btn"
                @click="openVideoPreview(file)"
              >
                播放
              </div>
              <div
                v-if="isDocumentFile(file)" 
                class="detail-btn"
                @click="openDocumentPreview(file)"
              >
                查看
              </div>
              <div
                class="detail-btn"
                @click="downloadFile(file)"
              >
                下载
              </div>
              <div 
                v-if="detailFlag == false"
                class="delete-btn"
                @click="handleRemove(file)"
              >
                删除
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <!-- 图片预览对话框 -->
  <el-dialog
    v-model="imagePreviewVisible"
    title="图片预览"
    width="80%"
    :before-close="closeImagePreview"
    append-to-body
  >
    <div class="image-preview-container">
      <el-image
        :src="currentPreviewImage"
        fit="cover"
        style="width: 100%;"
        :preview-src-list="[]"
        hide-on-click-modal
      />
    </div>
  </el-dialog>

  <!-- 视频预览对话框 -->
  <el-dialog
    v-model="videoPreviewVisible"
    title="视频播放"
    width="80%"
    :before-close="closeVideoPreview"
    destroy-on-close
    append-to-body
  >
    <div class="video-preview-container">
      <video
        :src="currentPreviewVideo"
        controls
        style="width: 100%; max-height: 70vh;"
        @error="handleVideoError"
      >
        您的浏览器不支持视频播放
      </video>
    </div>
  </el-dialog>

  <!-- 文档预览对话框 -->
  <el-dialog
    v-model="documentPreviewVisible"
    title="文档预览"
    width="90%"
    :before-close="closeDocumentPreview"
    append-to-body
    center
  >
    <div class="document-preview-container">
      <iframe
        :src="currentPreviewDocument"
        width="100%"
        height="600px"
        frameborder="0"
      ></iframe>
    </div>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="closeDocumentPreview">关闭</el-button>
        <el-button type="primary" @click="openDocumentInNewWindow">在新窗口打开</el-button>
      </span>
    </template>
  </el-dialog>
</div>
</template>

<script setup>
import { Upload, Document, VideoPlay } from '@element-plus/icons-vue'
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import request from '@/config/axios'
import SparkMD5 from 'spark-md5'
import { getAccessToken } from '@/utils/auth'
import { buildFileUrl } from '@/utils'

const props = defineProps({
  apiUrl: { type: String, required: true },
  chunkSize: { type: Number, default: 5 },
  accept: { type: String, default: '' },
  headers: { type: Object, default: () => ({}) },
  fileList: { type: Array, default: () => [] },
  autoUpload: { type: Boolean, default: true },
  listType: { type: String, default: 'text' },
  showTips: { type: Boolean, default: true },
  buttonText: { type: String, default: '上传文件' },
  buttonType: { type: String, default: 'default' },
  showButtonIcon: { type: Boolean, default: true },
  limit: { type: Number, default: 0 },
  disabled: { type: Boolean, default: false },
  detailFlag: { type: Boolean, default: false },
  maxSize: { type: Number, default: 0 },
  multiple: { type: Boolean, default: false }
})

const emit = defineEmits(['update:fileList', 'success', 'error'])

// 预览相关状态
const imagePreviewVisible = ref(false)
const videoPreviewVisible = ref(false)
const documentPreviewVisible = ref(false)
const currentPreviewImage = ref('')
const currentPreviewVideo = ref('')
const currentPreviewDocument = ref('')

// 处理后的文件列表
const processedFileList = computed(() => {
  return (props.fileList || [])?.map(file => ({
    ...file,
    url: file.url ? buildFileUrl(file.url) : buildFileUrl(file.name || `${file.path || ''}${file.name || ''}`)
  }))
})
const uploadFileList = computed(() => {
  return processedFileList.value.map(file => ({
    name: file.name,
    url: file.url,
    uid: file.uid,
    status: 'success'
  }))
})
const realAccept = computed(() => {
  return props.accept || '*'
})

const fileExtensions = computed(() => {
  return props.accept || '任意类型'
})
const handleExceed = (files, fileList) => {
  ElMessage.warning(`最多只能上传 ${props.limit} 个文件，请删除后再上传`)
}
const formatFileSize = (bytes) => {
  if (bytes === 0) return '0 B'
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

// 判断是否为图片文件
const isImage = (file) => {
  const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']
  const extension = (file.name || '').split('.').pop()?.toLowerCase()
  return imageTypes.includes(extension)
}

// 判断是否为视频文件
const isVideo = (file) => {
  const videoTypes = ['mp4', 'webm', 'ogg', 'mov', 'avi', 'flv', 'wmv']
  const extension = (file.name || '').split('.').pop()?.toLowerCase()
  return videoTypes.includes(extension)
}

// 判断是否为文档文件
const isDocumentFile = (file) => {
  const documentTypes = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt']
  const extension = (file.name || '').split('.').pop()?.toLowerCase()
  return documentTypes.includes(extension)
}

// 打开图片预览
const openImagePreview = (file) => {
  currentPreviewImage.value = file.url
  imagePreviewVisible.value = true
}

// 关闭图片预览
const closeImagePreview = () => {
  imagePreviewVisible.value = false
  currentPreviewImage.value = ''
}

// 打开视频预览
const openVideoPreview = (file) => {
  currentPreviewVideo.value = file.url
  videoPreviewVisible.value = true
}

// 关闭视频预览
const closeVideoPreview = () => {
  videoPreviewVisible.value = false
  currentPreviewVideo.value = ''
}

// 视频加载错误处理
const handleVideoError = () => {
  console.log('视频加载失败，请检查文件格式或网络连接')
}

// 打开文档预览
const openDocumentPreview = (file) => {
  const extension = (file.name || '').split('.').pop()?.toLowerCase()
  
  if (extension === 'pdf') {
    currentPreviewDocument.value = file.url
  } else {
    currentPreviewDocument.value = `https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(file.url)}`
  }
  
  documentPreviewVisible.value = true
}

// 关闭文档预览
const closeDocumentPreview = () => {
  documentPreviewVisible.value = false
  currentPreviewDocument.value = ''
}

// 在新窗口打开文档
const openDocumentInNewWindow = () => {
  if (currentPreviewDocument.value) {
    window.open(currentPreviewDocument.value, '_blank')
  }
}

// 下载文件
const downloadFile = (file) => {
  if (isImage(file)) {
    window.open(file.url, '_blank')
  } else {
    const link = document.createElement('a')
    link.href = file.url
    link.download = file.name
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
  }
}

// 处理文件预览
const handlePreview = (file) => {
  if (isImage(file)) {
    openImagePreview(file)
  } else if (isVideo(file)) {
    openVideoPreview(file)
  } else if (isDocumentFile(file)) {
    openDocumentPreview(file)
  }
}

// 文件上传前校验
const beforeUpload = (file) => {
  // 手动检查 limit
  if (props.limit > 0 && processedFileList.value.length >= props.limit) {
    ElMessage.warning(`最多只能上传 ${props.limit} 个文件`)
    return false
  }

  const lastName = (file.name || '').match(/\.([^.]+)$/)?.[0] || null
  if (realAccept.value !== '*' && !realAccept.value.includes(lastName)) {
    ElMessage.error('只能上传' + realAccept.value)
    return false
  }
  
  if (props.maxSize > 0 && file.size > props.maxSize) {
    ElMessage.error(`文件大小不能超过 ${formatFileSize(props.maxSize)}`)
    return false
  }
  
  return true
}


const activeUploads = ref(false)

// 文件上传方法
const handlePostFile = async (options) => {
  const { file, onProgress, onSuccess, onError } = options
  try {
    activeUploads.value = true
    const formData = new FormData()
    formData.append('file', file)

    const result = await request.post({
      url: props.apiUrl,
      data: formData,
      headers: {
        authorization: 'Bearer ' + getAccessToken(),
        'Content-Type': 'multipart/form-data',
        accept: '*/*',
        ...props.headers
      },
      onUploadProgress: (progressEvent) => {
        const percent = Math.round((progressEvent.loaded / file.size) * 100)
        onProgress({ percent })
      }
    })
    if(result) {
      const fileObj = {
        ...file,
        name: file.name,
        status: 'success',
        url: result,
        uid: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
      }
      updateFileList(fileObj)
      onSuccess(result)
      emit('success', result, file)
    }
  } catch (err) {
    onError(err)
    emit('error', err, file)
  } finally {
    activeUploads.value = false
  }
}

const handleSuccess = (response, file) => {
  activeUploads.value = false
}

const handleError = (err) => {
  activeUploads.value = false
  ElMessage.error('上传失败')
}

const handleRemove = async (file) => {
  if (file.id) {
    try {
      await request.delete(`${props.apiUrl}/${file.id}`)
      updateFileList(file, true)
      await nextTick()
      // 强制触发组件更新
      ElMessage.success('删除成功')
    } catch (err) {
      ElMessage.error('删除失败')
    }
  } else {
    updateFileList(file, true)
    await nextTick()
  }
}

const updateFileList = (file, isRemove = false) => {
  const newList = [...props.fileList]
  
  // 优先使用 uid 查找，避免误判
  const index = newList.findIndex(f => {
    if (file.uid && f.uid) return f.uid === file.uid
    if (file.url && f.url) return f.url === file.url
    return f.name === file.name
  })

  if (isRemove && index > -1) {
    newList.splice(index, 1)
  } else if (!isRemove && index === -1) {
    newList.push(file)
  } else if (!isRemove && index > -1) {
    newList[index] = { ...newList[index], ...file }
  }

  emit('update:fileList', newList)
}

const handleBeforeUnload = (e) => {
  if (activeUploads.value) {
    e.preventDefault()
    e.returnValue = '文件正在上传中，确定要离开吗？'
    return '文件正在上传中，确定要离开吗？'
  }
}

onMounted(() => {
  window.addEventListener('beforeunload', handleBeforeUnload)
})

onBeforeUnmount(() => {
  window.removeEventListener('beforeunload', handleBeforeUnload)
})
</script>

<style scoped>
.upload-container {
  width: 100%;
}

.uploaded-files-section {
  margin-top: 16px;
}

.files-header {
  margin-bottom: 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid #e4e7ed;
}

.files-title {
  font-size: 14px;
  font-weight: 500;
  color: #303133;
}

.uploaded-files {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.custom-file-item {
  display: block;
  width: 100%;
  padding: 12px;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
  background-color: #fafafa;
  transition: all 0.3s ease;
}

.custom-file-item:hover {
  background-color: #f0f9ff;
  border-color: #409eff;
}

.file-info {
  display: flex;
  align-items: flex-start;
  width: 100%;
}

.file-preview {
  margin-right: 12px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.doc-icon {
  color: #2563eb;
  cursor: pointer;
}

.file-icon {
  color: #718096;
}

.file-content {
  flex: 1;
  min-width: 0;
}

.file-name {
  font-size: 14px;
  color: #303133;
  /* margin-bottom: 8px; */
  word-break: break-all;
  line-height: 1.4;
}

.file-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 15px;
}

.image-preview-container {
  text-align: center;
  padding: 20px;
}

.document-preview-container {
  width: 100%;
  height: 600px;
  border: 1px solid #e4e7ed;
  border-radius: 4px;
  overflow: hidden;
}

/* 隐藏默认的文件列表 */
:deep(.el-upload-list) {
  display: none;
}
.detail-btn {
  font-size: 12px;
  color: #015293;
  cursor: pointer;
}
.delete-btn {
  font-size: 12px;
  color: #F56c6c;
  cursor: pointer;
}
.video-icon {
  cursor: pointer;
  transition: transform 0.2s;
}

.video-icon:hover {
  transform: scale(1.1);
}

.video-preview-container {
  display: flex;
  justify-content: center;
  align-items: center;
  background: #000;
  border-radius: 4px;
  padding: 20px;
}
/* 响应式设计 */
@media (max-width: 768px) {
  .file-actions {
    margin-top: 4px;
  }
  
  .file-actions .el-button {
    padding: 4px 8px;
    font-size: 12px;
  }
}
</style>
