using System;
using System.Collections;
using System.Collections.Generic;
using BestHTTP.SocketIO;
using Cute;
using UnityEngine;
using Wizard;

public class Gungnir : IDisposable
{
	private enum ConnectingStatus
	{
		ONLINE,
		WAITING,
		OFFLINE,
		TIMEOUT
	}

	public enum DisconnectStatus
	{
		NOT,
		SELF_DISCONNECT,
		OPPONENT_DISCONNECT
	}

	public const string URI = "Gungnir";

	public const string EMIT_ALIVE = "alive";

	private const string CURRENT_SEQUENCE = "currentSeq";

	public const string ACTION_SEQ = "actionSeq";

	private const string OCS_KEY = "ocs";

	private const string SCS_KEY = "scs";

	private const string CLIENT_PUB_SEQ_KEY = "clientPubSeq";

	private const string CLIENT_REQ_RESEND_KEY = "reqResend";

	private const float REPORT_INTERVAL = 5f;

	private RealTimeNetworkAgent _agent;

	private ConnectionReporter _connectionReporter;

	public Action OnAlive;

	public Action OnOpponentAlive;

	public Action OnOpponentDisconnect;

	public Action OnOpponentOffLine;

	public Action OnOpponentTimeOut;

	public Action<int> OnResendEmitData;

	public bool _isNotEmit;

	private int _receiveReSendZeroNum;

	public List<int> _actionSeqPubSeqList = new List<int>();

	public int _actionSequenceNum;

	private float _gungnirLogWaitTimer;

	private Coroutine _gungnirAckCheckCoroutine;

	public const float SUCCESS_GUNGNIR_RECEIVE_LOG_TIME = 5f;

	public DisconnectStatus _DisconnectStatus { get; private set; }

	public long LastSuccessTime { get; private set; }

	public bool IsSendActionSequenceNum { get; private set; }

	public bool IsEnableTimeoutCallBack { get; set; } = true;

	public long GungnirReceiveCheckTime { get; private set; }

	public Gungnir(RealTimeNetworkAgent agent)
	{
		_agent = agent;
		_connectionReporter = new ConnectionReporter(agent, EmitGungnir, 5f);
		Tick();
		_DisconnectStatus = DisconnectStatus.NOT;
	}

	private IEnumerator GungnirLogAckCheck()
	{
		while (true)
		{
			_gungnirLogWaitTimer += Time.deltaTime;
			if (_gungnirLogWaitTimer >= 2f)
			{
				break;
			}
			yield return null;
		}
		if (!LocalLog._isSendGungnirLog)
		{
			_agent.NetworkLogger.LogInfo("OnGungnirLog");
		}
		LocalLog._isSendGungnirLog = true;
	}

	public void Start()
	{
		_agent.NetworkLogger.LogInfo("Gungnir: Start");
		_connectionReporter.StartReporter();
		LocalLog.InitGungnirLog();
		LocalLog.InitDisconnectLog();
	}

	public void Stop()
	{
		_connectionReporter.StopReporter();
		_agent.NetworkLogger.LogInfo("Gungnir: Stop");
		LocalLog.AddGungnirLog("GungnirStopReporter ");
	}

	public void SetSendActionSequenceNumFlag(bool isActive)
	{
		if (!isActive && IsSendActionSequenceNum)
		{
			_agent.NetworkLogger.LogInfo("GungnirSendActionSeq:OFF");
		}
		if (isActive && !IsSendActionSequenceNum)
		{
			_agent.NetworkLogger.LogInfo("GungnirSendActionSeq:ON");
		}
		IsSendActionSequenceNum = isActive;
	}

	public void EmitGungnir()
	{
		if (GameMgr.GetIns().IsWatchBattle || _isNotEmit)
		{
			return;
		}
		if (_agent.IsOpen())
		{
			_agent.SocketManager.Socket.Emit("alive", OnAckPacket, CreateEmitData());
			if (IsRecordGungnirLog())
			{
				_gungnirAckCheckCoroutine = _agent.StartCoroutine(GungnirLogAckCheck());
			}
			LocalLog.AddGungnirLog("EmitGungnir");
			return;
		}
		LocalLog.AddGungnirLog("NotOpenEmitGungnir");
		if (!LocalLog._isSendGungnirLog)
		{
			_agent.NetworkLogger.LogInfo("OnGungnirLog");
		}
		if (IsRecordGungnirLog())
		{
			LocalLog._isSendGungnirLog = true;
		}
	}

	private bool IsRecordGungnirLog()
	{
		if (_agent == null || _agent.CurrentMatchingStatus != RealTimeNetworkAgent.MatchingStatus.Prepared || GameMgr.GetIns() == null || GameMgr.GetIns().IsWatchBattle)
		{
			return false;
		}
		return true;
	}

