<script>
import Upload from './upload.vue';
import UploadList from './upload-list.vue';
import { prefix, prefixMixins } from 'jdd-design/utils';
// import JddProgress from '../progress';

function fn() {}

export default {
    name: `${prefix}-upload`,
    components: {
        Upload,
        UploadList
    },
    mixins: [prefixMixins],
    provide() {
        return {
            uploader: this
        };
    },
    props: {
        width: Number,
        height: Number,
        // 上传的地址
        action: {
            type: String,
            required: true
        },
        // 设置上传的请求头部
        headers: {
            type: Object,
            default() {
                return {};
            }
        },
        // 是否支持多选文件
        multiple: Boolean,
        // 上传时附带的额外参数
        data: Object,
        // 上传的文件名
        name: {
            type: String,
            default: 'file'
        },
        // 支持发送 cookie 凭证信息
        withCredentials: Boolean,
        // 是否显示已上传文件列表
        showFileList: {
            type: Boolean,
            default: true
        },
        // 接受上传的文件类型
        accept: String,
        type: {
            type: String,
            default: 'select'
        },
        // 是否立即自动上传
        autoUpload: {
            type: Boolean,
            default: true
        },
        // 文件列表的类型 text,card,file,目前支持text、file
        listType: {
            type: String,
            default: 'text'
        },
        // 是否禁用
        disabled: {
            type: Boolean,
            default: false
        },
        // 最大允许上传个数
        limit: Number,
        // 是否拖拽上传
        drag: Boolean,
        // 上传文件列表
        fileList: {
            type: Array,
            default() {
                return [];
            }
        },
        // 覆盖默认的上传行为，可以自定义上传的实现
        httpRequest: Function,
        // 文件状态改变时的钩子
        onChange: {
            type: Function,
            default: fn
        },
        beforeUpload: Function,
        // 文件上传时的钩子
        onProgress: {
            type: Function,
            default: fn
        },
        // 文件上传成功时的钩子
        onSuccess: {
            type: Function,
            default: fn
        },
        // 文件上传失败时的钩子
        onError: {
            type: Function,
            default: fn
        },
        // 文件移除前的钩子
        beforeRemove: Function,
        // 文件移除时的钩子
        onRemove: {
            type: Function,
            default: fn
        },
        // 文件超出个数限制时的钩子
        onExceed: {
            type: Function,
            default: fn
        },
        // 预览钩子函数
        onPreview: {
            type: Function
        }
    },
    data() {
        return {
            uploadFiles: [],
            tempIndex: 1
        };
    },
    computed: {
        uploadDisabled() {
            return this.disabled;
        }
    },
    watch: {
        listType(type) {
            if (type === 'file' || type === 'card') {
                this.uploadFiles = this.uploadFiles.map(file => {
                    if (!file.url && file.raw) {
                        try {
                            file.url = URL.createObjectURL(file.raw);
                        } catch (err) {
                            console.error('upload err:', err);
                        }
                    }
                    return file;
                });
            }
        },
        fileList: {
            immediate: true,
            handler(fileList) {
                this.uploadFiles = fileList.map(item => {
                    item.uid = item.uid || Date.now() + this.tempIndex++;
                    item.status = item.status || 'success';
                    return item;
                });
            }
        }
    },

    beforeDestroy() {
        this.uploadFiles.forEach(file => {
            if (file.url && file.url.indexOf('blob:') === 0) {
                URL.revokeObjectURL(file.url);
            }
        });
    },

    methods: {
        handleStart(rawFile) {
            rawFile.uid = Date.now() + this.tempIndex++;
            let file = {
                status: 'ready',
                name: rawFile.name,
                size: rawFile.size,
                percentage: 0,
                uid: rawFile.uid,
                raw: rawFile
            };

            if (this.listType === 'file' || this.listType === 'card') {
                try {
                    file.url = URL.createObjectURL(rawFile);
                } catch (err) {
                    console.error('upload err:', err);
                    return;
                }
            }

            this.uploadFiles.push(file);
            this.onChange(file, this.uploadFiles);
        },
        handleProgress(ev, rawFile) {
            const file = this.getFile(rawFile);
            this.onProgress(ev, file, this.uploadFiles);
            file.status = 'running';
            file.percentage = ev.percent || 0;
        },
        handleSuccess(res, rawFile) {
            const file = this.getFile(rawFile);

            if (file) {
                file.status = 'success';
                file.response = res;
                this.setFileType(file);
                this.onSuccess(res, file, this.uploadFiles);
                this.onChange(file, this.uploadFiles);
            }
        },
        setFileType(file) {
            let fileType = (file && file.raw && file.raw.type) || '';
            file.fileType = 'default';
            if (fileType) {
                if (/^image\/[a-zA-Z]+$/.test(fileType)) {
                    file.fileType = 'image';
                } else {
                    file.fileType = 'file';
                }
            }
            let name = file && file.name;
            let suffix = '';
            if (name) {
                let nameArr = name.split('.');
                suffix = nameArr.pop();
                let newName = nameArr.join('.');
                file.newname = {
                    front: newName.substr(0, newName.length - 1),
                    last: newName.substr(-1),
                    suffix
                };
            }
            if (suffix) {
                file.icon = 'default';
                if (file.fileType === 'file') {
                    // ppt/pdf, xlsx, docx, txt, rar/zip
                    let type = '';
                    switch (suffix) {
                        case 'txt':
                            type = 'txt';
                            break;
                        case 'ppt':
                        case 'pdf':
                            type = 'ppt';
                            break;
                        case 'rar':
                        case 'zip':
                            type = 'zip';
                            break;
                        default:
                            if (/^(xls|XLS)[a-zA-Z]*$/.test(suffix)) {
                                type = 'xls';
                            } else if (/^(doc|DOC)[a-zA-Z]*$/.test(suffix)) {
                                type = 'doc';
                            }
                            break;
                    }
                    file.icon = type;
                }
            }
        },
        handleError(err, rawFile) {
            const file = this.getFile(rawFile);
            const fileList = this.uploadFiles;

            file.status = 'error';

            fileList.splice(fileList.indexOf(file), 1);

            this.onError(err, file, this.uploadFiles);
            this.onChange(file, this.uploadFiles);
        },
        handleRemove(file, raw) {
            if (raw) {
                file = this.getFile(raw);
            }
            let doRemove = () => {
                this.abort(file);
                let fileList = this.uploadFiles;
                fileList.splice(fileList.indexOf(file), 1);
                this.onRemove(file, fileList);
            };

            if (!this.beforeRemove) {
                doRemove();
            } else if (typeof this.beforeRemove === 'function') {
                const before = this.beforeRemove(file, this.uploadFiles);
                if (before && before.then) {
                    before.then(() => {
                        doRemove();
                    }, fn);
                } else if (before !== false) {
                    doRemove();
                }
            }
        },
        getFile(rawFile) {
            let fileList = this.uploadFiles;
            let target;
            fileList.every(item => {
                target = rawFile.uid === item.uid ? item : null;
                return !target;
            });
            return target;
        },
        abort(file) {
            if (this.$refs['upload-inner']) {
                this.$refs['upload-inner'].abort(file);
            } else {
                file.raw.req.abort();
            }
        },
        clearFiles() {
            this.uploadFiles = [];
        },
        submit() {
            this.uploadFiles
                .filter(file => file.status === 'ready')
                .forEach(file => {
                    this.$refs['upload-inner'].upload(file.raw);
                });
        }
    },

    render() {
        let uploadList;
        if (this.showFileList && this.uploadFiles.length) {
            uploadList = (
                <UploadList
                    disabled={this.uploadDisabled}
                    listType={this.listType}
                    files={this.uploadFiles}
                    on-remove={this.handleRemove}
                    handlePreview={this.onPreview}
                    width={this.width}
                    height={this.height}
                >
                    {props => {
                        if (this.$scopedSlots.file) {
                            return this.$scopedSlots.file({
                                file: props.file
                            });
                        }
                    }}
                </UploadList>
            );
        }

        const uploadData = {
            props: {
                width: this.width,
                height: this.height,
                type: this.type,
                drag: this.drag,
                action: this.action,
                multiple: this.multiple,
                'before-upload': this.beforeUpload,
                'with-credentials': this.withCredentials,
                headers: this.headers,
                name: this.name,
                data: this.data,
                accept: this.accept,
                fileList: this.uploadFiles,
                autoUpload: this.autoUpload,
                listType: this.listType,
                disabled: this.uploadDisabled,
                limit: this.limit,
                'on-exceed': this.onExceed,
                'on-start': this.handleStart,
                'on-progress': this.handleProgress,
                'on-success': this.handleSuccess,
                'on-error': this.handleError,
                'on-preview': this.onPreview,
                'on-remove': this.handleRemove,
                'http-request': this.httpRequest
            },
            ref: 'upload-inner'
        };

        const trigger = this.$slots.trigger || this.$slots.default;
        const uploadComponent = <upload {...uploadData}>{trigger}</upload>;
        const showUpload = this.limit > this.uploadFiles.length;
        let main = [];
        if (showUpload) {
            main.push(uploadComponent);
        }
        return (
            <div>
                {this.listType === 'file' ? uploadList : ''}
                {main}
                {this.$slots.tip}
                {this.listType !== 'file' ? uploadList : ''}
            </div>
        );
    }
};
</script>
