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 GBattleModeManager from "./battle/GBattleModeManager";
import { GLayer, GUI, UIConfig } from "./ui/UIConfig";
import JLoaderSystem from "../../extensions/ngame/assets/ngame/system/JLoaderSystem";
import { sp } from "cc";
import { SpriteFrame } from "cc";
import Loading from "../../extensions/ngame/assets/ngame/util/Loading";
import { Tables } from "../resources/config/data/schema";
import { JsonAsset } from "cc";
import { GAction } from "./consts/GAction";
import { StorageData, StorageEnum } from "./consts/GData";
import { JAPI, JAPIConfig } from "../../extensions/ngame/assets/ngame/util/JAPI";
import { AppData } from "./AppData";
import AppAction from "./AppAction";

let APIPath = `http://localhost:8080`
let WsPath = `ws://localhost:8080/websocket`
// let APIPath = `http://192.168.1.23:8080`
// let WsPath = `ws://192.168.1.23:8080/websocket`
// let APIPath = `http://192.168.0.123:8080`
// let WsPath = `ws://192.168.0.123:8080/websocket`
// let APIPath = `https://api.pet.jisol.cn`
// let WsPath = `wss://api.pet.jisol.cn/websocket`

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

//重写Socket
class JNGSocket extends JNSocket{
    async onInit() {
        this.on(GAction.TOKEN_EXPIRED,this.onTokenExpired.bind(this));
        await super.onInit();
    }
    public url():Promise<string> {
        return new Promise<string>(resolve => {
            //获取Token
            let token = StorageData.get(StorageEnum.Token);
            if(token){
                resolve(`${WsPath}/${token}`)
                return;
            }

            const loginResolve = (token:string) => {
                resolve(`${WsPath}/${token}`);
            }
            //如果没有Token则弹出登入页面
            app.layer.Open(GUI.Login,loginResolve);
        });
    }
    //Token失效
    onTokenExpired(){
        console.log("onTokenExpired");
        //清除Token
        StorageData.delect(StorageEnum.Token);
    }
}

// 重写帧同步
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);
    }

}


export var TD:Tables = null;
//读写config
export class JNGConfig extends SystemBase{

    static loading = "JNGConfig";
    
    async onInit(): Promise<any> {

        app.loading.setCurrent(JNGConfig.loading);

        let json2 = resources.getDirWithPath("config/json/",JsonAsset).map((info) => {
            let args = info.path.split("/");
            return {
                name:args[args.length - 1],
                bundle:"resources",
                path:"config/json/"
            }
        })

        for (const key in json2) {
            const load = json2[key];
            await JsonUtil.load(load);
        }

        TD = new Tables((file) => JsonUtil.get(file))
        console.log(TD);

        app.loading.ok(JNGConfig.loading);
    }

}

//资源初始器
export class JLoaderBattle extends JLoaderSystem{

    static loading = "JLoaderBattle";
    static loadingInit = "JLoaderBattle_Init";

    roleSpine:{[id:number]:sp.SkeletonData} = {};       //角色Spine
    roleResImage:{[id:number]:SpriteFrame} = {};        //角色战斗素材图片
    roleResSpine:{[id:number]:sp.SkeletonData} = {};    //角色战斗素材Spine
    effects:{[id:number]:sp.SkeletonData} = {};         //Spine特效
    maps:{[id:number]:SpriteFrame[]} = {};              //地图

    async onInit(): Promise<any> {

        app.loading.setCurrent(JLoaderBattle.loading);

        await super.onInit();

        app.loading.ok(JLoaderBattle.loading);

        app.loading.setCurrent(JLoaderBattle.loadingInit);

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

        //读取角色战斗素材
        for(const info of TD.TbGRoleBattleRes.getDataMap().values()){
            if(info.resType == "Spine"){
                this.roleResSpine[info.id] = await (new Promise(r => {
                    this.bundle.load(info.resSrc,sp.SkeletonData,(err,data) => {
                        r(data);
                    })
                }))
            }else{
                this.roleResImage[info.id] = await (new Promise(r => {
                    this.bundle.load(info.resSrc,SpriteFrame,(err,data) => {
                        r(data);
                    })
                }))
            }
        }

        //读取地图
        for (const info of TD.TbGMap.getDataMap().values()) {

            this.maps[info.id] = await (Promise.all(["1","2","3"].map(index => `map${index}`).map(key => {
                return new Promise<SpriteFrame>(r => {
                    if(info[key]){
                        this.bundle.load(info[key],SpriteFrame,(err,data) => {
                            r(data);
                        })
                    }
                })
            })))
            
        }

        app.loading.ok(JLoaderBattle.loadingInit);
        
    }

}

export const app = {
    layer : new JNGLayer(), //UI
    socket : new JNGSocket(), //Socket
    sync : new JNGSyncFrame(), //同步
    event : EventDispatcher.getIns(), //通知
    proto : NGameMessage.getIns(), //消息
    api : JAPI.create({
        baseURL: `${APIPath}`,
    }), //请求
    // api : {}, //请求
    battle : GBattleModeManager.getIns(), //战斗
    config : new JNGConfig(), //配置文件
    battleRes : new JLoaderBattle("battle"), //battle包
    data : new AppData(), //游戏基础信息
    action : new AppAction(), //游戏行为
    loading : new Loading({
        [JNGConfig.loading]:{title:"加载配置文件"},
        [JLoaderBattle.loading]:{title:"加载战斗资源"},
        [JLoaderBattle.loadingInit]:{title:"初始化战斗资源"},
        [AppData.loading]:{title:"初始化信息"},
    })
}

app.api.addRequestInterceptors((config:JAPIConfig) => {
    //设置Token
    if(StorageData.get(StorageEnum.Token))
        config.headers["Token"] = StorageData.get(StorageEnum.Token);
    return true;
})