import { NoticeType } from './const/index';

type NoticeWatch = {

    [key in NoticeType] ?: {
        watch:{
            [propName:string]: {
                watch:{
                    [propName:string]: Function
                },
                length:number
            }
        },
        length:number,
        condition?:{
            [propName:string]:Array<string>
        }
    }

}

export default class Notice {

    constructor() {
        for (let i=0,count=this.conditionOrder.length;i<count;i++) {
            this.conditionOrderObject[this.conditionOrder[i]] = i;
        }
    }

    // 监听对象
    observation:NoticeWatch = {};

    // 筛选条件的索引
    conditionFormat:Record<keyof NoticeCondition,string> = {
        userId:'uid',
        roomId:'rid'
    };

    // 排序
    conditionOrder:Array<keyof NoticeCondition> = ['userId','roomId'];
    // @ts-ignore
    conditionOrderObject:Record<keyof NoticeCondition, number> = {};

    // 设置监听
    on(name:string,callback:Function,type:NoticeType = NoticeType.message,condition?:NoticeCondition){

        if(!callback) return null;

        if (this.observation[type] === undefined) {
            this.observation[type] = {length:0,condition:{},watch:{}};
        }
        // 设置type
        let targetType = this.observation[type];


        // 构建条件
        let conditionName = this.createConditionName(condition);

        // 创建
        if (targetType.watch[name] === undefined) {
            targetType.watch[name] = {
                watch:{},
                length:0
            }
            targetType.length++;
        }


        // 添加回调函数
        this.addNoticeItem(targetType.watch[name],conditionName,callback);

        // 添加快照属性
        if (targetType.condition[conditionName] === undefined) targetType.condition[conditionName] = [];
        if (targetType.condition[conditionName].indexOf(name) < 0) targetType.condition[conditionName].push(name);

        return this;

    }

    // 移除监听
    off(name:string,type:NoticeType = NoticeType.message,condition?:NoticeCondition | boolean){

        if (this.observation[type]) {

            let targetItem = this.observation[type];

            // 如果为 boolean 且不存在name 则为全部移除
            if (condition === true && !name) {
                // 如果存在此类型
                if (targetItem.watch[name].watch) {
                    // 删除所有条件
                    for (let key in targetItem.watch[name].watch) {
                        if (targetItem.watch[name].watch.hasOwnProperty(key)) {
                            if (targetItem.condition[key]) {
                                this.deleteCondition(targetItem,key,name);
                            }
                        }
                    }
                    // 删除
                    this.deleteNoticeItem(targetItem,name);
                }
            } else {

                // 构建条件
                let conditionName = this.createConditionName(condition);

                if (targetItem.watch[name] && targetItem.watch[name].watch && targetItem.watch[name].watch[conditionName]) {

                    // 删除此模式
                    this.deleteCondition(targetItem,conditionName,name);

                    // 删除
                    this.deleteNoticeItem(targetItem.watch[name],conditionName);

                    if (targetItem.watch[name].length <= 0) {
                        delete targetItem.watch[name];
                        targetItem.length--;
                    }

                }

            }

            // 执行判断
            if (targetItem.length <= 0) {
                delete this.observation[type];
            }

        }

        return this;

    }

    // 触发监听
    triggerNotice(type:NoticeType,params:any,condition?:NoticeCondition){

        if (this.observation[type]) {

            let triggerName = {};

            // 执行触发 规则
            if (condition) {

                // 触发单组模式
               let conditionName = this.createConditionName(condition, (name)=> {
                   if (!triggerName[name]) {
                       triggerName[name] = true;
                       this.triggerNoticeList(type,name,params);
                   }
               });

               // 执行触发组合模式
               if (!triggerName[conditionName]) {
                  triggerName[conditionName] = true;
                  this.triggerNoticeList(type,conditionName,params);
               }

            }

            // 执行触发 默认模式
            if (!triggerName['default']) {
                this.triggerNoticeList(type,'default',params);
            }

        }

        return this;

    }

    // 触发函数
    triggerNoticeList(type,conditionName,params:any){


        let targetItem = this.observation[type];

        if (targetItem && targetItem.condition && targetItem.condition[conditionName]) {
            // 执行触发
            targetItem.condition[conditionName].map(function(name){
                if (targetItem.watch[name] && targetItem.watch[name].watch[conditionName]) {
                    return targetItem.watch[name].watch[conditionName](params);
                }
            });
        }
    }

    addNoticeItem(target,name,value){
        if (target.watch[name] === undefined) {
            target.length++;
        }
        target.watch[name] = value;
    }

    deleteNoticeItem(target,name){
        if (target.watch[name]) {
            delete target.watch[name];
            target.length--;
        }
    }

    deleteCondition(targetItem,key,name){
        let index = targetItem.condition[key].indexOf(name);
        if (index >= 0) {
            if (targetItem.condition[key].length <= 0) {
                delete targetItem.condition[key];
            } else {
                targetItem.condition[key].splice(index,1);
            }
        }
    }

    createConditionName(condition,callback?){

        if (condition) {

            let names:Record<string,string> = {};
            for (let key in condition) {
                if (condition.hasOwnProperty(key) && this.conditionOrderObject[key] !== undefined) {
                    names[this.conditionOrderObject[key]] = this.createConditionNameItem(key,condition);

                    callback && callback(names[this.conditionOrderObject[key]]);
                }
            }

            let name:string = Object.values(names).join('-');

            return name || 'default';

        } else {
            return 'default';
        }

    }

    createConditionNameItem(key,condition) {
        return this.conditionFormat[key] +':'+condition[key];
    }


}