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

namespace QCRPG.TSL.FM.Packets;

public class RadioControl : PacketBase
{
	public class UserFieldsWrapper
	{
		public enum HighAndLowSideInjectionEnum
		{
			AUTO_HIGH_SIDE_AND_LOW_SIDE,
			LOW_SIDE_INJECTION,
			HIGH_SIDE_INJECTION,
			InvalidHighAndLowSideInjectionValue
		}

		public static class HighAndLowSideInjectionInfo
		{
			public static HighAndLowSideInjectionEnum ValueToHighAndLowSideInjection(uint value)
			{
				return value switch
				{
					0u => HighAndLowSideInjectionEnum.AUTO_HIGH_SIDE_AND_LOW_SIDE, 
					1u => HighAndLowSideInjectionEnum.LOW_SIDE_INJECTION, 
					2u => HighAndLowSideInjectionEnum.HIGH_SIDE_INJECTION, 
					_ => HighAndLowSideInjectionEnum.InvalidHighAndLowSideInjectionValue, 
				};
			}

			public static uint HighAndLowSideInjectionToValue(HighAndLowSideInjectionEnum enumItem)
			{
				return enumItem switch
				{
					HighAndLowSideInjectionEnum.AUTO_HIGH_SIDE_AND_LOW_SIDE => 0u, 
					HighAndLowSideInjectionEnum.LOW_SIDE_INJECTION => 1u, 
					HighAndLowSideInjectionEnum.HIGH_SIDE_INJECTION => 2u, 
					_ => uint.MaxValue, 
				};
			}

			public static string HighAndLowSideInjectionToString(HighAndLowSideInjectionEnum enumItem)
			{
				return enumItem switch
				{
					HighAndLowSideInjectionEnum.AUTO_HIGH_SIDE_AND_LOW_SIDE => "AUTO_HIGH_SIDE_AND_LOW_SIDE", 
					HighAndLowSideInjectionEnum.LOW_SIDE_INJECTION => "LOW_SIDE_INJECTION", 
					HighAndLowSideInjectionEnum.HIGH_SIDE_INJECTION => "HIGH_SIDE_INJECTION", 
					_ => "Invalid HighAndLowSideInjection Value", 
				};
			}

			public static string HighAndLowSideInjectionToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = AUTO_HIGH_SIDE_AND_LOW_SIDE");
				stringBuilder.AppendLine("0x1 = LOW_SIDE_INJECTION");
				stringBuilder.AppendLine("0x2 = HIGH_SIDE_INJECTION");
				return stringBuilder.ToString();
			}
		}

		public enum EmphasisEnum
		{
			TIME_CONSTANT_75US,
			TIME_CONSTANT_50US,
			InvalidEmphasisValue
		}

		public static class EmphasisInfo
		{
			public static EmphasisEnum ValueToEmphasis(uint value)
			{
				return value switch
				{
					0u => EmphasisEnum.TIME_CONSTANT_75US, 
					1u => EmphasisEnum.TIME_CONSTANT_50US, 
					_ => EmphasisEnum.InvalidEmphasisValue, 
				};
			}

			public static uint EmphasisToValue(EmphasisEnum enumItem)
			{
				return enumItem switch
				{
					EmphasisEnum.TIME_CONSTANT_75US => 0u, 
					EmphasisEnum.TIME_CONSTANT_50US => 1u, 
					_ => uint.MaxValue, 
				};
			}

			public static string EmphasisToString(EmphasisEnum enumItem)
			{
				return enumItem switch
				{
					EmphasisEnum.TIME_CONSTANT_75US => "75us time constant (the pre-emphasis/de-emphasis timing typically used in the US and Japan)", 
					EmphasisEnum.TIME_CONSTANT_50US => "50us time constant (the pre-emphasis/de-emphasis timing typically used outside of the US and Japan)", 
					_ => "Invalid Emphasis Value", 
				};
			}

