<template>
  <view class="upload-container" :class="containerClass">
    <!-- 上传区域 -->
    <view 
      class="upload-area" 
      :class="uploadAreaClass"
      @click="handleClick"
    >
      <!-- 拖拽上传 -->
      <view v-if="drag" class="upload-drag">
        <view class="drag-content">
          <image class="drag-icon" :src="dragIcon" mode="aspectFit"></image>
          <text class="drag-text">{{ dragText }}</text>
          <text class="drag-hint">{{ dragHint }}</text>
        </view>
      </view>
      
      <!-- 按钮上传 -->
      <view v-else class="upload-button">
        <button class="upload-btn" :class="buttonClass" :disabled="disabled">
          <text class="btn-text">{{ buttonText }}</text>
        </button>
        <text v-if="tip" class="upload-tip">{{ tip }}</text>
      </view>
    </view>
    
    <!-- 文件列表 -->
    <view v-if="showFileList && fileList.length > 0" class="file-list">
      <view 
        v-for="(file, index) in fileList" 
        :key="file.uid || index"
        class="file-item"
        :class="getFileItemClass(file)"
      >
        <!-- 文件图标 -->
        <view class="file-icon">
          <image 
            v-if="isImage(file)" 
            class="file-preview" 
            :src="file.url || file.path" 
            mode="aspectFill"
            @click="handlePreview(file, index)"
          ></image>
          <image 
            v-else 
            class="file-type-icon" 
            :src="getFileTypeIcon(file)" 
            mode="aspectFit"
          ></image>
        </view>
        
        <!-- 文件信息 -->
        <view class="file-info">
          <text class="file-name">{{ file.name }}</text>
          <text v-if="file.size" class="file-size">{{ formatFileSize(file.size) }}</text>
          
          <!-- 上传进度 -->
          <view v-if="file.status === 'uploading'" class="upload-progress">
            <view class="progress-bar">
              <view 
                class="progress-fill" 
                :style="{ width: `${file.percent || 0}%` }"
              ></view>
            </view>
            <text class="progress-text">{{ file.percent || 0 }}%</text>
          </view>
          
          <!-- 上传状态 -->
          <view v-if="file.status === 'error'" class="upload-error">
            <text class="error-text">{{ file.error || '上传失败' }}</text>
          </view>
        </view>
        
        <!-- 操作按钮 -->
        <view class="file-actions">
          <button 
            v-if="file.status === 'success' && !disabled" 
            class="action-btn preview-btn"
            @click="handlePreview(file, index)"
          >
            预览
          </button>
          <button 
            v-if="!disabled" 
            class="action-btn remove-btn"
            @click="handleRemove(file, index)"
          >
            删除
          </button>
          <button 
            v-if="file.status === 'error'" 
            class="action-btn retry-btn"
            @click="handleRetry(file, index)"
          >
            重试
          </button>
        </view>
      </view>
    </view>
    
    <!-- 上传限制提示 -->
    <view v-if="showLimit" class="upload-limit">
      <text class="limit-text">
        已上传 {{ fileList.length }} / {{ limit }} 个文件
      </text>
    </view>
  </view>
</template>

<script>
import { ref, computed, watch } from 'vue'
import { commonApi } from '@/common/api'

