using System;
using System.Collections.Generic;
using System.Text;
using QCRPG.Framework;

namespace QCRPG.TSL.BT.Packets;

public class LeCreateConnection : PacketBase
{
	public class UserFieldsWrapper
	{
		public enum OwnAddressTypeEnum
		{
			Public_Device_Address,
			Random_Device_Address,
			Resolvable_Private_Address_OR_Public_Address,
			Resolvable_Private_Address_OR_LE_Set_Random_Address,
			Reserved_for_future_use,
			InvalidOwnAddressTypeValue
		}

		public static class OwnAddressTypeInfo
		{
			public static OwnAddressTypeEnum ValueToOwnAddressType(uint value)
			{
				switch (value)
				{
				case 0u:
					return OwnAddressTypeEnum.Public_Device_Address;
				case 1u:
					return OwnAddressTypeEnum.Random_Device_Address;
				case 2u:
					return OwnAddressTypeEnum.Resolvable_Private_Address_OR_Public_Address;
				case 3u:
					return OwnAddressTypeEnum.Resolvable_Private_Address_OR_LE_Set_Random_Address;
				default:
					if (value >= 4 && value <= 255)
					{
						return OwnAddressTypeEnum.Reserved_for_future_use;
					}
					return OwnAddressTypeEnum.InvalidOwnAddressTypeValue;
				}
			}

			public static uint OwnAddressTypeToValue(OwnAddressTypeEnum enumItem)
			{
				return enumItem switch
				{
					OwnAddressTypeEnum.Public_Device_Address => 0u, 
					OwnAddressTypeEnum.Random_Device_Address => 1u, 
					OwnAddressTypeEnum.Resolvable_Private_Address_OR_Public_Address => 2u, 
					OwnAddressTypeEnum.Resolvable_Private_Address_OR_LE_Set_Random_Address => 3u, 
					OwnAddressTypeEnum.Reserved_for_future_use => 4u, 
					_ => uint.MaxValue, 
				};
			}

			public static string OwnAddressTypeToString(OwnAddressTypeEnum enumItem)
			{
				return enumItem switch
				{
					OwnAddressTypeEnum.Public_Device_Address => "Public Device Address", 
					OwnAddressTypeEnum.Random_Device_Address => "Random Device Address", 
					OwnAddressTypeEnum.Resolvable_Private_Address_OR_Public_Address => "Controller generates Resolvable Private Address based on the local IRK from the resolving list. If the resolving list contains no matching entry, use the public address.", 
					OwnAddressTypeEnum.Resolvable_Private_Address_OR_LE_Set_Random_Address => "Controller generates Resolvable Private Address based on the local IRK from the resolving list. If the resolving list contains no matching entry, use the random address from the most recent successful LE_Set_Random_Address Command.", 
					OwnAddressTypeEnum.Reserved_for_future_use => "Reserved for future use", 
					_ => "Invalid OwnAddressType Value", 
				};
			}

			public static string OwnAddressTypeToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = Public Device Address");
				stringBuilder.AppendLine("0x1 = Random Device Address");
				stringBuilder.AppendLine("0x2 = Controller generates Resolvable Private Address based on the local IRK from the resolving list. If the resolving list contains no matching entry, use the public address.");
				stringBuilder.AppendLine("0x3 = Controller generates Resolvable Private Address based on the local IRK from the resolving list. If the resolving list contains no matching entry, use the random address from the most recent successful LE_Set_Random_Address Command.");
				stringBuilder.AppendLine("0x4-0xFF = Reserved for future use");
				return stringBuilder.ToString();
			}
		}

		private uint _LeScanInterval = 4u;

		private uint _LeScanWindow = 4u;

		private uint _InitiatorFilterPolicy;

		private uint _PeerAddressType;

		private ulong _PeerAddress;

		private uint _OwnAddressType;

		private uint _ConnIntervalMin = 6u;

		private uint _ConnIntervalMax = 6u;

		private uint _ConnLatency;

		private uint _SupervisionTimeout = 10u;

		private uint _MinimumCeLength;

		private uint _MaximumCeLength;

