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

namespace QCRPG.TSL.BT.Packets;

public class LeDirectedAdvertisingReport : PacketBase
{
	public class UserFieldsWrapper
	{
		private const uint _SubeventCode = 11u;

		private uint _NumReports;

		private List<ReportsSubField> _ReportsList = new List<ReportsSubField>();

		public uint SubeventCode => 11u;

		public uint NumReports
		{
			get
			{
				return _NumReports;
			}
			set
			{
				if (value > 255)
				{
					throw new Exception("Maximum possible value for NumReports is 0xFF");
				}
				_NumReports = value;
				while (_ReportsList.Count < _NumReports)
				{
					_ReportsList.Add(new ReportsSubField());
				}
				while (_ReportsList.Count > _NumReports)
				{
					_ReportsList.RemoveAt(_ReportsList.Count - 1);
				}
			}
		}

		public List<ReportsSubField> ReportsList => _ReportsList;

		public NumberOfReportsEnum GetNumReportsAsNumberOfReportsEnum()
		{
			return NumberOfReportsInfo.ValueToNumberOfReports(_NumReports);
		}

		public void SetNumReportsAsNumberOfReportsEnum(NumberOfReportsEnum enumItem)
		{
			NumReports = NumberOfReportsInfo.NumberOfReportsToValue(enumItem);
		}
	}

	public class ReportsSubField
	{
		public enum EventTypeEnum
		{
			Reserved_for_future_use,
			Connectable_directed_advertising_ADV_DIRECT_IND,
			InvalidEventTypeValue
		}

		public static class EventTypeInfo
		{
			public static EventTypeEnum ValueToEventType(uint value)
			{
				switch (value)
				{
				case 0u:
					return EventTypeEnum.Reserved_for_future_use;
				case 1u:
					return EventTypeEnum.Connectable_directed_advertising_ADV_DIRECT_IND;
				default:
					if (value >= 2 && value <= 255)
					{
						return EventTypeEnum.Reserved_for_future_use;
					}
					return EventTypeEnum.InvalidEventTypeValue;
				}
			}

			public static uint EventTypeToValue(EventTypeEnum enumItem)
			{
				switch (enumItem)
				{
				case EventTypeEnum.Reserved_for_future_use:
					return 0u;
				case EventTypeEnum.Connectable_directed_advertising_ADV_DIRECT_IND:
					return 1u;
				default:
					if (enumItem == EventTypeEnum.Reserved_for_future_use)
					{
						return 2u;
					}
					return uint.MaxValue;
				}
			}

			public static string EventTypeToString(EventTypeEnum enumItem)
			{
				switch (enumItem)
				{
				case EventTypeEnum.Reserved_for_future_use:
					return "Reserved for future use";
				case EventTypeEnum.Connectable_directed_advertising_ADV_DIRECT_IND:
					return "Connectable directed advertising (ADV_DIRECT_IND)";
				default:
					if (enumItem == EventTypeEnum.Reserved_for_future_use)
					{
						return "Reserved for future use";
					}
					return "Invalid EventType Value";
				}
			}

			public static string EventTypeToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = Reserved for future use");
				stringBuilder.AppendLine("0x1 = Connectable directed advertising (ADV_DIRECT_IND)");
				stringBuilder.AppendLine("0x2-0xFF = Reserved for future use");
				return stringBuilder.ToString();
			}
		}

		public enum DirectAddressTypeEnum
		{
			Reserved_for_future_use,
			Random_Device_Address,
			InvalidDirectAddressTypeValue
		}

		public static class DirectAddressTypeInfo
		{
			public static DirectAddressTypeEnum ValueToDirectAddressType(uint value)
			{
				switch (value)
				{
				case 0u:
					return DirectAddressTypeEnum.Reserved_for_future_use;
				case 1u:
					return DirectAddressTypeEnum.Random_Device_Address;
				default:
					if (value >= 2 && value <= 255)
					{
						return DirectAddressTypeEnum.Reserved_for_future_use;
					}
					return DirectAddressTypeEnum.InvalidDirectAddressTypeValue;
				}
			}

			public static uint DirectAddressTypeToValue(DirectAddressTypeEnum enumItem)
			{
				switch (enumItem)
				{
				case DirectAddressTypeEnum.Reserved_for_future_use:
					return 0u;
				case DirectAddressTypeEnum.Random_Device_Address:
					return 1u;
				default:
					if (enumItem == DirectAddressTypeEnum.Reserved_for_future_use)
					{
						return 2u;
					}
					return uint.MaxValue;
				}
			}

			public static string DirectAddressTypeToString(DirectAddressTypeEnum enumItem)
			{
				switch (enumItem)
				{
				case DirectAddressTypeEnum.Reserved_for_future_use:
					return "Reserved for future use";
				case DirectAddressTypeEnum.Random_Device_Address:
					return "Random Device Address (default)";
				default:
					if (enumItem == DirectAddressTypeEnum.Reserved_for_future_use)
					{
						return "Reserved for future use";
					}
					return "Invalid DirectAddressType Value";
				}
			}

