import { InstructionsWhere,InstructionsTypes } from '../const/request';

export default class Instructions {

    static options:Array<LibRequestOptionsKeyOf> = ['triggerType','where','zIndex'];

    static defaultOptions:Pick<LibRequestInstructionsObject,LibRequestOptionsKeyOf> = {
      triggerType: InstructionsTypes.start,
      where: InstructionsWhere.has,
      zIndex:0
    };

    static defaultUnshift:{ [key in InstructionsWhere]?:boolean } = {
        [InstructionsWhere.skip]:true
    }

    static NotHas:{ [key in InstructionsWhere]?:boolean } = {
        [InstructionsWhere.custom]:true
    }

    // 配置文件表
    config:{ [key in InstructionsTypes]?:InstructionsTypeConfig} = {
        [InstructionsTypes.start]:{},
        [InstructionsTypes.end]:{}
    };

    constructor(configs?:Record<string, LibRequestInstructions>,options?:LibRequestInstructionsObject) {
        configs && this.pushConfig(configs,options);
    }

    // 执行函数列表
    triggers:Record<string, LibRequestInstructionsObject> = {};

    // 增加添加配置文件
    pushConfig(data:Record<string, LibRequestInstructions>,options?:LibRequestInstructionsObject):Instructions{

        for (let key in data) {
            if (data.hasOwnProperty(key)) {
                this.push(key,data[key],options);
            }
        }

        return this;
    }

    push(name:string,data:LibRequestInstructions,options?:LibRequestInstructionsObject){

        if (this.triggers[name]) return;

        let resultData:LibRequestInstructionsObject;

        if (typeof data === 'function') {
            resultData = {
                trigger: data
            };
        } else {
            resultData = data as LibRequestInstructionsObject;
        }

        for (let i=0,count = Instructions.options.length;i<count;i++) {
            if (resultData[Instructions.options[i]] === undefined) {
                // @ts-ignore
                resultData[Instructions.options[i]] = options && options[Instructions.options[i]] ? options[Instructions.options[i]] : Instructions.defaultOptions[Instructions.options[i]];
            }
        }

        let where:InstructionsWhere = resultData.where === undefined && typeof resultData.whereTrigger === 'function' ? InstructionsWhere.hasCustom : resultData.where as InstructionsWhere;

        if (resultData.triggerType === InstructionsTypes.start || resultData.triggerType === InstructionsTypes.all) {
            this.setTypeWhere(<InstructionsTypeConfig>this.config[InstructionsTypes.start],name,resultData,where);
        }

        if (resultData.triggerType === InstructionsTypes.end || resultData.triggerType === InstructionsTypes.all) {
            this.setTypeWhere(<InstructionsTypeConfig>this.config[InstructionsTypes.end],name,resultData,where);
        }

        this.triggers[name] = resultData;
    }

    setTypeWhere(data:InstructionsTypeConfig,name:string,resultData:LibRequestInstructionsObject,where:InstructionsWhere){

        if (data.orderObject === undefined) {
            data.orderObject = {};
        }

        if (Instructions.defaultUnshift[where]) {

            if (data.unshiftObject === undefined) {
                data.unshiftObject = {};
            }

            data.unshiftObject[name] = resultData.zIndex || 999;
            data.orderObject[name] =  data.unshiftObject[name];

        } else if (resultData.zIndex != null){
           data.orderObject[name] = resultData.zIndex;
        }

        if (Instructions.NotHas[where]) {
            if (data.notHas === undefined) {
                data.notHas = [name];
            } else {
                data.notHas.push(name);
            }
        }



    }

    static createRequestContext(data:LibRequestContext){
        // 创建执行环境
        data.execContext = true;
        // 创建退出函数
        data.exit = function (name:string,fail:boolean = true) {
            // 是否提示fail
            fail && data.reject(<InstructionsExitStatus>{
                status:-200,
                msg:name + ':exit',
                exit:true
            });

            // 释放所有的事件
            for (let key in data) {
                if (data.hasOwnProperty(key)) {
                    // @ts-ignore
                    delete data[key];
                }
            }
        }

        return data;

    }

    // 根据配置表 执行配置
    trigger(data:LibRequestContext,type:InstructionsTypes = InstructionsTypes.start):boolean{

        try {
            // @ts-ignore
            let config:InstructionsTypeConfig = this.config[type];

            let resultData:Record<string,number> = {};
            // 执行前缀合并
            if (config.unshiftObject) {
                Object.assign(resultData,config.unshiftObject);
            }
            // 执行验证 不需要存在即可执行的定义
            if (config.notHas) {
                for (let i=0,count = config.notHas.length;i<count;i++) {

                    if (resultData[config.notHas[i]] === undefined &&
                        (
                            // @ts-ignore
                            this.whereTrigger[this.triggers[config.notHas[i]].where] === undefined
                            ||
                            // @ts-ignore
                            this.whereTrigger[this.triggers[config.notHas[i]].where](config.notHas[i],data,this)
                        )){
                        // @ts-ignore
                        resultData[config.notHas[i]] = config.orderObject[config.notHas[i]];
                    }
                }
            }

            // 构建触发表
            for (let key in data.requestData) {
                // @ts-ignore
                if (data.requestData.hasOwnProperty(key) && resultData[key] === undefined && config.orderObject[key] !== undefined) {
                    // @ts-ignore
                    if (!this.whereTrigger[this.triggers[key].where] || this.whereTrigger[this.triggers[key].where](key,data,this)) {
                        // @ts-ignore
                        resultData[key] = config.orderObject[key];
                    }
                }
            }

            // 触发data
            let orderList = Object.keys(resultData).sort(function (a:string,b:string){
                return resultData[a] > resultData[b] ? -1 : 1;
            });

            // 执行触发
            for (let i=0,count=orderList.length;i<count;i++) {

                // 执行
                // @ts-ignore
                this.triggers[orderList[i]].trigger(data);
                if (data.execContext === undefined) return false;

            }

            return data.execContext !== undefined;
        } catch (e) {
            console.log(e);
        }


        return  true;





    }

    // 触发条件
    whereTrigger ={

        // 自定义校验
        [InstructionsWhere.custom]:function(name:string,data:LibRequestContext,config:Instructions){

            if (config.triggers[name] && config.triggers[name].whereTrigger) {
                // @ts-ignore
                return config.triggers[name].whereTrigger(data);
            } else {
                return false;
            }

        },
        // 存在自定义验证
        [InstructionsWhere.hasCustom]:function(name:string,data:LibRequestContext,config:Instructions){
            return  this[InstructionsWhere.custom](name,data,config);
        }
    }

}