		public uint LeScanInterval
		{
			get
			{
				return _LeScanInterval;
			}
			set
			{
				if (value > 65535)
				{
					throw new Exception("Maximum possible value for LeScanInterval is 0xFFFF");
				}
				_LeScanInterval = value;
			}
		}

		public uint LeScanWindow
		{
			get
			{
				return _LeScanWindow;
			}
			set
			{
				if (value > 65535)
				{
					throw new Exception("Maximum possible value for LeScanWindow is 0xFFFF");
				}
				_LeScanWindow = value;
			}
		}

		public uint InitiatorFilterPolicy
		{
			get
			{
				return _InitiatorFilterPolicy;
			}
			set
			{
				if (value > 255)
				{
					throw new Exception("Maximum possible value for InitiatorFilterPolicy is 0xFF");
				}
				_InitiatorFilterPolicy = value;
			}
		}

		public uint PeerAddressType
		{
			get
			{
				return _PeerAddressType;
			}
			set
			{
				if (value > 255)
				{
					throw new Exception("Maximum possible value for PeerAddressType is 0xFF");
				}
				_PeerAddressType = value;
			}
		}

		public ulong PeerAddress
		{
			get
			{
				return _PeerAddress;
			}
			set
			{
				_PeerAddress = value;
			}
		}

		public uint OwnAddressType
		{
			get
			{
				return _OwnAddressType;
			}
			set
			{
				if (value > 255)
				{
					throw new Exception("Maximum possible value for OwnAddressType is 0xFF");
				}
				_OwnAddressType = value;
			}
		}

		public uint ConnIntervalMin
		{
			get
			{
				return _ConnIntervalMin;
			}
			set
			{
				if (value > 65535)
				{
					throw new Exception("Maximum possible value for ConnIntervalMin is 0xFFFF");
				}
				_ConnIntervalMin = value;
			}
		}

		public uint ConnIntervalMax
		{
			get
			{
				return _ConnIntervalMax;
			}
			set
			{
				if (value > 65535)
				{
					throw new Exception("Maximum possible value for ConnIntervalMax is 0xFFFF");
				}
				_ConnIntervalMax = value;
			}
		}

		public uint ConnLatency
		{
			get
			{
				return _ConnLatency;
			}
			set
			{
				if (value > 65535)
				{
					throw new Exception("Maximum possible value for ConnLatency is 0xFFFF");
				}
				_ConnLatency = value;
			}
		}

		public uint SupervisionTimeout
		{
			get
			{
				return _SupervisionTimeout;
			}
			set
			{
				if (value > 65535)
				{
					throw new Exception("Maximum possible value for SupervisionTimeout is 0xFFFF");
				}
				_SupervisionTimeout = value;
			}
		}

		public uint MinimumCeLength
		{
			get
			{
				return _MinimumCeLength;
			}
			set
			{
				if (value > 65535)
				{
					throw new Exception("Maximum possible value for MinimumCeLength is 0xFFFF");
				}
				_MinimumCeLength = value;
			}
		}

		public uint MaximumCeLength
		{
			get
			{
				return _MaximumCeLength;
			}
			set
			{
				if (value > 65535)
				{
					throw new Exception("Maximum possible value for MaximumCeLength is 0xFFFF");
				}
				_MaximumCeLength = value;
			}
		}

		public InitiatingFilterPolicyEnum GetInitiatorFilterPolicyAsInitiatingFilterPolicyEnum()
		{
			return InitiatingFilterPolicyInfo.ValueToInitiatingFilterPolicy(_InitiatorFilterPolicy);
		}

		public void SetInitiatorFilterPolicyAsInitiatingFilterPolicyEnum(InitiatingFilterPolicyEnum enumItem)
		{
			InitiatorFilterPolicy = InitiatingFilterPolicyInfo.InitiatingFilterPolicyToValue(enumItem);
		}

		public PeerResolvableAddressTypeEnum GetPeerAddressTypeAsPeerResolvableAddressTypeEnum()
		{
			return PeerResolvableAddressTypeInfo.ValueToPeerResolvableAddressType(_PeerAddressType);
		}

