import React, { Component } from 'react';
import { PageComponent, } from '../../types/index';
import { message, Spin, Progress, Modal, Icon } from 'antd';
import QiniuUploader from './qiniuUploader'
import * as Tools from 'jad-tool';


type limitType = '=='|'<='|'<'|'>'|'>='|'!=';
type whProportionType = {width:number,height:number};
type imgCondition = {
    // 上传相关的
    aspectRatio?: number;
    maxWidth?: number;
    minWidth?: number;
    maxHeight?: number;
    minHeight?: number;
    whProportion?:whProportionType,
    validateVolume?:{proportion?:whProportionType,limit:limitType,width:number,height:number}[]
    fileSizeMax?: number; // 单位kb
    fileSizeMin?: number; // 单位kb
    fileSizeLimitValue?: number;
    fileSizeLimit?: limitType;
    fileType?: string[]; // [.jpg, .png]
    maxLength?: number; // 最长
    minLength?: number; // 最短
    required?: boolean;
    imgTotalLimit?: number[];
    maxNumber?: { limit: number, keys: string[] };
    minNumber?: { limit: number, keys: string[] };
    equal?: { limit: number, keys: string[] };
    pattern?: string;
    defaultUploadRender?: any;
}
const defaultCcondition = {
    fileSizeMax: 1024,            //单位kb
    fileType: ['jpg', 'png'],   // [.jpg, .png]
}
const _getTransfer = function (event: any) {
    return event.dataTransfer ? event.dataTransfer : event.originalEvent.dataTransfer; // jQuery fix;
}
const getImgWidth = function (src: string): any {
    return new Promise(function (resolve, reject) {
        var img = new Image()
        
        img.src = src
        if (img.complete) {
            resolve({
                width: img.width,
                height: img.height,
            })
        } else {

            img.onload = function () {
                resolve({
                    width: img.width,
                    height: img.height,
                })
            }
            img.onerror = function () {
                reject(false)
            }
        }
    })

}
const _haveFiles = function (types: any) {
    if (!types) {
        return false;
    }

    if (types.indexOf) {
        return types.indexOf('Files') !== -1;
    } else if (types.contains) {
        return types.contains('Files');
    } else {
        return false;
    }
}
const _preventAndStop = function (event: any) {
    event.preventDefault();
    event.stopPropagation();
}
const limitToText = function(limit?:limitType){
    if(!limit) return ''
    switch(limit){
        case "==":
            return '等于'
        case '<':
            return '小于'
        case '<=':
            return '小于等于'
        case '>':
            return '大于'
        case '>=':
            return '大于等于'
        case '!=':
            return '不等于'
        default:
            return ''
    }
}
const limitExec = function(limit:limitType,s1:number,s2:number){
    switch(limit){
        case "==":
            return s1 == s2;
        case '<':
            return s1 < s2;
        case '<=':
            return s1 <= s2;
        case '>':
            return s1 > s2;
        case '>=':
            return s1 >= s2;
        case '!=':
            return s1 !== s2;
        default:
            return false
    }
}



