<template>
    <div class="upload-container">
        <el-upload
            ref="upload"
            class="upload-demo"
            drag
            action="#"
            multiple
            :show-file-list="true"
            :before-upload="beforeUpload"
            :on-remove="handleRemove"
            :on-change="handleFileChange"
            :on-exceed="handleExceed"
            :file-list="files"
            :accept="accept"
            :limit="limitUploadNum"
            :auto-upload="autoUpload"
            :http-request="customUpload"
        >
            <div class="upload-content">
                <!-- 图片预览 -->
                <div v-if="showImagePreview" class="image-preview">
                    <img :src="previewImageUrl" :alt="previewImageName" class="preview-thumbnail" />
                    <div class="preview-overlay">
                        <div class="preview-text">
                            <div class="main-text">点击更换图片</div>
                            <div class="tip-text">或拖拽新图片到此处</div>
                        </div>
                    </div>
                </div>

                <!-- 文档预览 -->
                <div v-else-if="showFilePreview" class="file-preview">
                    <div class="file-icon-container">
                        <i :class="fileIconClass" class="file-icon"></i>
                        <div class="file-name">{{ previewFileName }}</div>
                    </div>
                    <div class="preview-overlay">
                        <div class="preview-text">
                            <div class="main-text">点击更换文件</div>
                            <div class="tip-text">或拖拽新文件到此处</div>
                        </div>
                    </div>
                </div>

                <!-- 默认上传区域 -->
                <div v-else class="upload-text">
                    <div class="main-text"> + 点击或将文件拖拽到这里上传</div>
                    <div class="tip-text">
                        <div>单份文件大小上限 {{ maxFileTips }}，</div>
                        <div>支持文件类型：{{ uploadType }}</div>
                    </div>
                </div>
            </div>
        </el-upload>
    </div>
</template>

<script>
import {
    uploadSmallFileByOcr,
    uploadLargeFileByOcr,
    uploadSmallFile,
    uploadLargeFile,
} from '@/api/common/uploadFile.js'
import mammoth from 'mammoth'
import * as XLSX from 'xlsx'

// 常量定义
const FILE_STATUS = {
    READY: 'ready',
    UPLOADING: 'uploading',
    SUCCESS: 'success',
    FAIL: 'fail',
    REMOVED: 'removed'
}

const FILE_TYPES = {
    IMAGE: '1',
    DOCUMENT: '2'
}

const DEFAULT_FILE_SIZE = 5 * 1024 * 1024 // 5MB
const ICON_MAP = {
    pdf: 'el-icon-document',
    doc: 'el-icon-document',
    docx: 'el-icon-document',
    xls: 'el-icon-document',
    xlsx: 'el-icon-document',
    zip: 'el-icon-document'
}