export default {
  name: 'Upload',
  props: {
    // 上传地址
    action: {
      type: String,
      default: ''
    },
    
    // 文件列表
    fileList: {
      type: Array,
      default: () => []
    },
    
    // 是否支持多选
    multiple: {
      type: Boolean,
      default: false
    },
    
    // 文件数量限制
    limit: {
      type: Number,
      default: 0
    },
    
    // 文件大小限制（MB）
    maxSize: {
      type: Number,
      default: 10
    },
    
    // 允许的文件类型
    accept: {
      type: String,
      default: '*'
    },
    
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false
    },
    
    // 是否显示文件列表
    showFileList: {
      type: Boolean,
      default: true
    },
    
    // 是否支持拖拽上传
    drag: {
      type: Boolean,
      default: false
    },
    
    // 按钮文本
    buttonText: {
      type: String,
      default: '选择文件'
    },
    
    // 拖拽文本
    dragText: {
      type: String,
      default: '将文件拖到此处'
    },
    
    // 拖拽提示
    dragHint: {
      type: String,
      default: '或点击选择文件'
    },
    
    // 拖拽图标
    dragIcon: {
      type: String,
      default: '/static/images/upload.png'
    },
    
    // 提示文本
    tip: {
      type: String,
      default: ''
    },
    
    // 上传前钩子
    beforeUpload: {
      type: Function,
      default: null
    },
    
    // 上传成功钩子
    onSuccess: {
      type: Function,
      default: null
    },
    
    // 上传失败钩子
    onError: {
      type: Function,
      default: null
    },
    
    // 上传进度钩子
    onProgress: {
      type: Function,
      default: null
    },
    
    // 文件移除钩子
    onRemove: {
      type: Function,
      default: null
    },
    
    // 文件预览钩子
    onPreview: {
      type: Function,
      default: null
    },
    
    // 自定义上传
    customRequest: {
      type: Function,
      default: null
    },
    
    // 额外的上传参数
    data: {
      type: Object,
      default: () => ({})
    },
    
    // 请求头
    headers: {
      type: Object,
      default: () => ({})
    },
    
    // 上传的文件字段名
    name: {
      type: String,
      default: 'file'
    },
    
    // 是否自动上传
    autoUpload: {
      type: Boolean,
      default: true
    }
  },
  
  emits: [
    'change', 
    'success', 
    'error', 
    'progress', 
    'remove', 
    'preview',
    'exceed'
  ],
  
  setup(props, { emit }) {
    // 响应式数据
    const uploading = ref(false)
    const dragOver = ref(false)
    
    // 计算属性
    const containerClass = computed(() => {
      const classes = []
      
      if (props.disabled) {
        classes.push('upload-disabled')
      }
      
      if (uploading.value) {
        classes.push('upload-loading')
      }
      
      return classes
    })
    
    const uploadAreaClass = computed(() => {
      const classes = []
      
      if (props.drag) {
        classes.push('upload-drag-area')
        
        if (dragOver.value) {
          classes.push('drag-over')
        }
      }
      
      if (props.disabled) {
        classes.push('disabled')
      }
      
      return classes
    })
    
    const buttonClass = computed(() => {
      const classes = ['upload-button-main']
      
      if (props.disabled) {
        classes.push('disabled')
      }
      
      return classes
    })
    
    const showLimit = computed(() => {
      return props.limit > 0 && props.showFileList
    })
    
    // 方法
    const handleClick = () => {
      if (props.disabled) return
      
      // 检查文件数量限制
      if (props.limit > 0 && props.fileList.length >= props.limit) {
        emit('exceed', props.fileList, props.limit)
        return
      }
      
      selectFiles()
    }
    
    const selectFiles = () => {
      uni.chooseFile({
        count: props.multiple ? (props.limit > 0 ? props.limit - props.fileList.length : 9) : 1,
        type: getFileType(),
        success: (res) => {
          handleFiles(res.tempFiles)
        },
        fail: (err) => {
          console.error('选择文件失败:', err)
        }
      })
    }
    
    const getFileType = () => {
      if (props.accept === '*') return 'all'
      if (props.accept.includes('image')) return 'image'
      if (props.accept.includes('video')) return 'video'
      return 'all'
    }
    
    const handleFiles = async (files) => {
      const fileList = Array.from(files).map(file => ({
        uid: Date.now() + Math.random(),
        name: file.name,
        size: file.size,
        path: file.path,
        file: file,
        status: 'ready',
        percent: 0
      }))
      
      // 文件验证
      const validFiles = []
      for (const file of fileList) {
        if (await validateFile(file)) {
          validFiles.push(file)
        }
      }
      
      if (validFiles.length === 0) return
      
      // 添加到文件列表
      const newFileList = [...props.fileList, ...validFiles]
      emit('change', newFileList)
      
      // 自动上传
      if (props.autoUpload) {
        validFiles.forEach(file => {
          uploadFile(file)
        })
      }
    }
    
    const validateFile = async (file) => {
      // 文件大小验证
      if (props.maxSize > 0 && file.size > props.maxSize * 1024 * 1024) {
        uni.showToast({
          title: `文件大小不能超过 ${props.maxSize}MB`,
          icon: 'none'
        })
        return false
      }
      
      // 文件类型验证
      if (props.accept !== '*' && !isAcceptedFileType(file)) {
        uni.showToast({
          title: '文件类型不支持',
          icon: 'none'
        })
        return false
      }
      
      // 自定义验证
      if (props.beforeUpload && typeof props.beforeUpload === 'function') {
        try {
          const result = await props.beforeUpload(file)
          if (result === false) {
            return false
          }
        } catch (error) {
          console.error('文件验证失败:', error)
          return false
        }
      }
      
      return true
    }
    
    const isAcceptedFileType = (file) => {
      if (props.accept === '*') return true
      
      const acceptTypes = props.accept.split(',').map(type => type.trim())
      const fileName = file.name.toLowerCase()
      
      return acceptTypes.some(type => {
        if (type.startsWith('.')) {
          return fileName.endsWith(type)
        }
        if (type.includes('/')) {
          // MIME type
          return file.type && file.type.includes(type.split('/')[0])
        }
        return false
      })
    }
    
    const uploadFile = async (file) => {
      const fileIndex = props.fileList.findIndex(f => f.uid === file.uid)
      if (fileIndex === -1) return
      
      // 更新状态
      updateFileStatus(file.uid, 'uploading', 0)
      uploading.value = true
      
      try {
        let result
        
        if (props.customRequest && typeof props.customRequest === 'function') {
          // 自定义上传
          result = await props.customRequest({
            file: file.file,
            data: props.data,
            headers: props.headers,
            onProgress: (percent) => {
              updateFileStatus(file.uid, 'uploading', percent)
              if (props.onProgress) {
                props.onProgress(percent, file)
              }
              emit('progress', percent, file)
            }
          })
        } else {
          // 默认上传
          result = await commonApi.uploadFile(file.file, {
            ...props.data,
            name: props.name
          })
        }
        
        // 上传成功
        updateFileStatus(file.uid, 'success', 100, result.data.url)
        
        if (props.onSuccess) {
          props.onSuccess(result, file)
        }
        emit('success', result, file)
        
      } catch (error) {
        // 上传失败
        updateFileStatus(file.uid, 'error', 0, null, error.message)
        
        if (props.onError) {
          props.onError(error, file)
        }
        emit('error', error, file)
        
      } finally {
        uploading.value = false
      }
    }
    
    const updateFileStatus = (uid, status, percent = 0, url = null, error = null) => {
      const fileIndex = props.fileList.findIndex(f => f.uid === uid)
      if (fileIndex > -1) {
        const updatedFile = {
          ...props.fileList[fileIndex],
          status,
          percent,
          url: url || props.fileList[fileIndex].url,
          error
        }
        
        const newFileList = [...props.fileList]
        newFileList[fileIndex] = updatedFile
        
        emit('change', newFileList)
      }
    }
    
    const handleRemove = (file, index) => {
      if (props.onRemove && typeof props.onRemove === 'function') {
        const result = props.onRemove(file, index)
        if (result === false) return
      }
      
      const newFileList = props.fileList.filter(f => f.uid !== file.uid)
      emit('change', newFileList)
      emit('remove', file, index)
    }
    
    const handlePreview = (file, index) => {
      if (props.onPreview && typeof props.onPreview === 'function') {
        props.onPreview(file, index)
      } else {
        // 默认预览行为
        if (isImage(file)) {
          uni.previewImage({
            urls: [file.url || file.path],
            current: 0
          })
        }
      }
      
      emit('preview', file, index)
    }
    
    const handleRetry = (file, index) => {
      uploadFile(file)
    }
    
    const getFileItemClass = (file) => {
      const classes = []
      
      classes.push(`file-${file.status}`)
      
      if (isImage(file)) {
        classes.push('file-image')
      }
      
      return classes
    }
    
    const isImage = (file) => {
      const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']
      const ext = getFileExtension(file.name)
      return imageTypes.includes(ext.toLowerCase())
    }
    
    const getFileExtension = (filename) => {
      return filename.split('.').pop() || ''
    }
    
    const getFileTypeIcon = (file) => {
      const ext = getFileExtension(file.name).toLowerCase()
      
      const iconMap = {
        pdf: '/static/images/file-pdf.png',
        doc: '/static/images/file-doc.png',
        docx: '/static/images/file-doc.png',
        xls: '/static/images/file-excel.png',
        xlsx: '/static/images/file-excel.png',
        ppt: '/static/images/file-ppt.png',
        pptx: '/static/images/file-ppt.png',
        txt: '/static/images/file-txt.png',
        zip: '/static/images/file-zip.png',
        rar: '/static/images/file-zip.png'
      }
      
      return iconMap[ext] || '/static/images/file-default.png'
    }
    
    const formatFileSize = (size) => {
      if (size < 1024) {
        return `${size} B`
      } else if (size < 1024 * 1024) {
        return `${(size / 1024).toFixed(1)} KB`
      } else if (size < 1024 * 1024 * 1024) {
        return `${(size / (1024 * 1024)).toFixed(1)} MB`
      } else {
        return `${(size / (1024 * 1024 * 1024)).toFixed(1)} GB`
      }
    }
    
    // 公开方法
    const submit = () => {
      const readyFiles = props.fileList.filter(file => file.status === 'ready')
      readyFiles.forEach(file => {
        uploadFile(file)
      })
    }
    
    const abort = (file) => {
      // 取消上传（uni-app 暂不支持）
      console.warn('uni-app 暂不支持取消上传')
    }
    
    return {
      uploading,
      dragOver,
      containerClass,
      uploadAreaClass,
      buttonClass,
      showLimit,
      handleClick,
      handleRemove,
      handlePreview,
      handleRetry,
      getFileItemClass,
      isImage,
      getFileTypeIcon,
      formatFileSize,
      submit,
      abort
    }
  }
}
</script>

