using System;
using System.Threading;
using QCRPG.Framework;

namespace QCRPG.TSL.NFC;

public class ProtocolNCIReader : ProtocolBase
{
	private enum ReceiveState
	{
		GETTING_PAYLOAD_LENGTH,
		GETTING_FULL_PACKET
	}

	private int readResponseTimeoutMs = 3000;

	private ManualResetEvent receivedReadResponsePacketEvent = new ManualResetEvent(initialState: false);

	private IncomingPacketData lastReadResponseReceived = new IncomingPacketData(new byte[0]);

	private int expectedReadResponseLength;

	private bool waitingForResponse;

	private object waitingForResponseLockObject = new object();

	private ReceiveState receiveState = ReceiveState.GETTING_FULL_PACKET;

	public int ReadResponseTimeoutMs
	{
		get
		{
			return readResponseTimeoutMs;
		}
		set
		{
			readResponseTimeoutMs = value;
		}
	}

	public override void Send(OutgoingPacketData packetData)
	{
		sendDataNotifier.NotifyObservers(packetData);
	}

	public IncomingPacketData SendReadAndGetResponse()
	{
		receivedReadResponsePacketEvent.Reset();
		OutgoingPacketData packetData = new OutgoingPacketData(PacketDataType.Notification, new byte[2] { 2, 3 });
		lock (waitingForResponseLockObject)
		{
			receiveState = ReceiveState.GETTING_PAYLOAD_LENGTH;
			if (!waitingForResponse)
			{
				Send(packetData);
			}
			waitingForResponse = true;
		}
		if (receivedReadResponsePacketEvent.WaitOne(readResponseTimeoutMs))
		{
			lock (lastReadResponseReceived)
			{
				receivedReadResponsePacketEvent.Reset();
				return lastReadResponseReceived.DeepCopy();
			}
		}
		lock (waitingForResponseLockObject)
		{
			waitingForResponse = false;
			receiveState = ReceiveState.GETTING_FULL_PACKET;
		}
		throw new TimeoutException("Timeout waiting for read response");
	}

	public override void NotifyObserver(IncomingPacketData packetData)
	{
		if (packetData.type == PacketDataType.Data)
		{
			if (receiveState == ReceiveState.GETTING_PAYLOAD_LENGTH)
			{
				if (packetData.bytes.Length == 3)
				{
					expectedReadResponseLength = packetData.bytes[2] + 3;
					if (expectedReadResponseLength <= 255)
					{
						OutgoingPacketData packetData2 = new OutgoingPacketData(PacketDataType.Notification, new byte[2]
						{
							2,
							(byte)expectedReadResponseLength
						});
						Send(packetData2);
					}
					else
					{
						expectedReadResponseLength = 0;
						lock (waitingForResponseLockObject)
						{
							waitingForResponse = false;
						}
						IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, "Received payload size overflow in ProtocolNCI.NotifyObserver(IncomingPacketData)");
						receiveDataNotifier.NotifyObservers(arg);
					}
				}
				else
				{
					expectedReadResponseLength = 0;
					lock (waitingForResponseLockObject)
					{
						waitingForResponse = false;
					}
					IncomingPacketData arg2 = new IncomingPacketData(PacketDataType.WarningMessage, "Packet length mismatch in ProtocolNCI.NotifyObserver(IncomingPacketData) for payload length response");
					receiveDataNotifier.NotifyObservers(arg2);
				}
				receiveState = ReceiveState.GETTING_FULL_PACKET;
				return;
			}
			if (receiveState != ReceiveState.GETTING_FULL_PACKET)
			{
				throw new Exception("Unsupported receive state: " + receiveState);
			}
			lock (waitingForResponseLockObject)
			{
				if (!waitingForResponse)
				{
					return;
				}
			}
			if (expectedReadResponseLength == packetData.bytes.Length)
			{
				lock (waitingForResponseLockObject)
				{
					waitingForResponse = false;
				}
				lock (lastReadResponseReceived)
				{
					lastReadResponseReceived = packetData.DeepCopy();
					receivedReadResponsePacketEvent.Set();
				}
				receiveDataNotifier.NotifyObservers(lastReadResponseReceived);
			}
			else
			{
				lock (waitingForResponseLockObject)
				{
					waitingForResponse = false;
				}
				IncomingPacketData arg3 = new IncomingPacketData(PacketDataType.WarningMessage, "Packet length mismatch in ProtocolNCI.NotifyObserver(IncomingPacketData) for full response");
				receiveDataNotifier.NotifyObservers(arg3);
			}
		}
		else if (packetData.type == PacketDataType.Notification)
		{
			if (packetData.bytes[0] == 1)
			{
				if (receiveState == ReceiveState.GETTING_PAYLOAD_LENGTH)
				{
					OutgoingPacketData packetData3 = new OutgoingPacketData(PacketDataType.Notification, new byte[2] { 2, 3 });
					lock (waitingForResponseLockObject)
					{
						Send(packetData3);
						waitingForResponse = true;
						return;
					}
				}
				if (receiveState == ReceiveState.GETTING_FULL_PACKET)
				{
					OutgoingPacketData packetData4 = new OutgoingPacketData(PacketDataType.Notification, new byte[2] { 2, 3 });
					lock (waitingForResponseLockObject)
					{
						receiveState = ReceiveState.GETTING_PAYLOAD_LENGTH;
						if (!waitingForResponse)
						{
							Send(packetData4);
						}
						waitingForResponse = true;
						return;
					}
				}
				throw new Exception("Unsupported receive state: " + receiveState);
			}
			receiveDataNotifier.NotifyObservers(packetData);
		}
		else
		{
			receiveDataNotifier.NotifyObservers(packetData);
		}
	}
}