		public void SetPeerAddressTypeAsPeerResolvableAddressTypeEnum(PeerResolvableAddressTypeEnum enumItem)
		{
			PeerAddressType = PeerResolvableAddressTypeInfo.PeerResolvableAddressTypeToValue(enumItem);
		}

		public OwnAddressTypeEnum GetOwnAddressTypeAsOwnAddressTypeEnum()
		{
			return OwnAddressTypeInfo.ValueToOwnAddressType(_OwnAddressType);
		}

		public void SetOwnAddressTypeAsOwnAddressTypeEnum(OwnAddressTypeEnum enumItem)
		{
			OwnAddressType = OwnAddressTypeInfo.OwnAddressTypeToValue(enumItem);
		}
	}

	private const uint _Opcode = 8205u;

	private Type[] expectedResponseTypes = new Type[2]
	{
		typeof(CommandStatusForLeCreateConnection),
		typeof(LeConnectionComplete)
	};

	private PacketInfoBase info;

	private uint _PayloadLength;

	public UserFieldsWrapper _UserFields = new UserFieldsWrapper();

	public override PacketType Type => PacketType.Command;

	public override Type[] ExpectedResponseTypes => expectedResponseTypes;

	public override PacketInfoBase Info
	{
		get
		{
			if (info == null)
			{
				info = new LeCreateConnectionInfo(this);
			}
			return info;
		}
	}

	public uint Opcode => 8205u;

	public uint PayloadLength
	{
		get
		{
			ToBitString();
			return _PayloadLength;
		}
	}

	public UserFieldsWrapper UserFields => _UserFields;

	public override void SetDefaultValues()
	{
		UserFields.LeScanInterval = 16u;
		UserFields.LeScanWindow = 16u;
		UserFields.ConnIntervalMin = 32u;
		UserFields.ConnIntervalMax = 32u;
		UserFields.ConnLatency = 0u;
		UserFields.SupervisionTimeout = 1000u;
		UserFields.MinimumCeLength = 0u;
		UserFields.MaximumCeLength = 0u;
	}

	protected override bool FromBitBuilder(ref BitBuilder bitBuilder)
	{
		if (bitBuilder.RemoveBitsAsUintLittleEndian(16) != Opcode)
		{
			return false;
		}
		_PayloadLength = bitBuilder.RemoveBitsAsUint(8);
		int numberOfBits = bitBuilder.GetNumberOfBits();
		if (numberOfBits > _PayloadLength * 8 + 7)
		{
			return false;
		}
		if (numberOfBits < _PayloadLength * 8)
		{
			return false;
		}
		UserFields.LeScanInterval = bitBuilder.RemoveBitsAsUintLittleEndian(16);
		UserFields.LeScanWindow = bitBuilder.RemoveBitsAsUintLittleEndian(16);
		UserFields.InitiatorFilterPolicy = bitBuilder.RemoveBitsAsUint(8);
		UserFields.PeerAddressType = bitBuilder.RemoveBitsAsUint(8);
		UserFields.PeerAddress = bitBuilder.RemoveBitsAsUlongLittleEndian(48);
		UserFields.OwnAddressType = bitBuilder.RemoveBitsAsUint(8);
		UserFields.ConnIntervalMin = bitBuilder.RemoveBitsAsUintLittleEndian(16);
		UserFields.ConnIntervalMax = bitBuilder.RemoveBitsAsUintLittleEndian(16);
		UserFields.ConnLatency = bitBuilder.RemoveBitsAsUintLittleEndian(16);
		UserFields.SupervisionTimeout = bitBuilder.RemoveBitsAsUintLittleEndian(16);
		UserFields.MinimumCeLength = bitBuilder.RemoveBitsAsUintLittleEndian(16);
		UserFields.MaximumCeLength = bitBuilder.RemoveBitsAsUintLittleEndian(16);
		if (bitBuilder.GetNumberOfBits() > 7)
		{
			return false;
		}
		return true;
	}

	public override string ToBitString()
	{
		BitBuilder bitBuilder = new BitBuilder();
		bitBuilder.AddBitsAsUintLittleEndian(Opcode, 16);
		int numberOfBits = bitBuilder.GetNumberOfBits();
		bitBuilder.AddBitsAsUint(0u, 8);
		bitBuilder.AddBitsAsUintLittleEndian(UserFields.LeScanInterval, 16);
		bitBuilder.AddBitsAsUintLittleEndian(UserFields.LeScanWindow, 16);
		bitBuilder.AddBitsAsUint(UserFields.InitiatorFilterPolicy, 8);
		bitBuilder.AddBitsAsUint(UserFields.PeerAddressType, 8);
		bitBuilder.AddBitsAsUlongLittleEndian(UserFields.PeerAddress, 48);
		bitBuilder.AddBitsAsUint(UserFields.OwnAddressType, 8);
		bitBuilder.AddBitsAsUintLittleEndian(UserFields.ConnIntervalMin, 16);
		bitBuilder.AddBitsAsUintLittleEndian(UserFields.ConnIntervalMax, 16);
		bitBuilder.AddBitsAsUintLittleEndian(UserFields.ConnLatency, 16);
		bitBuilder.AddBitsAsUintLittleEndian(UserFields.SupervisionTimeout, 16);
		bitBuilder.AddBitsAsUintLittleEndian(UserFields.MinimumCeLength, 16);
		bitBuilder.AddBitsAsUintLittleEndian(UserFields.MaximumCeLength, 16);
		_PayloadLength = (uint)((bitBuilder.GetNumberOfBits() - numberOfBits - 8) / 8);
		if ((bitBuilder.GetNumberOfBits() - numberOfBits - 8) % 8 != 0)
		{
			_PayloadLength++;
		}
		bitBuilder.ChangeBitsAsUint(numberOfBits, _PayloadLength, 8);
		return bitBuilder.ToString();
	}

	public override List<string> GetWarnings()
	{
		List<string> list = new List<string>();
		if (UserFields.LeScanInterval < 4)
		{
			list.Add("Minimum allowed value for LE_Scan_Interval is 0x4");
		}
		if (UserFields.LeScanInterval > 16384)
		{
			list.Add("Maximum allowed value for LE_Scan_Interval is 0x4000");
		}
		if (UserFields.LeScanWindow < 4)
		{
			list.Add("Minimum allowed value for LE_Scan_Window is 0x4");
		}
		if (UserFields.LeScanWindow > 16384)
		{
			list.Add("Maximum allowed value for LE_Scan_Window is 0x4000");
		}
		if (UserFields.ConnIntervalMin < 6)
		{
			list.Add("Minimum allowed value for Conn_Interval_Min is 0x6");
		}
		if (UserFields.ConnIntervalMin > 3200)
		{
			list.Add("Maximum allowed value for Conn_Interval_Min is 0xC80");
		}
		if (UserFields.ConnIntervalMax < 6)
		{
			list.Add("Minimum allowed value for Conn_Interval_Max is 0x6");
		}
		if (UserFields.ConnIntervalMax > 3200)
		{
			list.Add("Maximum allowed value for Conn_Interval_Max is 0xC80");
		}
		if (UserFields.ConnLatency < 0)
		{
			list.Add("Minimum allowed value for Conn_Latency is 0x0");
		}
		if (UserFields.ConnLatency > 499)
		{
			list.Add("Maximum allowed value for Conn_Latency is 0x1F3");
		}
		if (UserFields.SupervisionTimeout < 10)
		{
			list.Add("Minimum allowed value for Supervision_Timeout is 0xA");
		}
		if (UserFields.SupervisionTimeout > 3200)
		{
			list.Add("Maximum allowed value for Supervision_Timeout is 0xC80");
		}
		if (UserFields.MinimumCeLength < 0)
		{
			list.Add("Minimum allowed value for Minimum_CE_Length is 0x0");
		}
		if (UserFields.MinimumCeLength > 65535)
		{
			list.Add("Maximum allowed value for Minimum_CE_Length is 0xFFFF");
		}
		if (UserFields.MaximumCeLength < 0)
		{
			list.Add("Minimum allowed value for Maximum_CE_Length is 0x0");
		}
		if (UserFields.MaximumCeLength > 65535)
		{
			list.Add("Maximum allowed value for Maximum_CE_Length is 0xFFFF");
		}
		return list;
	}
}
