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

namespace QCRPG.TSL.FMHCI.Packets;

public class Log : PacketBase
{
	public class UserFieldsWrapper
	{
		public enum LogTypeEnum
		{
			GENERIC,
			AUDIO,
			UNDEFINED,
			InvalidLogTypeValue
		}

		public static class LogTypeInfo
		{
			public static LogTypeEnum ValueToLogType(uint value)
			{
				switch (value)
				{
				case 0u:
					return LogTypeEnum.GENERIC;
				case 1u:
					return LogTypeEnum.AUDIO;
				default:
					if (value >= 2 && value <= 3)
					{
						return LogTypeEnum.UNDEFINED;
					}
					return LogTypeEnum.InvalidLogTypeValue;
				}
			}

			public static uint LogTypeToValue(LogTypeEnum enumItem)
			{
				return enumItem switch
				{
					LogTypeEnum.GENERIC => 0u, 
					LogTypeEnum.AUDIO => 1u, 
					LogTypeEnum.UNDEFINED => 2u, 
					_ => uint.MaxValue, 
				};
			}

			public static string LogTypeToString(LogTypeEnum enumItem)
			{
				return enumItem switch
				{
					LogTypeEnum.GENERIC => "Generic FM logs", 
					LogTypeEnum.AUDIO => "FM audio logs", 
					LogTypeEnum.UNDEFINED => "Undefined", 
					_ => "Invalid LogType Value", 
				};
			}

			public static string LogTypeToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = Generic FM logs");
				stringBuilder.AppendLine("0x1 = FM audio logs");
				stringBuilder.AppendLine("0x2-0x3 = Undefined");
				return stringBuilder.ToString();
			}
		}

		public enum AudioLogTypeEnum
		{
			FM_RX_PCM,
			FM_TX_PCM,
			UNDEFINED,
			InvalidAudioLogTypeValue
		}

		public static class AudioLogTypeInfo
		{
			public static AudioLogTypeEnum ValueToAudioLogType(uint value)
			{
				switch (value)
				{
				case 0u:
					return AudioLogTypeEnum.FM_RX_PCM;
				case 1u:
					return AudioLogTypeEnum.FM_TX_PCM;
				default:
					if (value >= 2 && value <= 3)
					{
						return AudioLogTypeEnum.UNDEFINED;
					}
					return AudioLogTypeEnum.InvalidAudioLogTypeValue;
				}
			}

			public static uint AudioLogTypeToValue(AudioLogTypeEnum enumItem)
			{
				return enumItem switch
				{
					AudioLogTypeEnum.FM_RX_PCM => 0u, 
					AudioLogTypeEnum.FM_TX_PCM => 1u, 
					AudioLogTypeEnum.UNDEFINED => 2u, 
					_ => uint.MaxValue, 
				};
			}

			public static string AudioLogTypeToString(AudioLogTypeEnum enumItem)
			{
				return enumItem switch
				{
					AudioLogTypeEnum.FM_RX_PCM => "FM_RX_PCM", 
					AudioLogTypeEnum.FM_TX_PCM => "FM_TX_PCM", 
					AudioLogTypeEnum.UNDEFINED => "Undefined", 
					_ => "Invalid AudioLogType Value", 
				};
			}