			public static string DirectAddressTypeToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = Reserved for future use");
				stringBuilder.AppendLine("0x1 = Random Device Address (default)");
				stringBuilder.AppendLine("0x2-0xFF = Reserved for future use");
				return stringBuilder.ToString();
			}
		}

		private uint _EventType;

		private uint _AddressType;

		private ulong _Address;

		private uint _DirectAddressType;

		private ulong _DirectAddress;

		private uint _Rssi;

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

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

		public ulong Address
		{
			get
			{
				return _Address;
			}
			set
			{
				_Address = value;
			}
		}

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

		public ulong DirectAddress
		{
			get
			{
				return _DirectAddress;
			}
			set
			{
				_DirectAddress = value;
			}
		}

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

		public EventTypeEnum GetEventTypeAsEventTypeEnum()
		{
			return EventTypeInfo.ValueToEventType(_EventType);
		}

		public void SetEventTypeAsEventTypeEnum(EventTypeEnum enumItem)
		{
			EventType = EventTypeInfo.EventTypeToValue(enumItem);
		}

		public AdvertisingReportAddressTypeEnum GetAddressTypeAsAdvertisingReportAddressTypeEnum()
		{
			return AdvertisingReportAddressTypeInfo.ValueToAdvertisingReportAddressType(_AddressType);
		}

		public void SetAddressTypeAsAdvertisingReportAddressTypeEnum(AdvertisingReportAddressTypeEnum enumItem)
		{
			AddressType = AdvertisingReportAddressTypeInfo.AdvertisingReportAddressTypeToValue(enumItem);
		}

		public DirectAddressTypeEnum GetDirectAddressTypeAsDirectAddressTypeEnum()
		{
			return DirectAddressTypeInfo.ValueToDirectAddressType(_DirectAddressType);
		}

		public void SetDirectAddressTypeAsDirectAddressTypeEnum(DirectAddressTypeEnum enumItem)
		{
			DirectAddressType = DirectAddressTypeInfo.DirectAddressTypeToValue(enumItem);
		}

		public AdvertisingRssiEnum GetRssiAsAdvertisingRssiEnum()
		{
			return AdvertisingRssiInfo.ValueToAdvertisingRssi(_Rssi);
		}

		public void SetRssiAsAdvertisingRssiEnum(AdvertisingRssiEnum enumItem)
		{
			Rssi = AdvertisingRssiInfo.AdvertisingRssiToValue(enumItem);
		}

		public bool FromBitBuilder(ref BitBuilder bitBuilder)
		{
			EventType = bitBuilder.RemoveBitsAsUint(8);
			AddressType = bitBuilder.RemoveBitsAsUint(8);
			Address = bitBuilder.RemoveBitsAsUlongLittleEndian(48);
			DirectAddressType = bitBuilder.RemoveBitsAsUint(8);
			DirectAddress = bitBuilder.RemoveBitsAsUlongLittleEndian(48);
			Rssi = bitBuilder.RemoveBitsAsUint(8);
			return true;
		}

		public string ToBitString()
		{
			BitBuilder bitBuilder = new BitBuilder();
			bitBuilder.AddBitsAsUint(EventType, 8);
			bitBuilder.AddBitsAsUint(AddressType, 8);
			bitBuilder.AddBitsAsUlongLittleEndian(Address, 48);
			bitBuilder.AddBitsAsUint(DirectAddressType, 8);
			bitBuilder.AddBitsAsUlongLittleEndian(DirectAddress, 48);
			bitBuilder.AddBitsAsUint(Rssi, 8);
			return bitBuilder.ToString();
		}
	}

	private const uint _EventCode = 62u;

	private Type[] expectedResponseTypes = new Type[0];

	private PacketInfoBase info;

	private uint _PayloadLength;

	public UserFieldsWrapper _UserFields = new UserFieldsWrapper();

	public override PacketType Type => PacketType.Notification;

	public override Type[] ExpectedResponseTypes => expectedResponseTypes;

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

	public uint EventCode => 62u;

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

	public UserFieldsWrapper UserFields => _UserFields;

	protected override bool FromBitBuilder(ref BitBuilder bitBuilder)
	{
		if (bitBuilder.RemoveBitsAsUint(8) != EventCode)
		{
			return false;
		}
		_PayloadLength = bitBuilder.RemoveBitsAsUint(8);
		int numberOfBits = bitBuilder.GetNumberOfBits();
		if (numberOfBits > _PayloadLength * 8 + 7)
		{
			return false;
		}
		if (numberOfBits < _PayloadLength * 8)
		{
			return false;
		}
		if (bitBuilder.RemoveBitsAsUint(8) != UserFields.SubeventCode)
		{
			return false;
		}
		UserFields.NumReports = bitBuilder.RemoveBitsAsUint(8);
		for (int i = 0; i < UserFields.ReportsList.Count; i++)
		{
			UserFields.ReportsList[i].FromBitBuilder(ref bitBuilder);
		}
		if (bitBuilder.GetNumberOfBits() > 7)
		{
			return false;
		}
		return true;
	}

	public override string ToBitString()
	{
		BitBuilder bitBuilder = new BitBuilder();
		bitBuilder.AddBitsAsUint(EventCode, 8);
		int numberOfBits = bitBuilder.GetNumberOfBits();
		bitBuilder.AddBitsAsUint(0u, 8);
		bitBuilder.AddBitsAsUint(UserFields.SubeventCode, 8);
		bitBuilder.AddBitsAsUint(UserFields.NumReports, 8);
		for (int i = 0; i < UserFields.ReportsList.Count; i++)
		{
			bitBuilder.AddBitsAsString(UserFields.ReportsList[i].ToBitString());
		}
		_PayloadLength = (uint)((bitBuilder.GetNumberOfBits() - numberOfBits - 8) / 8);
		if ((bitBuilder.GetNumberOfBits() - numberOfBits - 8) % 8 != 0)
		{
			_PayloadLength++;
		}
		bitBuilder.ChangeBitsAsUint(numberOfBits, _PayloadLength, 8);
		return bitBuilder.ToString();
	}
}
