import { eg } from "../frameWork/eg";
import { GameServerConfig } from "../network/GameServerConfig";

import { HttpClient as HttpClient_Browser, TsrpcError, WsClient as WsClient_Browser } from 'tsrpc-browser';
import { HttpClient as HttpClient_Miniapp, WsClient as WsClient_Miniapp } from 'tsrpc-miniapp';
import { serviceProto as ServiceProtoRoom, ServiceType, ServiceType as ServiceTypeRoom } from "../shared/serviceProto";
import IDataModel from "../frameWork/model/IDataModel";
import UIHelp, { DialogParams } from "../logic/ui/UIHelp";
import GameController from "../GameController";
import { I18n } from "../utils/I18nUtil";
import { NetworkEvent } from "../data/const/EventConst";
import EventMng from "../manager/EventMng";
import GameDataCenter from "../data/GameDataCenter";
import { Code } from "../shared/base";


/** 游戏服 */
export class GameServerModel extends IDataModel {

    /** 连接房间服务器 Websocket 客户端 */
    wscRoom: WsClient_Miniapp<ServiceTypeRoom> | WsClient_Browser<ServiceTypeRoom> = null!;
    /** 重连次数 */
    reconnectCnt: number = 0;
    async Init(serverUrl: string) {
        this.wscRoom = eg.tspcNet.createWscRoom(serverUrl);
    }

    /** 连接游戏服 */
    async Connect() {
        let resConnect = await this.wscRoom.connect();
        if (!resConnect.isSucc) {
            console.error('连接游戏服失败', resConnect.errMsg);
            return;
        }
        CC_PREVIEW && console.log('连接游戏服成功');
        this.PostDisconnectFlow();
    }

    /** 重连游戏服 */
    async ReConnect() {
        this.reconnectCnt++;
        let resConnect = await this.wscRoom.connect();
        if (!resConnect.isSucc) {
            console.log('连接游戏服失败', resConnect.errMsg);
            if (this.reconnectCnt >= GameServerConfig.reconnectMax) {
                CC_PREVIEW && console.error("重连服务器超过上限");
                let dialogParam: DialogParams = {
                    content: I18n.getI18nText("http_overtime"),
                    cbConfirm: () => {
                        this.reconnectCnt = 0;
                        GameController.clear();
                        cc.game.restart();
                    },
                    txtConfirm: I18n.getI18nText("http_overtime_confirm_1"),
                    onlyConfirm: true
                }
                UIHelp.ShowSystemDialog(dialogParam)
                return;
            }
            setTimeout(() => {
                this.ReConnect();
            }, 2000);
            return;
        }
        EventMng.emit(NetworkEvent.WAIT, -1)
        CC_PREVIEW && console.log("重连服务器成功");
        GameDataCenter.login.sendEnterGame(GameDataCenter.login.playerInfo.sid)
    }

    /** 客户端与服务器断开事件 */
    private PostDisconnectFlow() {
        this.wscRoom.flows.postDisconnectFlow.push(v => {
            // 非客户端手动断开时处理（例：网络错误、服务器关闭）
            if (!v.isManual) {
                CC_PREVIEW && console.log("wss断线", v.reason);
                EventMng.emit(NetworkEvent.WAIT, 1);
                this.reconnectCnt = 0;
                // 等待 2 秒后自动重连
                this.ReConnect();
            }
            return v;
        });
    }

    /** 错误处理 */
    private ErrorHandler(err: TsrpcError) {
        if (err) {
            UIHelp.ShowTips(err.message);
            switch (err.code) {
                case Code.fail:
                    UIHelp.ShowTips(err.message);
                    break;
            }
            return null;
        }
    }

    /** 请求api */
    public async ReqApi<T extends string & keyof ServiceType['api']>(apiName: T, req: ServiceType['api'][T]['req']) {
        let ret = await this.wscRoom.callApi(apiName, req);
        if (!ret.isSucc) {
            this.ErrorHandler(ret.err)
            return null;
        }
        return ret;
    }



    /** ws发送消息 */
    public SendMsg<T extends string & keyof ServiceType['msg']>(msgName: T, msg: ServiceType['msg'][T]) {
        this.wscRoom.sendMsg(msgName, msg);
    }


    /** 监听消息 */
    public ListenMsg<T extends keyof ServiceType['msg']>(msgName: T | RegExp, callback: Function, target: any) {
        this.wscRoom.listenMsg(msgName, v => {
            callback.call(target, v);
        });
    }

}