<style lang="scss" scoped>
.upload-container {
  &.upload-disabled {
    opacity: 0.6;
    pointer-events: none;
  }
  
  &.upload-loading {
    .upload-area {
      pointer-events: none;
    }
  }
}

.upload-area {
  &.upload-drag-area {
    border: 2px dashed #d9d9d9;
    border-radius: 6px;
    background: #fafafa;
    text-align: center;
    cursor: pointer;
    transition: border-color 0.3s;
    
    &:hover {
      border-color: #409eff;
    }
    
    &.drag-over {
      border-color: #409eff;
      background: #f0f9ff;
    }
    
    &.disabled {
      cursor: not-allowed;
      background: #f5f5f5;
    }
  }
}

.upload-drag {
  padding: 40px 20px;
  
  .drag-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    
    .drag-icon {
      width: 48px;
      height: 48px;
      opacity: 0.6;
    }
    
    .drag-text {
      font-size: 16px;
      color: #606266;
    }
    
    .drag-hint {
      font-size: 14px;
      color: #909399;
    }
  }
}

.upload-button {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  
  .upload-btn {
    padding: 8px 16px;
    font-size: 14px;
    border: 1px solid #dcdfe6;
    border-radius: 4px;
    background: #fff;
    color: #606266;
    cursor: pointer;
    
    &:hover {
      color: #409eff;
      border-color: #c6e2ff;
      background: #ecf5ff;
    }
    
    &.disabled {
      color: #c0c4cc;
      cursor: not-allowed;
      background: #fff;
      border-color: #ebeef5;
    }
  }
  
  .upload-tip {
    font-size: 12px;
    color: #909399;
    line-height: 1.4;
  }
}

