import { resources } from "cc";
import { BehaviorManager } from "../../extensions/Behavior Creator/runtime/main";
import SystemBase from "../../extensions/ngame/assets/ngame/system/SystemBase";
import JNSocket from "../../extensions/ngame/assets/ngame/network/JNSocket";
import { JNSyncAction } from "../../extensions/ngame/assets/ngame/sync/JNSyncAction";
import { JNSyncMessage } from "../../extensions/ngame/assets/ngame/sync/JNSyncMessage";
import JNSyncFrame, { JNFrameInfo, JNFrameInfos, JNFrameInputs } from "../../extensions/ngame/assets/ngame/sync/frame/JNSyncFrame";
import JNSyncFrameComponent from "../../extensions/ngame/assets/ngame/sync/frame/game/JNSyncFrameComponent";
import JNSyncFrameProtoComponent from "../../extensions/ngame/assets/ngame/sync/frame/game/JNSyncFrameProtoComponent";
import JNLayer, { JNLayerAnim, JNLayerInfo } from "../../extensions/ngame/assets/ngame/ui/JNLayer";
import JNLayerBase from "../../extensions/ngame/assets/ngame/ui/base/JNLayerBase";
import { EventDispatcher } from "../../extensions/ngame/assets/ngame/util/EventDispatcher";
import { JsonLoad, JsonUtil } from "../../extensions/ngame/assets/ngame/util/JsonUtil";
import NGameMessage from "../../extensions/ngame/assets/ngame/util/NGameMessage";
import axios from "../../extensions/ngame/assets/plugins/axios.js";
import GBattleModeManager from "./battle/GBattleModeManager";
import { GLayer, UIConfig } from "./ui/UIConfig";
import JLoaderSystem from "../../extensions/ngame/assets/ngame/system/JLoaderSystem";
import { TableGRole } from "../resources/config/ts/TableGRole";
import { sp } from "cc";
import { TableGRoleAttack } from "../resources/config/ts/TableGRoleAttack";
import { SpriteFrame } from "cc";
import { TableGRoleAttackBullet } from "../resources/config/ts/TableGRoleAttackBullet";
import { TableGRoleAttackEffect } from "../resources/config/ts/TableGRoleAttackEffect";
import { TableGRoleSkill } from "../resources/config/ts/TableGRoleSkill";
import { TableGRoleSkillEffect } from "../resources/config/ts/TableGRoleSkillEffect";

let IP = "kyu.jisol.cn";

//重写UI
class JNGLayer extends JNLayer{
    layers: string[] = [GLayer.View];
    views: { [key: string]: JNLayerInfo; } = UIConfig;
}

//重写Socket
class JNGSocket extends JNSocket{
    public url() {
        return `ws://${IP}:8080/websocket`;
    }
}

// 重写帧同步
class JNGSyncFrame extends JNSyncFrame{

    protected onResetValue(){
        //重置状态机
        BehaviorManager.deleteInstance();
        super.onResetValue();
    }

    async onServerData(start?:number,end?:number): Promise<JNFrameInfos> {

        return app.proto
                .getType(JNSyncMessage.JNFrameInfos)
                .decode(
                    new Uint8Array(

                        (await app.api.get("/sync/frame",{
                            responseType:'arraybuffer',
                            params:{
                                start,
                                end
                            }
                        })).data
                    )
                ) as any;

    }

    onSendInput(message: JNFrameInputs) {
        app.socket.Send(JNSyncAction.NSyncFrameInput,message,JNSyncMessage.JNFrameInputs);
    }

}

//重写UI Base
export class JNGLayerBase extends JNLayerBase{
    public close():void {
        console.log("close");
        app.layer.CloseNode(this.node);
    }
}

//重写Sync Base
export class JNGSyncBase<T> extends JNSyncFrameComponent<T>{
    onSyncLoad() { }
    onSyncUpdate(dt: number,frame:JNFrameInfo, input?: T) { }
    protected getSync(): JNSyncFrame {
        return app.sync
    }

}
//重写Sync Proto Base
export abstract class JNGSyncProtoBase<T> extends JNSyncFrameProtoComponent<T>{

    onSyncLoad() { }
    onSyncUpdate(dt: number,frame:JNFrameInfo, input?: T) { }
    protected getSync(): JNSyncFrame {
        return app.sync
    }

}

//读写config
export class JNGConfig extends SystemBase{

    //配置JSON加载
    jsons:JsonLoad[] = [
        {name:TableGRole.TableName}, //角色
        {name:TableGRoleAttack.TableName}, //角色攻击
        {name:TableGRoleAttackBullet.TableName}, //角色攻击子弹
        {name:TableGRoleAttackEffect.TableName}, //角色攻击特效
        {name:TableGRoleSkill.TableName}, //角色技能
        {name:TableGRoleSkillEffect.TableName}, //角色技能特效
    ].map((table) => {
        return {
            name:table.name,
            bundle:"resources",
            path:"config/game/"
        }
    });
    
    async onInit(): Promise<any> {
        for (const key in this.jsons) {
            const load = this.jsons[key];
            await JsonUtil.load(load);
        }
    }

}

//角色初始器
export class JLoaderRole extends JLoaderSystem{

    skData:{[id:number]:sp.SkeletonData} = {};
    bullets:{[id:number]:SpriteFrame} = {};
    effects:{[id:number]:sp.SkeletonData} = {};

    async onInit(): Promise<any> {
        await super.onInit();

        //将配置表的角色都读取出来
        for (const info of Object.values(TableGRole.getAllConfig())) {
            this.skData[info.id] = await (new Promise(r => {
                this.bundle.load(info.spine,sp.SkeletonData,(err,data) => {
                    r(data);
                })
            }))
        }

        //将所有子弹读取出来
        for (const info of Object.values(TableGRoleAttackBullet.getAllConfig())) {
            this.bullets[info.id] = await (new Promise(r => {
                this.bundle.load(info.bulletSrc,SpriteFrame,(err,data) => {
                    r(data);
                })
            }))
        }

        //攻击特效读取
        for (const info of Object.values(TableGRoleAttackEffect.getAllConfig())) {
            this.effects[info.id] = await (new Promise(r => {
                this.bundle.load(info.spine,sp.SkeletonData,(err,data) => {
                    r(data);
                })
            }))
        }

        //技能特效读取
        for (const info of Object.values(TableGRoleSkillEffect.getAllConfig())) {
            this.effects[info.id] = await (new Promise(r => {
                this.bundle.load(info.spine,sp.SkeletonData,(err,data) => {
                    r(data);
                })
            }))
        }
        
    }

}

export const app = {
    layer : new JNGLayer(), //UI
    socket : new JNGSocket(), //Socket
    sync : new JNGSyncFrame(), //同步
    event : EventDispatcher.getIns(), //通知
    proto : NGameMessage.getIns(), //消息
    api : axios.create({
        baseURL: `http://${IP}:8080`,
    }), //请求
    battle : GBattleModeManager.getIns(), //战斗
    config : new JNGConfig(),
    role : new JLoaderRole("role"), //role包
}