			public static string AudioLogTypeToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = FM_RX_PCM");
				stringBuilder.AppendLine("0x1 = FM_TX_PCM");
				stringBuilder.AppendLine("0x2-0x3 = Undefined");
				return stringBuilder.ToString();
			}
		}

		public enum AudioLogSampleRateEnum
		{
			RATE_16KHZ,
			RATE_48KHZ,
			UNDEFINED,
			InvalidAudioLogSampleRateValue
		}

		public static class AudioLogSampleRateInfo
		{
			public static AudioLogSampleRateEnum ValueToAudioLogSampleRate(uint value)
			{
				switch (value)
				{
				case 0u:
					return AudioLogSampleRateEnum.RATE_16KHZ;
				case 1u:
					return AudioLogSampleRateEnum.RATE_48KHZ;
				default:
					if (value >= 2 && value <= 3)
					{
						return AudioLogSampleRateEnum.UNDEFINED;
					}
					return AudioLogSampleRateEnum.InvalidAudioLogSampleRateValue;
				}
			}

			public static uint AudioLogSampleRateToValue(AudioLogSampleRateEnum enumItem)
			{
				return enumItem switch
				{
					AudioLogSampleRateEnum.RATE_16KHZ => 0u, 
					AudioLogSampleRateEnum.RATE_48KHZ => 1u, 
					AudioLogSampleRateEnum.UNDEFINED => 2u, 
					_ => uint.MaxValue, 
				};
			}

			public static string AudioLogSampleRateToString(AudioLogSampleRateEnum enumItem)
			{
				return enumItem switch
				{
					AudioLogSampleRateEnum.RATE_16KHZ => "16 kHz", 
					AudioLogSampleRateEnum.RATE_48KHZ => "48 kHz", 
					AudioLogSampleRateEnum.UNDEFINED => "Undefined", 
					_ => "Invalid AudioLogSampleRate Value", 
				};
			}

			public static string AudioLogSampleRateToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = 16 kHz");
				stringBuilder.AppendLine("0x1 = 48 kHz");
				stringBuilder.AppendLine("0x2-0x3 = Undefined");
				return stringBuilder.ToString();
			}
		}

		public enum AudioLogChannelCountEnum
		{
			MONO,
			STEREO,
			InvalidAudioLogChannelCountValue
		}

		public static class AudioLogChannelCountInfo
		{
			public static AudioLogChannelCountEnum ValueToAudioLogChannelCount(uint value)
			{
				return value switch
				{
					0u => AudioLogChannelCountEnum.MONO, 
					1u => AudioLogChannelCountEnum.STEREO, 
					_ => AudioLogChannelCountEnum.InvalidAudioLogChannelCountValue, 
				};
			}

			public static uint AudioLogChannelCountToValue(AudioLogChannelCountEnum enumItem)
			{
				return enumItem switch
				{
					AudioLogChannelCountEnum.MONO => 0u, 
					AudioLogChannelCountEnum.STEREO => 1u, 
					_ => uint.MaxValue, 
				};
			}

			public static string AudioLogChannelCountToString(AudioLogChannelCountEnum enumItem)
			{
				return enumItem switch
				{
					AudioLogChannelCountEnum.MONO => "MONO", 
					AudioLogChannelCountEnum.STEREO => "STEREO", 
					_ => "Invalid AudioLogChannelCount Value", 
				};
			}

			public static string AudioLogChannelCountToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = MONO");
				stringBuilder.AppendLine("0x1 = STEREO");
				return stringBuilder.ToString();
			}
		}

		private uint _LogType;

		private uint _AudioLogType;

		private uint _AudioLogSampleRate;

		private uint _AudioLogChannelCount;

		private uint _Reserved;

		private uint _LogSequenceNumber;

		private ulong _LogTimestamp;

		private uint _LogStringLength;

		private List<uint> _LogDataList = new List<uint>();

		public uint LogType
		{
			get
			{
				return _LogType;
			}
			set
			{
				if (value > 3)
				{
					throw new Exception("Maximum possible value for LogType is 0x3");
				}
				_LogType = value;
			}
		}

		public uint AudioLogType
		{
			get
			{
				return _AudioLogType;
			}
			set
			{
				if (value > 3)
				{
					throw new Exception("Maximum possible value for AudioLogType is 0x3");
				}
				_AudioLogType = value;
			}
		}

		public uint AudioLogSampleRate
		{
			get
			{
				return _AudioLogSampleRate;
			}
			set
			{
				if (value > 3)
				{
					throw new Exception("Maximum possible value for AudioLogSampleRate is 0x3");
				}
				_AudioLogSampleRate = value;
			}
		}

		public uint AudioLogChannelCount
		{
			get
			{
				return _AudioLogChannelCount;
			}
			set
			{
				if (value > 1)
				{
					throw new Exception("Maximum possible value for AudioLogChannelCount is 0x1");
				}
				_AudioLogChannelCount = value;
			}
		}

		public uint Reserved
		{
			get
			{
				return _Reserved;
			}
			set
			{
				if (value > 1)
				{
					throw new Exception("Maximum possible value for Reserved is 0x1");
				}
				_Reserved = value;
			}
		}

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

		public ulong LogTimestamp
		{
			get
			{
				return _LogTimestamp;
			}
			set
			{
				_LogTimestamp = value;
			}
		}

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

		public List<uint> LogDataList => _LogDataList;

		public LogTypeEnum GetLogTypeAsLogTypeEnum()
		{
			return LogTypeInfo.ValueToLogType(_LogType);
		}

		public void SetLogTypeAsLogTypeEnum(LogTypeEnum enumItem)
		{
			LogType = LogTypeInfo.LogTypeToValue(enumItem);
		}

		public AudioLogTypeEnum GetAudioLogTypeAsAudioLogTypeEnum()
		{
			return AudioLogTypeInfo.ValueToAudioLogType(_AudioLogType);
		}

		public void SetAudioLogTypeAsAudioLogTypeEnum(AudioLogTypeEnum enumItem)
		{
			AudioLogType = AudioLogTypeInfo.AudioLogTypeToValue(enumItem);
		}

		public AudioLogSampleRateEnum GetAudioLogSampleRateAsAudioLogSampleRateEnum()
		{
			return AudioLogSampleRateInfo.ValueToAudioLogSampleRate(_AudioLogSampleRate);
		}

		public void SetAudioLogSampleRateAsAudioLogSampleRateEnum(AudioLogSampleRateEnum enumItem)
		{
			AudioLogSampleRate = AudioLogSampleRateInfo.AudioLogSampleRateToValue(enumItem);
		}

		public AudioLogChannelCountEnum GetAudioLogChannelCountAsAudioLogChannelCountEnum()
		{
			return AudioLogChannelCountInfo.ValueToAudioLogChannelCount(_AudioLogChannelCount);
		}

		public void SetAudioLogChannelCountAsAudioLogChannelCountEnum(AudioLogChannelCountEnum enumItem)
		{
			AudioLogChannelCount = AudioLogChannelCountInfo.AudioLogChannelCountToValue(enumItem);
		}
	}

	private const uint _EventCode = 21u;

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

	public uint EventCode => 21u;

	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;
		}
		UserFields.LogType = bitBuilder.RemoveBitsAsUint(2);
		UserFields.AudioLogType = bitBuilder.RemoveBitsAsUint(2);
		UserFields.AudioLogSampleRate = bitBuilder.RemoveBitsAsUint(2);
		UserFields.AudioLogChannelCount = bitBuilder.RemoveBitsAsUint(1);
		UserFields.Reserved = bitBuilder.RemoveBitsAsUint(1);
		UserFields.LogSequenceNumber = bitBuilder.RemoveBitsAsUint(8);
		UserFields.LogTimestamp = bitBuilder.RemoveBitsAsUlong(56);
		UserFields.LogStringLength = bitBuilder.RemoveBitsAsUint(8);
		for (int i = 0; i < UserFields.LogDataList.Count; i++)
		{
			UserFields.LogDataList[i] = bitBuilder.RemoveBitsAsUint(8);
		}
		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.LogType, 2);
		bitBuilder.AddBitsAsUint(UserFields.AudioLogType, 2);
		bitBuilder.AddBitsAsUint(UserFields.AudioLogSampleRate, 2);
		bitBuilder.AddBitsAsUint(UserFields.AudioLogChannelCount, 1);
		bitBuilder.AddBitsAsUint(UserFields.Reserved, 1);
		bitBuilder.AddBitsAsUint(UserFields.LogSequenceNumber, 8);
		bitBuilder.AddBitsAsUlong(UserFields.LogTimestamp, 56);
		bitBuilder.AddBitsAsUint(UserFields.LogStringLength, 8);
		for (int i = 0; i < UserFields.LogDataList.Count; i++)
		{
			if (UserFields.LogDataList[i] > 255)
			{
				throw new Exception("UserFields.LogDataList[i] is > 0xFF");
			}
			bitBuilder.AddBitsAsUint(UserFields.LogDataList[i], 8);
		}
		_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.LogType > 3)
		{
			list.Add("Maximum allowed value for Log Type is 0x3");
		}
		if (UserFields.AudioLogType > 3)
		{
			list.Add("Maximum allowed value for Audio Log Type is 0x3");
		}
		if (UserFields.AudioLogSampleRate > 3)
		{
			list.Add("Maximum allowed value for Audio Log Sample Rate is 0x3");
		}
		if (UserFields.AudioLogChannelCount > 1)
		{
			list.Add("Maximum allowed value for Audio Log Channel Count is 0x1");
		}
		if (UserFields.LogStringLength > 235)
		{
			list.Add("Maximum allowed value for Log String Length is 0xEB");
		}
		return list;
	}
}