			public static string EmphasisToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = 75us time constant (the pre-emphasis/de-emphasis timing typically used in the US and Japan)");
				stringBuilder.AppendLine("0x1 = 50us time constant (the pre-emphasis/de-emphasis timing typically used outside of the US and Japan)");
				return stringBuilder.ToString();
			}
		}

		public enum ChannelSpacingEnum
		{
			CHANNEL_SPACING_200KHZ,
			CHANNEL_SPACING_100KHZ,
			CHANNEL_SPACING_50KHZ,
			InvalidChannelSpacingValue
		}

		public static class ChannelSpacingInfo
		{
			public static ChannelSpacingEnum ValueToChannelSpacing(uint value)
			{
				return value switch
				{
					0u => ChannelSpacingEnum.CHANNEL_SPACING_200KHZ, 
					1u => ChannelSpacingEnum.CHANNEL_SPACING_100KHZ, 
					2u => ChannelSpacingEnum.CHANNEL_SPACING_50KHZ, 
					_ => ChannelSpacingEnum.InvalidChannelSpacingValue, 
				};
			}

			public static uint ChannelSpacingToValue(ChannelSpacingEnum enumItem)
			{
				return enumItem switch
				{
					ChannelSpacingEnum.CHANNEL_SPACING_200KHZ => 0u, 
					ChannelSpacingEnum.CHANNEL_SPACING_100KHZ => 1u, 
					ChannelSpacingEnum.CHANNEL_SPACING_50KHZ => 2u, 
					_ => uint.MaxValue, 
				};
			}

			public static string ChannelSpacingToString(ChannelSpacingEnum enumItem)
			{
				return enumItem switch
				{
					ChannelSpacingEnum.CHANNEL_SPACING_200KHZ => "CHANNEL_SPACING_200KHZ", 
					ChannelSpacingEnum.CHANNEL_SPACING_100KHZ => "CHANNEL_SPACING_100KHZ", 
					ChannelSpacingEnum.CHANNEL_SPACING_50KHZ => "CHANNEL_SPACING_50KHZ", 
					_ => "Invalid ChannelSpacing Value", 
				};
			}

			public static string ChannelSpacingToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = CHANNEL_SPACING_200KHZ");
				stringBuilder.AppendLine("0x1 = CHANNEL_SPACING_100KHZ");
				stringBuilder.AppendLine("0x2 = CHANNEL_SPACING_50KHZ");
				return stringBuilder.ToString();
			}
		}

		public enum BandEnum
		{
			US_AND_EUROPE,
			JAPAN,
			InvalidBandValue
		}

		public static class BandInfo
		{
			public static BandEnum ValueToBand(uint value)
			{
				return value switch
				{
					0u => BandEnum.US_AND_EUROPE, 
					1u => BandEnum.JAPAN, 
					_ => BandEnum.InvalidBandValue, 
				};
			}

			public static uint BandToValue(BandEnum enumItem)
			{
				return enumItem switch
				{
					BandEnum.US_AND_EUROPE => 0u, 
					BandEnum.JAPAN => 1u, 
					_ => uint.MaxValue, 
				};
			}

			public static string BandToString(BandEnum enumItem)
			{
				return enumItem switch
				{
					BandEnum.US_AND_EUROPE => "US/Europe FM band (87.5-108MHz)", 
					BandEnum.JAPAN => "Japan FM band (76-90MHz)", 
					_ => "Invalid Band Value", 
				};
			}

			public static string BandToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = US/Europe FM band (87.5-108MHz)");
				stringBuilder.AppendLine("0x1 = Japan FM band (76-90MHz)");
				return stringBuilder.ToString();
			}
		}

		public enum RadioControlEnum
		{
			OFF,
			RECEIVER_ON,
			TRANSMITTER_ON,
			RESET,
			InvalidRadioControlValue
		}

		public static class RadioControlInfo
		{
			public static RadioControlEnum ValueToRadioControl(uint value)
			{
				return value switch
				{
					0u => RadioControlEnum.OFF, 
					1u => RadioControlEnum.RECEIVER_ON, 
					2u => RadioControlEnum.TRANSMITTER_ON, 
					3u => RadioControlEnum.RESET, 
					_ => RadioControlEnum.InvalidRadioControlValue, 
				};
			}

			public static uint RadioControlToValue(RadioControlEnum enumItem)
			{
				return enumItem switch
				{
					RadioControlEnum.OFF => 0u, 
					RadioControlEnum.RECEIVER_ON => 1u, 
					RadioControlEnum.TRANSMITTER_ON => 2u, 
					RadioControlEnum.RESET => 3u, 
					_ => uint.MaxValue, 
				};
			}

			public static string RadioControlToString(RadioControlEnum enumItem)
			{
				return enumItem switch
				{
					RadioControlEnum.OFF => "OFF", 
					RadioControlEnum.RECEIVER_ON => "RECEIVER_ON", 
					RadioControlEnum.TRANSMITTER_ON => "TRANSMITTER_ON", 
					RadioControlEnum.RESET => "RESET", 
					_ => "Invalid RadioControl Value", 
				};
			}

			public static string RadioControlToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = OFF");
				stringBuilder.AppendLine("0x1 = RECEIVER_ON");
				stringBuilder.AppendLine("0x2 = TRANSMITTER_ON");
				stringBuilder.AppendLine("0x3 = RESET");
				return stringBuilder.ToString();
			}
		}

		private const uint _RegisterAddress = 3u;

		private uint _HighAndLowSideInjection;

		private uint _Emphasis;

		private uint _ChannelSpacing;

		private uint _Band;

		private uint _RadioControl;

		public uint RegisterAddress => 3u;

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

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

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

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

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

		public RegisterMapEnum GetRegisterAddressAsRegisterMapEnum()
		{
			return RegisterMapInfo.ValueToRegisterMap(3u);
		}

		public HighAndLowSideInjectionEnum GetHighAndLowSideInjectionAsHighAndLowSideInjectionEnum()
		{
			return HighAndLowSideInjectionInfo.ValueToHighAndLowSideInjection(_HighAndLowSideInjection);
		}

		public void SetHighAndLowSideInjectionAsHighAndLowSideInjectionEnum(HighAndLowSideInjectionEnum enumItem)
		{
			HighAndLowSideInjection = HighAndLowSideInjectionInfo.HighAndLowSideInjectionToValue(enumItem);
		}

		public EmphasisEnum GetEmphasisAsEmphasisEnum()
		{
			return EmphasisInfo.ValueToEmphasis(_Emphasis);
		}

		public void SetEmphasisAsEmphasisEnum(EmphasisEnum enumItem)
		{
			Emphasis = EmphasisInfo.EmphasisToValue(enumItem);
		}

		public ChannelSpacingEnum GetChannelSpacingAsChannelSpacingEnum()
		{
			return ChannelSpacingInfo.ValueToChannelSpacing(_ChannelSpacing);
		}

		public void SetChannelSpacingAsChannelSpacingEnum(ChannelSpacingEnum enumItem)
		{
			ChannelSpacing = ChannelSpacingInfo.ChannelSpacingToValue(enumItem);
		}

		public BandEnum GetBandAsBandEnum()
		{
			return BandInfo.ValueToBand(_Band);
		}

		public void SetBandAsBandEnum(BandEnum enumItem)
		{
			Band = BandInfo.BandToValue(enumItem);
		}

		public RadioControlEnum GetRadioControlAsRadioControlEnum()
		{
			return RadioControlInfo.ValueToRadioControl(_RadioControl);
		}

		public void SetRadioControlAsRadioControlEnum(RadioControlEnum enumItem)
		{
			RadioControl = RadioControlInfo.RadioControlToValue(enumItem);
		}
	}

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

	private PacketInfoBase info;

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

	public UserFieldsWrapper UserFields => _UserFields;

	protected override bool FromBitBuilder(ref BitBuilder bitBuilder)
	{
		if (bitBuilder.RemoveBitsAsUint(8) != UserFields.RegisterAddress)
		{
			return false;
		}
		UserFields.HighAndLowSideInjection = bitBuilder.RemoveBitsAsUint(2);
		UserFields.Emphasis = bitBuilder.RemoveBitsAsUint(1);
		UserFields.ChannelSpacing = bitBuilder.RemoveBitsAsUint(2);
		UserFields.Band = bitBuilder.RemoveBitsAsUint(1);
		UserFields.RadioControl = bitBuilder.RemoveBitsAsUint(2);
		if (bitBuilder.GetNumberOfBits() > 7)
		{
			return false;
		}
		return true;
	}

	public override string ToBitString()
	{
		BitBuilder bitBuilder = new BitBuilder();
		bitBuilder.AddBitsAsUint(UserFields.RegisterAddress, 8);
		bitBuilder.AddBitsAsUint(UserFields.HighAndLowSideInjection, 2);
		bitBuilder.AddBitsAsUint(UserFields.Emphasis, 1);
		bitBuilder.AddBitsAsUint(UserFields.ChannelSpacing, 2);
		bitBuilder.AddBitsAsUint(UserFields.Band, 1);
		bitBuilder.AddBitsAsUint(UserFields.RadioControl, 2);
		return bitBuilder.ToString();
	}

	public override List<string> GetWarnings()
	{
		List<string> list = new List<string>();
		if (UserFields.HighAndLowSideInjection > 2)
		{
			list.Add("Maximum allowed value for High And Low Side Injection is 0x2");
		}
		if (UserFields.Emphasis > 1)
		{
			list.Add("Maximum allowed value for Emphasis is 0x1");
		}
		if (UserFields.ChannelSpacing > 2)
		{
			list.Add("Maximum allowed value for Channel Spacing is 0x2");
		}
		if (UserFields.Band > 1)
		{
			list.Add("Maximum allowed value for Band is 0x1");
		}
		if (UserFields.RadioControl > 3)
		{
			list.Add("Maximum allowed value for Radio Control is 0x3");
		}
		return list;
	}
}