export class Uploder extends Component<PageComponent<{
    title?: string,
    volumeText?:string,
    sizeText?:string,
    typeText?:string
    condition?: imgCondition,
    value?: string,
    url?: string,
    imgWrapStyle?:any,
    disabled?: boolean,
    onChange?: (url:string)=>void,
    //must
    onValidate?: (task:any,config:any,image:HTMLImageElement)=>boolean,
    CDNToken:string,
    CDNUrl:string
}>> {
    state = {
        //实例
        uploader: null,
        //参数
        uploadProgress: 0,
        dialogWidth: 500,
        previewVisible: false,
        status: 'empty',
        loading: false
    }

    constructor(props) {
        super(props)
        this.resetUpLoadService()
    }

    UNSAFE_componentWillReceiveProps(nextProps){
        if(!this.props.CDNToken && nextProps.CDNToken){
            this.resetUpLoadService()
        }
    }


    resetUpLoadService() {
        const uploader = this.initUploadService()
        this.setState({
            uploader: uploader
        })
    }
    initUploadService() {
        const { condition, onChange=()=>null,CDNToken,CDNUrl } = this.props
        if(!CDNToken || !CDNUrl) return null;
        const uploadService = new QiniuUploader()
        const config = Tools.extend({}, defaultCcondition, condition)
        const accept = config.fileType.map(e=>e.toLowerCase())
        let ifInterrupt = false;
        let progressInterval;
        const commonMiddle = {
            onStart: (task) => {
                this.setState({
                    uploadProgress: 0,
                    status: 'uploading'
                })
                progressInterval = setInterval(() => {
                    let { uploadProgress } = this.state
                    if (uploadProgress >= 80) return;
                    uploadProgress += 10;
                    this.setState({
                        uploadProgress: uploadProgress,
                    })
                }, 100);
            },
            onSuccess: (task, url) => {
                clearInterval(progressInterval);
                setTimeout(() => {
                    this.setState({
                        uploadProgress: 100,
                        status: 'done'
                    })
                }, 1000);
                this.setState({
                    loading: false
                })
                onChange(url)
            },
            onProgress: (task) => {
                this.setState({
                    uploadProgress: task.progress,
                    status: 'uploading'
                })
            },
            onFinish: () => {
                this.setState({
                    loading: false,
                })
            },
            onFail: () => {
                this.setState({
                    loading: false,
                    uploadProgress: 0,
                    status: 'empty',
                })
            },
            onIntercept: (task): Promise<any> => {
                return new Promise((resolve, reject)=>{
                    var validateImage = new Image();
                    validateImage.src = URL.createObjectURL(task._file)
                    validateImage.onload = () => {
                        resolve({task,config,image:validateImage})
                    }
                    validateImage.onerror = () => reject()
                })
                .then(this.validateImageTypeTransaction.bind(this))
                .then(this.validateImageWHTransaction.bind(this))
                .then(this.validateImageSizeTransaction.bind(this))
                .then(this.validateCustomTransaction.bind(this))
                //验证成功返回false
                .then(()=>false)
                //验证失败返回true
                .catch((err)=>{
                    console.error(err)
                    message.error(Tools.toString(err),5)
                    ifInterrupt = true;
                    return Promise.resolve(true)
                })
            },
            onInterrupt: (task) => {
                //是否取消上传 return true | false
                if (ifInterrupt) {
                    message.error('图片不符合规格，请重新上传')
                    ifInterrupt = false;
                    return true;
                }
                return false;
            },
        };
        uploadService.init(accept,CDNToken,CDNUrl)
        uploadService.addMiddleWares(commonMiddle);
        return uploadService;
    }


    /*
        验证失败直接 throw error 
        成功则返回向下传递
    */
    validateImageTypeTransaction({task,config,image}){
        let { fileType } = config
        fileType = fileType.map(e=>e.replace('.',''))
        let uploadtype = task.file.name.split('.').pop();
        if (fileType.indexOf(uploadtype) === -1) {
            throw new Error('验证图片类型失败,不符合上传类型')
        }
        return {task,config,image}
    }
    validateImageWHTransaction({task,config,image}){
        let { maxWidth,minWidth,maxHeight,minHeight,validateVolume,whProportion } = config
        const imgWidth = image.naturalWidth || image.width
        const imgHeiht = image.naturalHeight || image.height
        if (!imgWidth && !imgHeiht) {
            throw new Error('验证图片失败,未获取到图片宽高')
        }
        //limit
        if(validateVolume){
            var errorMsg = ''
            var batchValidate = validateVolume.some(({limit,width,height,proportion})=>{
                if(!limitExec(limit,imgWidth,width)){
                    errorMsg = `验证图片失败,图片宽度${imgWidth}不符合${limitToText(limit)}${width}限制`;
                    return false;
                }
                if(!limitExec(limit,imgHeiht,height)){
                    errorMsg = `验证图片失败,图片高度${imgHeiht}不符合${limitToText(limit)}${height}限制`;
                    return false;
                }
                if(proportion && imgWidth / imgHeiht !== proportion.width/proportion.height  ){
                    errorMsg = `验证图片失败,图片宽度高度比例不符合${proportion.width}:${proportion.height}限制`;
                    return false;
                }
                return true
            })
            if(!batchValidate){
                throw new Error(errorMsg)
            }
            return {task,config,image}
        }
        //default 
        if( maxWidth && imgWidth>maxWidth ){
            throw new Error(`验证图片失败,图片宽度${imgWidth}超出限制`)
        }
        if( minWidth && imgWidth<minWidth ){
            throw new Error(`验证图片失败,图片宽度${imgWidth}小余限制`)
        }
        if( maxHeight && imgHeiht>maxHeight ){
            throw new Error(`验证图片失败,图片高度${imgHeiht}超出限制`)
        }
        if( minHeight && imgHeiht>minHeight ){
            throw new Error(`验证图片失败,图片高度${imgHeiht}小余限制`)
        }
        if(whProportion && imgWidth / imgHeiht !== whProportion.width/whProportion.height  ){
            throw new Error(`验证图片失败,图片宽度高度比例不符合${whProportion.width}:${whProportion.height}限制`)
        }
        return {task,config,image}
    }
    validateImageSizeTransaction({task,config,image}){
        const { fileSizeMax,fileSizeMin,fileSizeLimit,fileSizeLimitValue } = config
        const size = Math.ceil(task._file.size / 1024)
        if(fileSizeLimit && fileSizeLimitValue && !limitExec(fileSizeLimit,size,fileSizeLimitValue)){
            throw new Error(  `验证图片失败,图片大小${size}不符合${limitToText(fileSizeLimit)}${fileSizeLimitValue}限制`)
        }
        if(fileSizeMax && size > fileSizeMax){
            throw new Error(`验证图片失败,图片大小${size}kb超出限制`)
        }
        if(fileSizeMin && size < fileSizeMin){
            throw new Error(`验证图片失败,图片大小${size}kb小于限制`)
        }
        return {task,config,image}
    }
    validateCustomTransaction({task,config,image}){
        const { onValidate } = this.props
        if(onValidate){
            const result = onValidate(task,config,image)
            if(!result){
                throw new Error(`验证图片失败`)
            }
        }
        return {task,config,image}
    }


    onHandleClick(e) {
        const { uploader } = this.state
        const { disabled } = this.props
        if(disabled){
            return false;
        }
        if (!uploader) {
            return this.resetUpLoadService()
        }
        let { url } = this.props;
        if (url) {
            return
        }
        _preventAndStop(e)
        uploader.popupUplod()
    }
    onHandleFileDrop(e) {
        const { uploader } = this.state
        const { disabled } = this.props
        if(disabled){
            return false;
        }
        if (!uploader) {
            return this.resetUpLoadService()
        }
        _preventAndStop(e)
        const transfer = _getTransfer(event);
        if (!_haveFiles(transfer.types)) {
            return;
        }
        uploader.upload(transfer.files);
    }
    onHandleDropMove(e) {
        _preventAndStop(e)
        const transfer = _getTransfer(event);
        if (!_haveFiles(transfer.types)) {
            return;
        }
        transfer.dropEffect = 'copy';
    }
    onPreview(e) {
        e.stopPropagation();
        let { url,value } = this.props;
        url = url || value
        getImgWidth(url).then((res) => {
            let dialogWidth = res.width
            if (dialogWidth < 50) {
                dialogWidth = 50
            }
            if (dialogWidth > 1200) {
                dialogWidth = 1200
            }

            this.setState({
                previewVisible: true,
                dialogWidth
            })
        })

    }
    onDelete(e) {
        e.stopPropagation();
        const { disabled,onChange=()=>null } = this.props
        if(disabled){
            return false;
        }
        this.setState({
            status: 'empty',
        })
        onChange('')
    }


    renderProgress() {
        const { uploadProgress, status } = this.state
        if (status === 'empty' || status === 'done') {
            return null
        }
        return (
            <div className='jad-uploder-progress-modal' >
                <Progress type="circle" percent={uploadProgress} />
            </div>
        )
    }
    renderImgPreview(){
        let {  url,value,imgWrapStyle } = this.props;
        url = url || value
        return <div className='jad-uploder-img-wrap' style={imgWrapStyle}>
            <img src={url}  className='jad-uploder-img' alt="读取失败" />
            <div className='jad-uploder-asset-mask'>
                <span className='jad-uploder-asset-action' onClick={this.onDelete.bind(this)}>
                    <Icon type="close" />
                </span>
                <span className='jad-uploder-asset-action-1' onClick={this.onPreview.bind(this)}>
                    <Icon type="fullscreen" />
                </span>
            </div>
        </div>
    }
    renderUpload(){
        let { condition,volumeText,typeText,sizeText } = this.props;
        let config = Tools.extend({}, defaultCcondition, condition)
        const { fileType,fileSizeMax,width,height,validateVolume,whProportion,fileSizeLimitValue,fileSizeLimit } = config
        return config.defaultUploadRender?config.defaultUploadRender(config):<React.Fragment>
            <p className="icon"><Icon type="cloud-upload" /></p>
            <p className="title">点击或将文件拖拽到这里上传</p>
            <div className='content'>
                支持扩展名:&nbsp;&nbsp;{typeText? typeText: fileType.map(e => e.replace(/[^a-zA-Z]/g, '')).join(',').toLowerCase()},
                图片大小:{volumeText? volumeText: 
                        validateVolume?validateVolume.map(({limit,width,height,proportion},index)=>`${limitToText(limit)}${width}px*${height}px${index ===validateVolume.length -1?'':','}${proportion?`,宽高比:${proportion.width}:${proportion.height}${index ===validateVolume.length -1?'':','}`:''}`)
                        :Tools.isUndefined(width)||Tools.isUndefined(height)?'不限':`${width}px*${height}px`},
                {whProportion?`宽高比:${whProportion.width}:${whProportion.height},`:null}
                {fileSizeLimit &&fileSizeLimitValue ?`${limitToText(fileSizeLimit)}${(fileSizeLimitValue<1000?`${fileSizeLimitValue}KB`:`${((fileSizeLimitValue) / 1024).toFixed(1)}M`)}`
                :`小于等于${sizeText? sizeText: (fileSizeMax<1000?`${fileSizeMax}KB`:`${((fileSizeMax) / 1024).toFixed(1)}M`)}`}
            </div>
        </React.Fragment>
    }
    renderContent() {
        let { url,value } = this.props;
        return url || value ? this.renderImgPreview() : this.renderUpload()
    }
    render() {
        let { url,value,disabled=false } = this.props;
        const { loading, dialogWidth } = this.state
        url = url || value
        return (
            <Spin spinning={loading}>
                <div
                    style={{'backgroundColor':disabled?'#f5f5f5':''}}
                    className='jad-uploder-warp'
                    onClick={this.onHandleClick.bind(this)}
                    onDrop={this.onHandleFileDrop.bind(this)}
                    onDragOver={this.onHandleDropMove.bind(this)}
                >
                    {
                        this.renderContent()
                    }

                    {this.renderProgress()}
                </div>

                <Modal visible={this.state.previewVisible}
                    width={dialogWidth + 24 * 2 + 15 * 2}
                    footer={null}
                    maskClosable={false}
                    onCancel={() => {
                        this.setState({
                            previewVisible: false
                        })
                    }}>
                    <div className='jad-uploder-source-image' >
                        <img src={url}  alt="图片加载失败" />
                    </div>
                </Modal>
            </Spin>
        )
    }


}



 
