using System;
using System.Text;
using QCRPG.Framework;

namespace QCRPG.TSL.BT.Packets;

public class LtLeAeTest : PacketBase
{
	public class UserFieldsWrapper
	{
		public enum AeCaseEnum
		{
			None,
			SCAN_REQ_ADVA_tampered,
			CONNECT_IND_ADVA_tampered,
			SCAN_REQ_Min_Time,
			SCAN_REQ_Max_Time,
			SCAN_RSP_Min_Time,
			Privacy_CONN_IND_Identity,
			Skip_CONN_IND_Once,
			Force_T_MAFS,
			Force_T_MAFS_plus_SCAN_RSP_Min_Time,
			Scannable_Latest_Tx,
			InvalidAeCaseValue
		}

		public static class AeCaseInfo
		{
			public static AeCaseEnum ValueToAeCase(uint value)
			{
				return value switch
				{
					0u => AeCaseEnum.None, 
					1u => AeCaseEnum.SCAN_REQ_ADVA_tampered, 
					2u => AeCaseEnum.CONNECT_IND_ADVA_tampered, 
					3u => AeCaseEnum.SCAN_REQ_Min_Time, 
					4u => AeCaseEnum.SCAN_REQ_Max_Time, 
					5u => AeCaseEnum.SCAN_RSP_Min_Time, 
					6u => AeCaseEnum.Privacy_CONN_IND_Identity, 
					7u => AeCaseEnum.Skip_CONN_IND_Once, 
					8u => AeCaseEnum.Force_T_MAFS, 
					9u => AeCaseEnum.Force_T_MAFS_plus_SCAN_RSP_Min_Time, 
					11u => AeCaseEnum.Scannable_Latest_Tx, 
					_ => AeCaseEnum.InvalidAeCaseValue, 
				};
			}

			public static uint AeCaseToValue(AeCaseEnum enumItem)
			{
				return enumItem switch
				{
					AeCaseEnum.None => 0u, 
					AeCaseEnum.SCAN_REQ_ADVA_tampered => 1u, 
					AeCaseEnum.CONNECT_IND_ADVA_tampered => 2u, 
					AeCaseEnum.SCAN_REQ_Min_Time => 3u, 
					AeCaseEnum.SCAN_REQ_Max_Time => 4u, 
					AeCaseEnum.SCAN_RSP_Min_Time => 5u, 
					AeCaseEnum.Privacy_CONN_IND_Identity => 6u, 
					AeCaseEnum.Skip_CONN_IND_Once => 7u, 
					AeCaseEnum.Force_T_MAFS => 8u, 
					AeCaseEnum.Force_T_MAFS_plus_SCAN_RSP_Min_Time => 9u, 
					AeCaseEnum.Scannable_Latest_Tx => 11u, 
					_ => uint.MaxValue, 
				};
			}

			public static string AeCaseToString(AeCaseEnum enumItem)
			{
				return enumItem switch
				{
					AeCaseEnum.None => "No LE AE case set", 
					AeCaseEnum.SCAN_REQ_ADVA_tampered => "AdvA in SCAN_REQ is tampered", 
					AeCaseEnum.CONNECT_IND_ADVA_tampered => "AdvA in CONNECT_IND is tampered", 
					AeCaseEnum.SCAN_REQ_Min_Time => "The gap between AUX_ADV_IND and AUX_SCAN_REQ is T_IFS - 1.5us", 
					AeCaseEnum.SCAN_REQ_Max_Time => "The gap between AUX_ADV_IND and AUX_SCAN_REQ is T_IFS + 1.5us", 
					AeCaseEnum.SCAN_RSP_Min_Time => "The gap between AUX_SCAN_REQ and AUX_SCAN_RSP is T_IFS - 1.5", 
					AeCaseEnum.Privacy_CONN_IND_Identity => "Initiator uses identity address in CONNECT_IND PDU", 
					AeCaseEnum.Skip_CONN_IND_Once => "Advertiser skip CONNECT_IND once", 
					AeCaseEnum.Force_T_MAFS => "Force T_MAFS gap between ADV_EXT_IND and AUX_ADV_IND", 
					AeCaseEnum.Force_T_MAFS_plus_SCAN_RSP_Min_Time => "Force T_MAFS plus SCAN_RSP_Min_Time", 
					AeCaseEnum.Scannable_Latest_Tx => "Advertiser uses latest transmission time (for AUX_ADV_IND and AUX_SCAN_RSP) to scanner", 
					_ => "Invalid AeCase Value", 
				};
			}

			public static string AeCaseToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = No LE AE case set");
				stringBuilder.AppendLine("0x1 = AdvA in SCAN_REQ is tampered");
				stringBuilder.AppendLine("0x2 = AdvA in CONNECT_IND is tampered");
				stringBuilder.AppendLine("0x3 = The gap between AUX_ADV_IND and AUX_SCAN_REQ is T_IFS - 1.5us");
				stringBuilder.AppendLine("0x4 = The gap between AUX_ADV_IND and AUX_SCAN_REQ is T_IFS + 1.5us");
				stringBuilder.AppendLine("0x5 = The gap between AUX_SCAN_REQ and AUX_SCAN_RSP is T_IFS - 1.5");
				stringBuilder.AppendLine("0x6 = Initiator uses identity address in CONNECT_IND PDU");
				stringBuilder.AppendLine("0x7 = Advertiser skip CONNECT_IND once");
				stringBuilder.AppendLine("0x8 = Force T_MAFS gap between ADV_EXT_IND and AUX_ADV_IND");
				stringBuilder.AppendLine("0x9 = Force T_MAFS plus SCAN_RSP_Min_Time");
				stringBuilder.AppendLine("0xB = Advertiser uses latest transmission time (for AUX_ADV_IND and AUX_SCAN_RSP) to scanner");
				return stringBuilder.ToString();
			}
		}

		private const uint _SubOpcode = 13u;

		private uint _AeCase;

		public uint SubOpcode => 13u;

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

		public AeCaseEnum GetAeCaseAsAeCaseEnum()
		{
			return AeCaseInfo.ValueToAeCase(_AeCase);
		}

		public void SetAeCaseAsAeCaseEnum(AeCaseEnum enumItem)
		{
			AeCase = AeCaseInfo.AeCaseToValue(enumItem);
		}
	}

	private const uint _Opcode = 64536u;

	private Type[] expectedResponseTypes = new Type[2]
	{
		typeof(CommandCompleteForLowerTester),
		typeof(CommandCompleteForNop)
	};

	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 LtLeAeTestInfo(this);
			}
			return info;
		}
	}

	public uint Opcode => 64536u;

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

	public UserFieldsWrapper UserFields => _UserFields;

	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;
		}
		if (bitBuilder.RemoveBitsAsUint(8) != UserFields.SubOpcode)
		{
			return false;
		}
		UserFields.AeCase = bitBuilder.RemoveBitsAsUint(8);
		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.AddBitsAsUint(UserFields.SubOpcode, 8);
		bitBuilder.AddBitsAsUint(UserFields.AeCase, 8);
		_PayloadLength = (uint)((bitBuilder.GetNumberOfBits() - numberOfBits - 8) / 8);
		if ((bitBuilder.GetNumberOfBits() - numberOfBits - 8) % 8 != 0)
		{
			_PayloadLength++;
		}
		bitBuilder.ChangeBitsAsUint(numberOfBits, _PayloadLength, 8);
		return bitBuilder.ToString();
	}
}