.file-list {
  margin-top: 16px;
  
  .file-item {
    display: flex;
    align-items: center;
    padding: 8px 0;
    border-bottom: 1px solid #f0f0f0;
    
    &:last-child {
      border-bottom: none;
    }
    
    &.file-error {
      .file-name {
        color: #f56c6c;
      }
    }
    
    &.file-success {
      .file-name {
        color: #67c23a;
      }
    }
  }
  
  .file-icon {
    flex-shrink: 0;
    margin-right: 12px;
    
    .file-preview {
      width: 40px;
      height: 40px;
      border-radius: 4px;
      cursor: pointer;
    }
    
    .file-type-icon {
      width: 32px;
      height: 32px;
    }
  }
  
  .file-info {
    flex: 1;
    min-width: 0;
    
    .file-name {
      display: block;
      font-size: 14px;
      color: #606266;
      margin-bottom: 4px;
      word-break: break-all;
    }
    
    .file-size {
      font-size: 12px;
      color: #909399;
    }
    
    .upload-progress {
      display: flex;
      align-items: center;
      gap: 8px;
      margin-top: 4px;
      
      .progress-bar {
        flex: 1;
        height: 4px;
        background: #f0f0f0;
        border-radius: 2px;
        overflow: hidden;
        
        .progress-fill {
          height: 100%;
          background: #409eff;
          transition: width 0.3s;
        }
      }
      
      .progress-text {
        font-size: 12px;
        color: #409eff;
      }
    }
    
    .upload-error {
      margin-top: 4px;
      
      .error-text {
        font-size: 12px;
        color: #f56c6c;
      }
    }
  }
  
  .file-actions {
    flex-shrink: 0;
    display: flex;
    gap: 8px;
    
    .action-btn {
      padding: 4px 8px;
      font-size: 12px;
      border: none;
      border-radius: 3px;
      cursor: pointer;
      
      &.preview-btn {
        background: #ecf5ff;
        color: #409eff;
      }
      
      &.remove-btn {
        background: #fef0f0;
        color: #f56c6c;
      }
      
      &.retry-btn {
        background: #fdf6ec;
        color: #e6a23c;
      }
    }
  }
}

.upload-limit {
  margin-top: 8px;
  text-align: right;
  
  .limit-text {
    font-size: 12px;
    color: #909399;
  }
}
</style>