/**
 * 小型化jQuery文件上传插件
 * 特点：
 * 1. 紧凑设计，占用空间小
 * 2. 支持文件安全校验，禁止可执行文件上传
 * 3. 显示上传进度
 * 4. 自动创建隐藏字段存储文件路径
 * 5. 支持自定义配置和复用
 */

(function($) {

    /**
     * 默认配置选项
     * @type {Object}
     */
    const defaults = {
        uploadId: 'file_upload',          // 上传字段ID，也用作隐藏字段的ID
        uploadApi: '/upload',             // 上传API地址
        allowedTypes: '*',                // 允许的文件类型，默认所有类型
        maxSize: 100,                      // 最大文件大小(MB)
        blockedExtensions: [              // 禁止的文件扩展名列表（安全校验）
            'exe', 'bat', 'cmd', 'sh',    // Windows/Linux可执行文件
            'php', 'js', 'py',            // 脚本文件
            'jar', 'apk', 'dmg',          // 应用程序文件
            'vbs', 'ps1', 'scr'           // 脚本和屏幕保护程序
        ],
        onSuccess: function(response) {}, // 上传成功回调
        onError: function(error) {},      // 上传失败回调
        onProgress: function(percent) {}  // 上传进度回调
    };

    /**
     * 紧凑型文件上传插件构造函数
     * @param {HTMLElement} element - jQuery选择的DOM元素
     * @param {Object} options - 配置选项
     */
    function CompactUpload(element, options) {
        this.$element = $(element);
        this.settings = $.extend({}, defaults, options);
        this.file = null;
        this.hiddenField = null;
        this.init();
    }

    /**
     * 初始化插件
     */
    CompactUpload.prototype.init = function() {
        this.createHiddenField();
        this.createUI();
        this.bindEvents();
    };

    /**
     * 创建隐藏字段用于存储文件路径
     */
    CompactUpload.prototype.createHiddenField = function() {
        // 检查是否已存在隐藏字段，避免重复创建
        const existingField = $(`#${this.settings.uploadId}`);
        if (existingField.length > 0) {
            this.hiddenField = existingField;
        } else {
            this.hiddenField = $(`<input type="hidden" id="${this.settings.uploadId}" name="${this.settings.uploadId}">`);
            $('body').append(this.hiddenField);
        }
    };

    /**
     * 创建紧凑型UI界面
     */
    CompactUpload.prototype.createUI = function() {
        const ui = `
                    <div class="upload-wrapper">
                        <button class="upload-btn" id="uploadBtn_${this.settings.uploadId}">
                            <i class="fa-regular fa-folder-open"></i> 选择文件
                        </button>
                        <div class="file-info">
                            <div class="file-name" id="fileName_${this.settings.uploadId}">未选择文件</div>
                            <div class="file-size" id="fileSize_${this.settings.uploadId}"></div>
                        </div>
                        <button class="clear-btn" id="clearBtn_${this.settings.uploadId}" title="清除文件">×</button>
                    </div>
                    <div class="progress-container" id="progressContainer_${this.settings.uploadId}">
                        <div class="progress-bar">
                            <div class="progress-fill" id="progressFill_${this.settings.uploadId}"></div>
                        </div>
                        <div class="progress-text" id="progressText_${this.settings.uploadId}">0%</div>
                    </div>
                `;

        this.$element.html(ui);
    };

    /**
     * 绑定事件处理器
     */
    CompactUpload.prototype.bindEvents = function() {
        const self = this;
        const uploadId = this.settings.uploadId;

        // 绑定选择文件按钮点击事件
        $(`#uploadBtn_${uploadId}`).on('click', function(e) {
            e.preventDefault();
            self.createFileInput();
        });

        // 绑定清除文件按钮点击事件
        $(`#clearBtn_${uploadId}`).on('click', function(e) {
            e.preventDefault();
            e.stopPropagation();
            self.clearFile();
        });
    };

    /**
     * 创建隐藏的文件输入框并触发点击
     */
    CompactUpload.prototype.createFileInput = function() {
        const self = this;
        const inputId = `fileInput_${this.settings.uploadId}_${Date.now()}`;

        // 创建临时文件输入框
        const input = $(`<input type="file" id="${inputId}" style="display: none;">`);
        input.attr('accept', this.settings.allowedTypes);

        // 添加到DOM并触发点击
        $('body').append(input);
        input.click();

        // 文件选择事件处理
        input.on('change', function(e) {
            if (this.files && this.files.length > 0) {
                const file = this.files[0];

                // 校验文件安全性
                const safetyCheck = self.validateFileSafety(file);
                if (!safetyCheck.valid) {
                    self.showError(safetyCheck.message);
                    $(this).remove();
                    return;
                }

                // 校验文件大小
                const sizeCheck = self.validateFileSize(file);
                if (!sizeCheck.valid) {
                    self.showError(sizeCheck.message);
                    $(this).remove();
                    return;
                }

                // 校验文件类型
                const typeCheck = self.validateFileType(file);
                if (!typeCheck.valid) {
                    self.showError(typeCheck.message);
                    $(this).remove();
                    return;
                }

                // 文件校验通过，处理文件
                self.handleFileSelect(file);
            }

            // 移除临时输入框
            $(this).remove();
        });
    };

    /**
     * 校验文件安全性（禁止可执行文件）
     * @param {File} file - 文件对象
     * @returns {Object} 校验结果 {valid: Boolean, message: String}
     */
    CompactUpload.prototype.validateFileSafety = function(file) {
        const fileName = file.name.toLowerCase();

        // 检查文件扩展名是否在禁止列表中
        for (let i = 0; i < this.settings.blockedExtensions.length; i++) {
            const ext = this.settings.blockedExtensions[i].toLowerCase();
            if (fileName.endsWith('.' + ext)) {
                return {
                    valid: false,
                    message: `安全限制：禁止上传${ext}类型的文件`
                };
            }
        }

        // 检查文件MIME类型（额外安全层）
        const dangerousMimeTypes = [
            'application/x-msdownload',    // exe
            'application/x-msdos-program', // com
            'application/bat',             // bat
            'application/x-bat',           // bat
            'application/x-shellscript',   // sh
            'application/x-php',           // php
            'application/javascript',      // js
            'application/x-javascript',    // js
            'text/javascript',             // js
            'application/x-python',        // py
            'text/x-python'                // py
        ];

        if (dangerousMimeTypes.includes(file.type.toLowerCase())) {
            return {
                valid: false,
                message: `安全限制：禁止上传${file.type}类型的文件`
            };
        }

        // 检查文件魔数（前几个字节）
        // 注意：由于浏览器安全限制，我们无法直接读取文件内容
        // 在实际应用中，应该在服务器端进行更严格的校验

        return { valid: true, message: '文件安全校验通过' };
    };

    /**
     * 校验文件大小
     * @param {File} file - 文件对象
     * @returns {Object} 校验结果 {valid: Boolean, message: String}
     */
    CompactUpload.prototype.validateFileSize = function(file) {
        const maxSizeBytes = this.settings.maxSize * 1024 * 1024;

        if (file.size > maxSizeBytes) {
            return {
                valid: false,
                message: `文件大小超过限制 (最大 ${this.settings.maxSize}MB)`
            };
        }

        return { valid: true, message: '文件大小校验通过' };
    };

    /**
     * 校验文件类型
     * @param {File} file - 文件对象
     * @returns {Object} 校验结果 {valid: Boolean, message: String}
     */
    CompactUpload.prototype.validateFileType = function(file) {
        if (this.settings.allowedTypes === '*') {
            return { valid: true, message: '文件类型校验通过' };
        }

        const allowedTypes = this.settings.allowedTypes.split(',');
        const fileName = file.name.toLowerCase();
        const fileType = file.type.toLowerCase();

        for (let i = 0; i < allowedTypes.length; i++) {
            let type = allowedTypes[i].trim().toLowerCase();

            // 通配符匹配（如图片类型 image/*）
            if (type.includes('*')) {
                const category = type.split('/')[0];
                if (fileType.startsWith(category)) {
                    return { valid: true, message: '文件类型校验通过' };
                }
            }
            // MIME类型匹配
            else if (fileType === type) {
                return { valid: true, message: '文件类型校验通过' };
            }
            // 扩展名匹配
            else if (fileName.endsWith('.' + type.replace('.', ''))) {
                return { valid: true, message: '文件类型校验通过' };
            }
        }

        return {
            valid: false,
            message: `文件类型不支持，请上传以下类型: ${this.settings.allowedTypes}`
        };
    };

    /**
     * 处理文件选择
     * @param {File} file - 选中的文件对象
     */
    CompactUpload.prototype.handleFileSelect = function(file) {
        this.file = file;
        this.showFileInfo(file);
        $(`#clearBtn_${this.settings.uploadId}`).show();
        this.startUpload();
    };

    /**
     * 显示文件信息
     * @param {File} file - 文件对象
     */
    CompactUpload.prototype.showFileInfo = function(file) {
        const fileSize = this.formatFileSize(file.size);
        $(`#fileName_${this.settings.uploadId}`).text(file.name);
        $(`#fileSize_${this.settings.uploadId}`).text(fileSize);
    };

    /**
     * 格式化文件大小
     * @param {number} bytes - 文件大小（字节）
     * @returns {string} 格式化后的文件大小
     */
    CompactUpload.prototype.formatFileSize = function(bytes) {
        if (bytes === 0) return '0 Bytes';
        const k = 1024;
        const sizes = ['Bytes', 'KB', 'MB', 'GB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    };

    /**
     * 开始上传文件
     */
    CompactUpload.prototype.startUpload = function() {
        if (!this.file) {
            this.showError('请先选择文件');
            return;
        }

        const self = this;
        const uploadId = this.settings.uploadId;

        // 显示上传进度
        $(`#progressContainer_${uploadId}`).show();
        $(`#uploadBtn_${uploadId}`).prop('disabled', true);

        // 模拟上传进度
        this.simulateProgress(uploadId);

        // 实际的上传代码（注释掉，需要后端接口）
        const formData = new FormData();
        formData.append('file', this.file);
        formData.append('files', this.file);
        formData.append('fileName', this.file.name);
        setTimeout(() => {
            $.ajax({
                url: this.settings.uploadApi,
                type: 'POST',
                data: formData,
                processData: false,
                contentType: false,
                xhr: function() {
                    const xhr = new window.XMLHttpRequest();
                    xhr.upload.addEventListener('progress', function(e) {

                    }, false);
                    return xhr;
                },
                success: function(response) {
                    if (response.code === 200) {
                        const mockResponse = {
                            success: true,
                            message: '文件上传成功',
                            filePath: response.data.filePath,
                            fileHash: response.data.fileHash,
                            fileName: response.data.fileName,
                            fileSize: response.data.fileSize,
                            uploadId: 'filePaths',
                            uploadedAt: new Date().toISOString()
                        };

                        self.handleUploadSuccess(mockResponse);
                        resolve();
                    } else {
                        self.handleUploadError('上传失败：服务器错误或网络问题');
                        reject(new Error(response.message));
                    }
                },
                error: function(xhr, status, error) {
                    reject(new Error('上传失败: ' + error));
                }
            });
        }, 2000);
    };

    /**
     * 模拟上传进度显示
     * @param {string} uploadId - 上传ID
     */
    CompactUpload.prototype.simulateProgress = function(uploadId) {
        let progress = 0;
        const interval = setInterval(() => {
            progress += Math.random() * 10;
            if (progress > 100) {
                progress = 100;
                clearInterval(interval);
            }

            $(`#progressFill_${uploadId}`).css('width', `${progress}%`);
            $(`#progressText_${uploadId}`).text(`${Math.round(progress)}%`);
            this.settings.onProgress(progress);
        }, 200);
    };

    /**
     * 处理上传成功
     * @param {Object} response - 服务器响应
     */
    CompactUpload.prototype.handleUploadSuccess = function(response) {
        const uploadId = this.settings.uploadId;

        // 更新隐藏字段值
        this.hiddenField.val(response.filePath);

        // 显示成功状态
        this.showSuccess('文件上传成功！');

        // 隐藏进度条
        $(`#progressContainer_${uploadId}`).hide();

        // 启用上传按钮
        $(`#uploadBtn_${uploadId}`).prop('disabled', false);

        // 调用成功回调
        this.settings.onSuccess(response);

        // 更新隐藏字段显示
        this.updateHiddenFieldDisplay();
    };

    /**
     * 处理上传错误
     * @param {string} error - 错误信息
     */
    CompactUpload.prototype.handleUploadError = function(error) {
        const uploadId = this.settings.uploadId;

        // 显示错误状态
        this.showError(error);

        // 隐藏进度条
        $(`#progressContainer_${uploadId}`).hide();

        // 启用上传按钮
        $(`#uploadBtn_${uploadId}`).prop('disabled', false);

        // 调用错误回调
        this.settings.onError(error);
    };

    /**
     * 显示成功状态消息
     * @param {string} message - 成功消息
     */
    CompactUpload.prototype.showSuccess = function(message) {
        const uploadId = this.settings.uploadId;
        const statusDiv = $('#uploadStatus');

        statusDiv.removeClass('status-error').addClass('status-success');
        statusDiv.text(message);
        statusDiv.show();

        // 3秒后自动隐藏成功消息
        setTimeout(() => {
            statusDiv.fadeOut();
        }, 3000);
    };

    /**
     * 显示错误状态消息
     * @param {string} message - 错误消息
     */
    CompactUpload.prototype.showError = function(message) {
        const uploadId = this.settings.uploadId;
        const statusDiv = $('#uploadStatus');

        statusDiv.removeClass('status-success').addClass('status-error');
        statusDiv.text(message);
        statusDiv.show();

        // 5秒后自动隐藏错误消息
        setTimeout(() => {
            statusDiv.fadeOut();
        }, 5000);
    };

    /**
     * 清除已选文件
     */
    CompactUpload.prototype.clearFile = function() {
        this.file = null;
        this.hiddenField.val('');

        const uploadId = this.settings.uploadId;
        $(`#fileName_${uploadId}`).text('未选择文件');
        $(`#fileSize_${uploadId}`).text('');
        $(`#progressContainer_${uploadId}`).hide();
        $(`#clearBtn_${uploadId}`).hide();
        $(`#uploadBtn_${uploadId}`).prop('disabled', false);

        // 更新隐藏字段显示
        this.updateHiddenFieldDisplay();
    };

    /**
     * 更新隐藏字段值显示
     */
    CompactUpload.prototype.updateHiddenFieldDisplay = function() {
        const fieldValue = this.hiddenField.val();
        const displayDiv = $('#hiddenFieldValue');

        if (fieldValue) {
            displayDiv.text(fieldValue);
            displayDiv.css('color', '#27ae60');
        } else {
            displayDiv.text('等待文件上传...');
            displayDiv.css('color', '#2c3e50');
        }
    };

    /**
     * 更新插件配置
     * @param {Object} options - 新的配置选项
     */
    CompactUpload.prototype.updateConfig = function(options) {
        this.settings = $.extend({}, this.settings, options);
        this.clearFile();
        this.createUI();
        this.bindEvents();
    };

    /**
     * 获取隐藏字段的值
     * @returns {string} 隐藏字段的值
     */
    CompactUpload.prototype.getValue = function() {
        return this.hiddenField.val();
    };

    /**
     * 设置隐藏字段的值
     * @param {string} value - 要设置的值
     */
    CompactUpload.prototype.setValue = function(value) {
        this.hiddenField.val(value);
        this.updateHiddenFieldDisplay();
    };

    // 注册jQuery插件
    $.fn.compactUpload = function(options) {
        return this.each(function() {
            if (!$.data(this, 'compactUpload')) {
                $.data(this, 'compactUpload', new CompactUpload(this, options));
            }
        });
    };

    // 插件方法扩展
    $.fn.compactUpload.update = function(options) {
        return this.each(function() {
            const plugin = $.data(this, 'compactUpload');
            if (plugin) {
                plugin.updateConfig(options);
            }
        });
    };

    $.fn.compactUpload.getValue = function() {
        const plugin = $.data(this.get(0), 'compactUpload');
        return plugin ? plugin.getValue() : null;
    };

    $.fn.compactUpload.setValue = function(value) {
        return this.each(function() {
            const plugin = $.data(this, 'compactUpload');
            if (plugin) {
                plugin.setValue(value);
            }
        });
    };

    $.fn.compactUpload.clear = function() {
        return this.each(function() {
            const plugin = $.data(this, 'compactUpload');
            if (plugin) {
                plugin.clearFile();
            }
        });
    };

})(jQuery);