
import { StringMap } from "../Collections/StringMap";
import Gamecfg from "../common/gameCfg";
import { gameMethod } from "../common/gameMethod";
import { HdClubPkFightAll, PlayerLogin, PlayerLoginPlayer, PlayerLoginUser, PlayerReconnect, TaichuWajieMap, UserAdok, ZhangjieDaguai } from "../common/Xyc";
import { SevBack, SevBackType } from "../common/Xys";
import Config from "../Config";
import { GameEvent, NetworkEvent, UserEvent, WindowEvent } from "../data/const/EventConst";
import { InGame, ReportRoleType } from "../data/const/TypeConst";
import GameDataCenter from "../data/GameDataCenter";
import EventMng from "../manager/EventMng";
import HttpRequest, { POST_DATA } from "./HttpRequest";
import SevDataMng from "./SevDataMng";

export default class Network {
    private leftSevbacks: { cb: Function, sevback: SevBack }[] = []

    stopRequest: boolean = false //后端提示重启后停止发送协议
    stopPopEp: boolean = false //处理装备的属性变化不飘字
    isEpChange: boolean = false
    private isOutClub: boolean = false // 是否退出公会
    private isShowTimeben: [number, string] = [0, ""] // 是否打开或刷新福利礼包
    cmdCounts: number = 0 //网络请求计数
    m_Timers: StringMap<NodeJS.Timer> = new StringMap<NodeJS.Timer>();
    reSentTime: number;

    private getLoginUrl(url: string): string {
        let realUrl = Gamecfg.packageInfo.getItem(Config.pid).wayhttp + url +
            "?version=" + Config.appVersion +
            "&time=" + GameDataCenter.time.sevTime
        return realUrl
    }

    private getCmdUrl(url: string, cmdId: number): string {
        let realUrl = Gamecfg.packageInfo.getItem(Config.pid).wayhttp + url +
            "?uuid=" + GameDataCenter.user.uuid +
            "&token=" + GameDataCenter.user.token +
            "&version=" + Config.appVersion +
            "&cmdId=" + cmdId +
            "&time=" + GameDataCenter.time.sevTime
        return realUrl
    }