	private byte[] CreateEmitData()
	{
		Dictionary<string, object> dictionary = _agent.CreateEmitData("Gungnir", null, isTrySend: false);
		dictionary.Add("currentSeq", _agent.MaxMessageSequenceNumber);
		if (IsSendActionSequenceNum)
		{
			dictionary.Add("actionSeq", _actionSequenceNum);
		}
		return _agent.CreatePackEmitData(dictionary);
	}

	private void OnAckPacket(Socket socket, Packet originalPacket, params object[] args)
	{
		Tick();
		OnAlive.Call();
		LocalLog.AddGungnirLog("GungnirOnAck");
		if (_gungnirAckCheckCoroutine != null)
		{
			_agent.StopCoroutine(_gungnirAckCheckCoroutine);
		}
		_gungnirLogWaitTimer = 0f;
	}

	public void ReceiveGungnir(Packet originalPacket, params object[] args)
	{
		Dictionary<string, object> dictionary = _agent.DeserializeEncryptedPacket(originalPacket);
		if (dictionary.Count == 0)
		{
			LocalLog.AddGungnirLog("ReceiveGungnirDataZero");
			return;
		}
		string text = dictionary["uri"].ToString();
		if (text != NetworkBattleDefine.NetworkURINames[NetworkBattleDefine.NetworkBattleURI.Gungnir])
		{
			LocalLog.AddGungnirLog("ReceiveGungnirNoUri[" + text + "]");
		}
		else
		{
			if (_agent.HandleingNodeResultCodeIfNeeded(dictionary))
			{
				return;
			}
			if (_agent.IsExistTitleReturnError)
			{
				LocalLog.AddGungnirLog("ReceiveGungnirIsExistTitleReturnError");
				return;
			}
			GungnirReceiveCheckTime = TimeUtil.GetAbsoluteTime().Ticks;
			Tick();
			OnAlive.Call();
			if (dictionary.ContainsKey(NetworkBattleDefine.NetworkParameter.resultCode.ToString()) && int.Parse(dictionary[NetworkBattleDefine.NetworkParameter.resultCode.ToString()].ToString()) == 30002)
			{
				return;
			}
			if (dictionary.ContainsKey("reqResend"))
			{
				int num = int.Parse(dictionary["reqResend"].ToString());
				if (num == 0)
				{
					_receiveReSendZeroNum++;
				}
				if (num == 1 || _receiveReSendZeroNum >= 2)
				{
					_receiveReSendZeroNum = 0;
					if (dictionary.ContainsKey("clientPubSeq"))
					{
						int arg = int.Parse(dictionary["clientPubSeq"].ToString());
						OnResendEmitData.Call(arg);
					}
				}
			}
			if ((ConnectingStatus)Enum.Parse(typeof(ConnectingStatus), dictionary["scs"].ToString()) == ConnectingStatus.OFFLINE)
			{
				_agent.NetworkLogger.LogInfo("Gungnir: Self Offline");
				if (_agent.IsBattleStart)
				{
					_DisconnectStatus = DisconnectStatus.SELF_DISCONNECT;
				}
				return;
			}
			switch ((ConnectingStatus)Enum.Parse(typeof(ConnectingStatus), dictionary["ocs"].ToString()))
			{
			case ConnectingStatus.ONLINE:
				OnOpponentAlive.Call();
				break;
			case ConnectingStatus.WAITING:
				_agent.NetworkLogger.LogInfo("Gungnir: Opponent Disconnect");
				OnOpponentDisconnect.Call();
				break;
			case ConnectingStatus.OFFLINE:
				OpponentOffLine();
				_agent.NetworkLogger.LogInfo("Gungnir: Opponent Offline");
				OnOpponentOffLine.Call();
				break;
			case ConnectingStatus.TIMEOUT:
				OpponentOffLine();
				_agent.NetworkLogger.LogInfo("Gungnir: Opponent TimeOut");
				if (IsEnableTimeoutCallBack)
				{
					OnOpponentTimeOut.Call();
				}
				break;
			}
		}
	}

	private void OpponentOffLine()
	{
		if (_agent.IsBattleStart)
		{
			_DisconnectStatus = DisconnectStatus.OPPONENT_DISCONNECT;
		}
	}

	public void Tick()
	{
		LastSuccessTime = TimeUtil.GetAbsoluteTime().Ticks;
	}

	public void Dispose()
	{
		if (_gungnirAckCheckCoroutine != null)
		{
			_agent.StopCoroutine(_gungnirAckCheckCoroutine);
		}
		_connectionReporter.StopReporter();
		_connectionReporter = null;
		_agent = null;
	}
}
