using System;
using System.Linq;
using QC.QMSLPhone;

namespace QCRPG.Framework;

public class ConnectionDiag : ConnectionBase
{
	public const int ReceiveTimeoutMs = 10;

	private Phone phone = new Phone();

	public static string[] GetPortNames(LibraryModeEnum libraryMode, int maxNumPorts)
	{
		ushort NumPorts = (ushort)maxNumPorts;
		try
		{
			Phone.PhoneInstance.SetLibraryMode(libraryMode);
			Phone.PhoneInstance.GetAvailablePhonesPortList(ref NumPorts, out var PortList, 0, null);
			return (from portNumber in PortList.Take(NumPorts)
				select $"COM{portNumber}").ToArray();
		}
		catch (Exception)
		{
			return null;
		}
	}

	public void Open(string portName, LibraryModeEnum libraryMode, Phone.TargetType targetType, Phone.DiagType diagType)
	{
		if (!IsOpen())
		{
			phone.SetLibraryMode(libraryMode);
			phone.ConnectToServer(Convert.ToInt32(portName.Replace("COM", "")), targetType, diagType);
			ConnectionStateChangeInfo connectionStateChangeInfo = new ConnectionStateChangeInfo();
			connectionStateChangeInfo.openStateChanged = true;
			connectionStateChangeInfo.openState = true;
			connectionStateChangeInfo.portNameChanged = true;
			connectionStateChangeInfo.portName = portName;
			connectionStateChangeInfoNotifier.NotifyObservers(connectionStateChangeInfo);
		}
	}

	public override void Close()
	{
		if (IsOpen())
		{
			phone.DisconnectServer();
			ConnectionStateChangeInfo connectionStateChangeInfo = new ConnectionStateChangeInfo();
			connectionStateChangeInfo.openStateChanged = true;
			connectionStateChangeInfo.openState = false;
			connectionStateChangeInfoNotifier.NotifyObservers(connectionStateChangeInfo);
		}
	}

	public override bool IsOpen()
	{
		return phone.IsPhoneConnected();
	}

	public override void Send(OutgoingPacketData packetData)
	{
		if (packetData.type == PacketDataType.Notification && packetData.bytes.Length == 2)
		{
			Receive(BitConverter.ToUInt16(packetData.bytes, 0));
		}
		if (packetData.type != 0)
		{
			return;
		}
		if (!IsOpen())
		{
			throw new Exception("The connection is closed");
		}
		short resSize = 2048;
		byte[] array = new byte[2048];
		phone.SendSync((short)packetData.bytes.Length, packetData.bytes, ref resSize, array);
		array = array.Take(resSize).ToArray();
		receiveDataNotifier.NotifyObservers(new IncomingPacketData(array));
		if (!array.SequenceEqual(packetData.bytes))
		{
			IncomingPacketData arg = new IncomingPacketData(PacketDataType.WarningMessage, "Unexpected diag response: " + string.Join(" ", array.Select((byte b) => b.ToString("X2"))));
			receiveDataNotifier.NotifyObservers(arg);
		}
	}

	public void Receive(ushort logCode)
	{
		if (phone.getLogMessageCount() != 0)
		{
			QC.QMSLPhone.LogMessage msg;
			while (phone.getLogMessage(out msg, logCode, int.MinValue))
			{
				receiveDataNotifier.NotifyObservers(new IncomingPacketData(msg.message));
			}
		}
	}

	public void ConfigureAsyncReceive(ushort[] logCodes)
	{
		foreach (ushort logCode in logCodes)
		{
			phone.configLogging(logCode, OnOff: true);
		}
	}
}