    constructor() {
    }
    // 不需要处理回调数据的,走这里
    static POST_SPECIAL(path: string, body: string, cb: Function = () => { }) {
        let r = new XMLHttpRequest()
        r.open("POST", path, true)
        r.timeout = 15000
        r.setRequestHeader("Content-Type", "application/json")
        r.onreadystatechange = () => {
            if (r.status >= 200 && r.status <= 400 && r.readyState == 4) {
                cb()
            }
        };
        r.send(body)
    }
    sendLogin(url: string, body: Object, callback: Function = () => { }) {
        HttpRequest.POST(this.getLoginUrl(url), { uuid: GameDataCenter.user.uuid, version: Config.appVersion, url: url }, body, (result: SevBack) => {
            this.updateSevBack(result, callback)
        }, true)
    }
    send(url: string, body: Object, cb1?: (sev: SevBack) => void, cb2?: (sev: SevBack) => void, deal: number = 1, needWait: boolean = false, cmdId: number = -1) {
        if (this.stopRequest) {
            return
        }
        //每发送一个消息，消息计数累计，方便服务端做判断
        this.cmdCounts++
        //先缓存发送的消息，超时重新请求
        let postDataTemp: POST_DATA = {
            url: url,
            body: body,
            cb1: cb1,
            cb2: cb2,
            deal: deal,
            cmdId: cmdId == -1 ? this.cmdCounts : cmdId
        }
        let unErrArr = [PlayerReconnect.url, UserAdok.url, UserAdok.url];
        if (unErrArr.indexOf(url) < 0) {
            //重连接口，心跳包, 挂机打怪无需重新发送
            HttpRequest.errPostMap.Add(url, postDataTemp)
            let unArr = [PlayerLogin.url, PlayerLoginPlayer.url, PlayerLoginUser.url, HdClubPkFightAll.url, TaichuWajieMap.url, ZhangjieDaguai.url];
            if (unArr.indexOf(url) < 0) {
                let postTime = new Date().getTime()
                postDataTemp.postTime = postTime
                HttpRequest.curPostMap.Add(url, postDataTemp)
            }
        }
        this.AddTimer(url, () => {
            let curTime = new Date().getTime()
            if (!this.reSentTime) {
                this.reSentTime = cc.sys.platform == cc.sys.TAOBAO_MINIGAME ? 3000 : 1500;
            }
            if (HttpRequest.curPostMap.ContainsKey(url) && curTime - HttpRequest.curPostMap.Value(url).postTime >= this.reSentTime) {
                console.log(`1.5s后重新发送:${url}`)
                //遮罩计数-1
                EventMng.emit(NetworkEvent.WAIT, -1)
                this.m_Timers.Remove(url)
                let value = HttpRequest.curPostMap.Value(url)
                this.send(value.url, value.body, value.cb1, value.cb2, value.deal, false, value.cmdId)
            }
        }, 500)
        if (needWait) EventMng.emit(NetworkEvent.NETWAIT_MASK, true)
        let curCmdId = cmdId == -1 ? this.cmdCounts : cmdId
        HttpRequest.POST(this.getCmdUrl(url, curCmdId), { uuid: GameDataCenter.user.uuid, version: Config.appVersion, url: url }, body, (result: SevBack) => {
            if (needWait) EventMng.emit(NetworkEvent.NETWAIT_MASK, false)
            if (result.type == SevBackType.wu) {
                //无需处理的消息
                return
            }
            if (cb2) {
                cb2(result)
            }
            if (result.type == SevBackType.fail) {
                // 如果出现异常,则直接处理
                this.updateSevBack(result, cb1)
                return
            }
            if (deal == 1) {
                if (this.leftSevbacks.length > 0) {
                    this.leftSevbacks.push({ cb: cb1, sevback: result })
                } else {
                    this.updateSevBack(result, cb1)
                }
            } else if (deal == 2) { // 暂存弹窗信息
                if (this.leftSevbacks.length > 0) {
                    this.leftSevbacks.push({ cb: cb1, sevback: result })
                } else {
                    let tempSevback: SevBack = { type: result.type }
                    this.leftSevbacks.push({ cb: () => { }, sevback: tempSevback })
                    this.updateSevBack(result, cb1)
                }
            } else {
                this.leftSevbacks.push({ cb: cb1, sevback: result })
            }
        }, false)
    }
    // 处理暂存的后端数据
    dealLeftSevback() {
        this.leftSevbacks.forEach(element => {
            this.updateSevBack(element.sevback, element.cb)
        });
        this.leftSevbacks = []
    }
    updateSevBack(result: SevBack, cb1: Function) {
        // 刷新后端数据列表
        let oldPower: number = GameDataCenter.sevBack?.userInfo?.a?.power ?? 0;
        let sevback = SevDataMng.sevBackUpdate(GameDataCenter.sevBack, result)
        // 这里去检测通用类数据的前后对比
        this.isOutClub = false
        this.isShowTimeben = [0, ""]
        GameDataCenter.sevBack = sevback;
        // if ((!gameMethod.isEmpty(result?.userInfo?.a?.power) || (!gameMethod.isEmpty(result?.userInfo?.u?.power)))) {
        //     // 更新战斗力
        //     if (GameDataCenter.zhanLi) GameDataCenter.zhanLi.updateTotalZhanLi(oldPower, sevback?.userInfo?.a?.power);
        // }
        // 业务逻辑自定义参数处理
        for (let key in result) {
            let rspModels = GameDataCenter._rspModel.get(key)
            for (let i = 0; i < rspModels?.length; i++) {
                //需要分发事件的模块分发
                rspModels[i]?.doSevback(result)
            }
        }
        // 触发事件,刷新UI
        this.updateEvent(result, cb1)
        // 需要在数据处理后触发
        if (this.isOutClub) {

        }
    }

    updateEvent(result: SevBack, cb1: Function) {
        let alreadyRspModel = []  //已分发的模块，同个消息同个模块只分发一次
        for (let key in result) {
            let rspModels = GameDataCenter._rspModel.get(key)
            for (let i = 0; i < rspModels?.length; i++) {
                if (alreadyRspModel.indexOf(rspModels[i]) >= 0) {
                    continue
                }
                //需要分发事件的模块分发
                rspModels[i]?.doEvent(result)
                alreadyRspModel.push(rspModels[i])
            }
        }
        // 执行各自协议发送者回调
        if (cb1) {
            cb1(result)
        }
    }

    /**
     * 增加定时器
     * @param callback 
     * @param delta 单位毫秒ms
     */
    AddTimer(key: string, callback: Function, delta: number) {
        if (this.m_Timers.ContainsKey(key)) {
            return
        }
        let timer = setInterval(() => {
            callback.apply(this);
        }, delta);
        this.m_Timers.Add(key, timer);
        return timer;
    }

    /** 移除所有定时器 */
    RemoveTimers() {
        this.m_Timers.Foreach((key: string, value: NodeJS.Timer) => {
            clearInterval(value);
        });
        this.m_Timers.Clear()
    }
}