#pragma once

#include "NetChannel.h"
#include "ehs/io/socket/Socket.h"
#include "ehs/io/socket/ehc/NetEnc.h"
#include "ehs/io/socket/ehc/NetFrag.h"

namespace ehs
{
	class NetClientCh : public NetChannel
	{
	private:
		friend class EHC;

		Endpoint remoteEndpoint;
		Char_8 token[64];
		NetStatus status;
		UInt_64 queueSlot;
		float deltaDuration;
		float deltaRate;
		float lastPing;
		float latency;
		float timeout;
		UInt_64 nextSendId;
		Vector<Insurance> sent;
		UInt_64 nextRecvId;
		Vector<NetFrag> received;

	public:
		~NetClientCh();

		NetClientCh();

		NetClientCh(Str_8 name, const Version &version, Endpoint remoteEndpoint);

		NetClientCh(NetClientCh &&client) noexcept;

		NetClientCh(const NetClientCh &client);

		NetClientCh &operator=(NetClientCh &&client) noexcept;

		NetClientCh &operator=(const NetClientCh &client);

		virtual void OnConnected(Serializer<UInt_64> data);

		virtual void OnActive(Serializer<UInt_64> data);

		virtual void OnQueueUpdate(Serializer<UInt_64> data);

		virtual void OnDisconnected(Serializer<UInt_64> data);

		virtual void OnRejected(Serializer<UInt_64> data);

		virtual void OnTimeout(Serializer<UInt_64> data);

		void Connect(const Endpoint &endpoint, const Serializer<UInt_64>& payload);

		bool Disconnect(const Serializer<UInt_64>& payload);

		void Send(bool deltaLocked, UInt_64 encId, bool ensure, UInt_64 sysId, UInt_64 opId, const Serializer<UInt_64>& payload);

		void Send(bool deltaLocked, const Str_8 &encName, bool ensure, const Str_8& sysName, const Str_8& opName, const Serializer<UInt_64>& payload);

		NetStatus GetStatus() const;

	private:
		void Process(const float &delta, const Endpoint &endpoint, const Header &header, Serializer<UInt_64> &payload) override;

		void Poll(const float &delta) override;

		NetFrag FragmentData(IP version, const Header& header, const Serializer<>& data);

		void Send(NetEnc *enc, const Header& header, const Serializer<>& payload);

		void Pong(float delta);

		void RemoveInsurance(UInt_64 msgId, UInt_64 fragment);

		void AddReceived(const Header& header, const Serializer<>& payload);
	};
}