export default {
    name: 'UploadFile',
    props: {
        fileList: {
            type: Array,
            default: () => [],
        },
        maxFileTips: {
            type: String,
            default: '20MB',
        },
        uploadType: {
            type: String,
            default: 'png、jpg、jpeg',
        },
        limitUploadNum: {
            type: Number,
            default: 1,
        },
        fileUploadRule: {
            type: Object,
            default: () => ({}),
        },
        autoUpload: {
            type: Boolean,
            default: true,
        },
        type: {
            type: String,
            default: '',
        },
    },
    data() {
        return {
            files: [],
            previewImageUrl: '',
            previewImageName: '',
            previewFileName: '',
            previewFileType: '',
            isUploading: false,
        }
    },
    computed: {
        showImagePreview() {
            return this.previewImageUrl && this.files.length === 1
        },
        showFilePreview() {
            return this.previewFileName && this.previewFileType && this.files.length === 1
        },
        accept() {
            return this.allowedTypes.map(type => `.${type}`).join(',')
        },
        allowedTypes() {
            return this.uploadType.split('、')
        },
        maxSizeMB() {
            const sizeStr = this.maxFileTips.toLowerCase()
            if (sizeStr.includes('mb')) return parseFloat(sizeStr)
            if (sizeStr.includes('kb')) return parseFloat(sizeStr) / 1024
            if (sizeStr.includes('gb')) return parseFloat(sizeStr) * 1024
            return 20
        },
        mimeTypes() {
            const typeMap = {
                png: 'image/png',
                jpg: 'image/jpeg',
                jpeg: 'image/jpeg',
                pdf: 'application/pdf',
                doc: 'application/msword',
                docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                xls: 'application/vnd.ms-excel',
                xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                zip: 'application/x-zip-compressed',
            }
            return this.allowedTypes.map(type => typeMap[type] || '')
        },
        fileIconClass() {
            return ICON_MAP[this.previewFileType] || 'el-icon-document'
        }
    },
    watch: {
        fileList: {
            handler(newVal) {
                if (newVal.length > 0) {
                    this.$nextTick(() => {
                        this.files = this.formatFileList(newVal)
                        this.handlePreviewFromExternal(newVal)
                    })
                }else{
                    this.$nextTick(() => {
                        this.files = [];
                        this.handlePreviewFromExternal(newVal)
                    })
                }
            },
            immediate: false,
            deep: true
        },
    },
    methods: {
        // 文件验证
        beforeUpload(file) {
            if (this.isUploading) {
                this.$message.warning('当前有文件正在上传，请稍后再试')
                return false
            }

            const fileExtension = this.getFileExtension(file.name)
            const isAllowedType = this.allowedTypes.includes(fileExtension)
            const isAllowedMimeType = this.mimeTypes.includes(file.type)

          const isLtMaxSize = file.size / 1024 / 1024 < this.maxSizeMB

            if (!isAllowedType || !isAllowedMimeType) {
                this.$message.error(`只能上传 ${this.uploadType} 格式的文件!`)
                return false
            }

            if (!isLtMaxSize) {
                this.$emit('validate-fail')
                this.$message.error(`文件大小不能超过 ${this.maxFileTips}!`)
                return false
            }

            return true
        },

        // 文件变化处理
        handleFileChange(file, fileList) {
            if (this.shouldIgnoreFileChange(file.status)) return

            this.files = this.formatFileList(fileList)
            this.updatePreview(fileList)
        },

        // 文件超出限制处理
        handleExceed(files, fileList) {
            console.log('文件超出限制处理', files, fileList)
            const isAllowed = this.beforeUpload(files[0]);
            if (!isAllowed) return;
            if (files.length > 0) {
                // 触发删除事件
                this.$emit('del-file', { ...fileList[0], response: fileList[0].res })

                // 清空并添加新文件
                this.files = []
                const newFile = files[0]
                const newFileObj = this.createFileObject(newFile)
                this.files = [newFileObj]

                this.updatePreview([newFileObj])

                // 自动上传
                if (this.autoUpload && !this.isUploading) {
                    this.$nextTick(() => {
                        this.$refs.upload.submit()
                    })
                }
            }
        },

        // 文件移除处理
        handleRemove(file, fileList) {
            if (!file) {
                this.clearPreview()
                return true
            }

            if (this.isUploading && file.status === FILE_STATUS.UPLOADING) {
                this.$message.warning('文件正在上传中，请稍后再删除')
                return false
            }

            this.updatePreview(fileList)
            this.files = this.formatFileList(fileList)

            const delFileObj = this.findFileByRawFile(file.raw)
            if (delFileObj) {
                delFileObj.response = delFileObj.res
                this.$emit('del-file', delFileObj)
            }

            this.$emit('file-change', this.getCurrentFiles(), this.type)
            return true
        },

        // 自定义上传
        async customUpload(options) {
            const { file } = options
            this.isUploading = true

            const uploadFileObj = this.findFileByRawFile(file)
            if (!uploadFileObj) {
                this.handleError(new Error('文件对象不存在'), file)
                return
            }

            const fileUid = uploadFileObj.uid
            const statusText = this.fileUploadRule.fields_json ? '识别中' : '上传中'

            this.updateFileStatus(fileUid, FILE_STATUS.UPLOADING, statusText, null, 0)
            this.$bus.$emit('startUpload', statusText)

            try {
                const formData = this.createFormData(file)
                const res = await this.uploadFile(formData, file.size)

                if (res.code === 200) {
                    this.handleSuccess(res, uploadFileObj)
                } else {
                    this.handleError(new Error(res.message || '上传失败'), uploadFileObj)
                }
            } catch (err) {
                this.handleError(err, uploadFileObj)
            } finally {
                this.isUploading = false
            }
        },

        // 上传成功处理
        handleSuccess(response, file) {
          const fileExt = this.getFileExtension(file.name);
          if (fileExt === 'docx') {
            this.parseDocxFile(file.raw).then(text => {
              // 将解析出的文本传递给父组件处理OCR逻辑
              this.$emit('docx-content', text);
            });
          }

          else if (fileExt === 'xlsx' || fileExt === 'xls') {
            this.parseXlsxFile(file.raw).then(text => {
              this.$emit('xlsx-content', text);  // 触发xlsx内容事件
            }).catch(err => {
              console.error('xlsx解析失败:', err);
            });
          }

          this.$bus.$emit('endUpload')
          this.updateFileStatus(file.uid, FILE_STATUS.SUCCESS, '', response.data, 100)
          this.$emit('file-change', this.getCurrentFiles(), this.type)
          this.isUploading = false
        },

        // 上传失败处理
        handleError(error, file) {
            console.error('上传失败:', error)
            this.$bus.$emit('endUpload')
            this.$emit('upload-fail');
            this.removeFailedFile(file.uid)
            this.isUploading = false
        },

      parseDocxFile(file) {
        return new Promise((resolve, reject) => {
          const reader = new FileReader();
          reader.onload = function(e) {
            const arrayBuffer = e.target.result;
            // 使用mammoth解析docx
            mammoth.extractRawText({ arrayBuffer })
              .then(result => {
                resolve(result.value); // 提取的纯文本内容
              })
              .catch(err => {
                console.error('docx解析失败:', err);
                reject(err);
              });
          };
          reader.readAsArrayBuffer(file);

        });
      },

      parseXlsxFile(file) {
        return new Promise((resolve, reject) => {
          const reader = new FileReader();
          reader.onload = function(e) {
            try {
              // 读取二进制数据
              const data = new Uint8Array(e.target.result);
              // 解析Excel文件
              const workbook = XLSX.read(data, { type: 'array' });
              // 获取第一个工作表
              const firstSheetName = workbook.SheetNames[0];
              const worksheet = workbook.Sheets[firstSheetName];
              // 转换为JSON（只解析前100行，避免大文件性能问题）
              const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1, range: 0, raw: false });
              // 转换为文本格式（按行拼接，用换行分隔）
              const text = jsonData.map(row => row.join('\t')).join('\n');
              resolve(text);
            } catch (err) {
              console.error('xlsx解析失败:', err);
              reject(err);
            }
          };
          // 读取文件为二进制
          reader.readAsArrayBuffer(file);
        });
      },

        // 工具方法
        getFileExtension(filename) {
            return filename.split('.').pop().toLowerCase()
        },

        shouldIgnoreFileChange(status) {
            return [FILE_STATUS.REMOVED, FILE_STATUS.FAIL, FILE_STATUS.SUCCESS].includes(status)
        },

        createFormData(file) {
            const formData = new FormData()
            formData.append('file', file)
            formData.append('params', JSON.stringify(this.fileUploadRule))
            return formData
        },

        async uploadFile(formData, fileSize) {
            const isLargeFile = fileSize > DEFAULT_FILE_SIZE
            const hasOcr = !!this.fileUploadRule.fields_json

            if (isLargeFile) {
                return hasOcr ? await uploadLargeFileByOcr(formData) : await uploadLargeFile(formData)
            } else {
                return hasOcr ? await uploadSmallFileByOcr(formData) : await uploadSmallFile(formData)
            }
        },

        findFileByRawFile(rawFile) {
            return this.files.find(item =>
                item.raw === rawFile ||
                (item.name === rawFile.name && item.size === rawFile.size)
            )
        },

        removeFailedFile(fileUid) {
            const fileIndex = this.files.findIndex(item => item.uid === fileUid)
            if (fileIndex !== -1) {
                this.files.splice(fileIndex, 1)
                this.clearPreview()
                this.$emit('file-change', this.getCurrentFiles(), this.type)
            }
        },

        updateFileStatus(fileUid, status, statusText = null, responseData = null, percentage = null) {
            const fileIndex = this.files.findIndex(item => item.uid === fileUid)
            if (fileIndex === -1) {
                console.warn('未找到要更新的文件:', fileUid)
                return
            }

            const updatedFile = { ...this.files[fileIndex], status }

            if (statusText) updatedFile.statusText = statusText
            if (percentage !== null) updatedFile.percentage = Math.max(0, Math.min(100, percentage))

            if (responseData) {
                updatedFile.response = responseData
                updatedFile.response.businessType = this.fileUploadRule?.fileUploadType
                updatedFile.res = updatedFile.response
            }

            this.$set(this.files, fileIndex, updatedFile)
        },

        formatFileList(fileList) {
            return fileList.map(file => {
                const formattedFile = {
                    uid: file.uid,
                    name: file.name,
                    size: file.size,
                    type: file.type,
                    status: file.status,
                    raw: file.raw,
                }

                // 处理进度
                if (file.percentage !== undefined && file.percentage !== null) {
                    formattedFile.percentage = Math.max(0, Math.min(100, file.percentage))
                } else if (file.status === FILE_STATUS.UPLOADING) {
                    formattedFile.percentage = 0
                } else if (file.status === FILE_STATUS.SUCCESS) {
                    formattedFile.percentage = 100
                }

                // 保留其他属性
                if (file.response) {
                    formattedFile.response = file.response
                    formattedFile.res = file.response
                }
                if (file.filePath) formattedFile.filePath = file.filePath
                if (file.statusText) formattedFile.statusText = file.statusText

                return formattedFile
            })
        },

        getCurrentFiles() {
            return this.files.map(file => {
                const fileObj = {
                    uid: file.uid,
                    name: file.name,
                    size: file.size,
                    type: file.type,
                    status: file.status,
                    percentage: file.percentage || 0,
                }

                if (file.raw) fileObj.raw = file.raw
                if (file.response) {
                    fileObj.response = file.response
                    fileObj.response.businessType = this.fileUploadRule?.fileUploadType
                }

                return fileObj
            })
        },

        createFileObject(file) {
            return {
                name: file.name,
                size: file.size,
                type: file.type,
                raw: file,
                uid: Date.now(),
                status: FILE_STATUS.READY,
                percentage: 0,
            }
        },

        // 预览相关方法
        isImageFile(file) {
            return (file && file.type && file.type.startsWith('image/')) || (file && file.fileType === FILE_TYPES.IMAGE)
        },

        isDocumentFile(file) {
            if (!file || !file.name) return false
            const fileExtension = this.getFileExtension(file.name)
            return ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'zip'].includes(fileExtension) ||
                   (file && file.fileType === FILE_TYPES.DOCUMENT)
        },

        updatePreview(fileList) {
            if (fileList.length === 0) {
                this.clearPreview()
                return
            }

            if (fileList.length === 1 && fileList[0]) {
                const file = fileList[0].raw || fileList[0]
                if (this.isImageFile(file)) {
                    fileList[0].lsFilePath ?
                        this.generateImagePreviewFromPath(fileList[0]) :
                        this.generateImagePreview(file)
                } else if (this.isDocumentFile(file)) {
                    this.generateDocumentPreview(file)
                }
            } else {
                this.clearPreview()
            }
        },

        generateImagePreview(file) {
            const reader = new FileReader()
            reader.onload = (e) => {
                this.previewImageUrl = e.target.result
                this.previewImageName = file.name
                this.previewFileName = ''
                this.previewFileType = ''
            }
            reader.readAsDataURL(file)
        },

        generateImagePreviewFromPath(file) {
            this.previewImageUrl = file.lsFilePath
            this.previewImageName = file.name
            this.previewFileName = ''
            this.previewFileType = ''
        },

        generateDocumentPreview(file) {
            this.previewFileName = file.name
            this.previewFileType = this.getFileExtension(file.name)
            this.previewImageUrl = ''
            this.previewImageName = ''
        },

        clearPreview() {
            this.previewImageUrl = ''
            this.previewImageName = ''
            this.previewFileName = ''
            this.previewFileType = ''
        },

        handlePreviewFromExternal(fileList) {
            if (fileList.length > 0) {
                const firstFile = fileList[0]
                if (firstFile?.lsFilePath) {
                    this.isImageFile(firstFile) ?
                        this.generateImagePreviewFromPath(firstFile) :
                        this.generateDocumentPreview(firstFile)
                } else if (firstFile?.raw) {
                    this.isImageFile(firstFile.raw) ?
                        this.generateImagePreview(firstFile.raw) :
                        this.generateDocumentPreview(firstFile.raw)
                } else {
                    this.clearPreview()
                }
            } else {
                this.clearPreview()
            }
        },

        clearFiles() {
            this.files = []
            this.clearPreview()
            this.$emit('file-change', [])
        },
    },
}
</script>
<style scoped lang="scss">
.upload-container {
    width: 100%;

    .upload-demo {
        width: 100%;

        ::v-deep .el-upload {
            width: 100%;

            .el-upload-dragger {
                width: 100%;
                height: 240px;
                border: 2px dashed #dcdfe6;
                border-radius: 8px;
                background-color: #fafafa;
                display: flex;
                align-items: center;
                justify-content: center;
                transition: all 0.3s ease;
                position: relative;
                overflow: hidden;

                &:hover {
                    border-color: #409eff;
                    background-color: #f5f7fa;
                }
            }
        }
    }

    .upload-content {
        width: 100%;
        height: 100%;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        padding: 5px;

        // 图片预览样式
        .image-preview {
            position: relative;
            width: 100%;
            height: 100%;
            border-radius: 6px;
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;

            .preview-thumbnail {
                max-width: 100%;
                max-height: 100%;
                width: auto;
                height: auto;
                object-fit: contain;
                display: block;
            }

            .preview-overlay {
                position: absolute;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                background: rgba(0, 0, 0, 0.6);
                display: flex;
                align-items: center;
                justify-content: center;
                opacity: 0;
                transition: opacity 0.3s ease;
                pointer-events: none;

                .preview-text {
                    text-align: center;
                    color: white;
                    pointer-events: none;

                    .main-text {
                        font-size: 16px;
                        margin-bottom: 8px;
                        font-weight: 500;
                    }

                    .tip-text {
                        font-size: 12px;
                        opacity: 0.9;
                    }
                }
            }

            &:hover .preview-overlay {
                opacity: 1;
            }
        }

        // 文件预览样式
        .file-preview {
            position: relative;
            width: 100%;
            height: 100%;
            border-radius: 6px;
            overflow: hidden;

            .file-icon-container {
                width: 100%;
                height: 100%;
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;
                background: #f9fafc;

                .file-icon {
                    font-size: 64px;
                    color: #1f72ea;
                    margin-bottom: 16px;
                }

                .file-name {
                    font-size: 14px;
                    color: #606266;
                    text-align: center;
                    padding: 0 20px;
                    word-break: break-all;
                    max-width: 100%;
                    overflow: hidden;
                    text-overflow: ellipsis;
                    display: -webkit-box;
                    -webkit-line-clamp: 2;
                    line-clamp: 2;
                    -webkit-box-orient: vertical;
                }
            }

            .preview-overlay {
                position: absolute;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                background: rgba(0, 0, 0, 0.6);
                display: flex;
                align-items: center;
                justify-content: center;
                opacity: 0;
                transition: opacity 0.3s ease;
                pointer-events: none;

                .preview-text {
                    text-align: center;
                    color: white;
                    pointer-events: none;

                    .main-text {
                        font-size: 16px;
                        margin-bottom: 8px;
                        font-weight: 500;
                    }

                    .tip-text {
                        font-size: 12px;
                        opacity: 0.9;
                    }
                }
            }

            &:hover .preview-overlay {
                opacity: 1;
            }
        }

        // 默认上传区域样式
        .upload-text {
            text-align: center;

            .main-text {
                font-size: 18px;
                color: #1f72ea;
                margin-bottom: 12px;
                font-weight: 500;
            }

            .tip-text {
                font-size: 14px;
                color: #909399;
                line-height: 1.5;

                div {
                    margin-bottom: 2px;
                }
            }
        }
    }
}
</style>
