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

namespace QCRPG.TSL.FMHCI.Packets;

public class SetStereoMode : PacketBase
{
	public class UserFieldsWrapper
	{
		public enum StereoModeEnum
		{
			MONO_AND_STEREO,
			FORCE_MONO_ONLY,
			InvalidStereoModeValue
		}

		public static class StereoModeInfo
		{
			public static StereoModeEnum ValueToStereoMode(uint value)
			{
				return value switch
				{
					0u => StereoModeEnum.MONO_AND_STEREO, 
					1u => StereoModeEnum.FORCE_MONO_ONLY, 
					_ => StereoModeEnum.InvalidStereoModeValue, 
				};
			}

			public static uint StereoModeToValue(StereoModeEnum enumItem)
			{
				return enumItem switch
				{
					StereoModeEnum.MONO_AND_STEREO => 0u, 
					StereoModeEnum.FORCE_MONO_ONLY => 1u, 
					_ => uint.MaxValue, 
				};
			}

			public static string StereoModeToString(StereoModeEnum enumItem)
			{
				return enumItem switch
				{
					StereoModeEnum.MONO_AND_STEREO => "Both mono and stereo reception are possible - the FM HW will transition to stereo when possible", 
					StereoModeEnum.FORCE_MONO_ONLY => "Force mono-only reception", 
					_ => "Invalid StereoMode Value", 
				};
			}

			public static string StereoModeToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = Both mono and stereo reception are possible - the FM HW will transition to stereo when possible");
				stringBuilder.AppendLine("0x1 = Force mono-only reception");
				return stringBuilder.ToString();
			}
		}

		public enum SignalBlendingEnum
		{
			DISABLED,
			ENABLED,
			InvalidSignalBlendingValue
		}

		public static class SignalBlendingInfo
		{
			public static SignalBlendingEnum ValueToSignalBlending(uint value)
			{
				return value switch
				{
					0u => SignalBlendingEnum.DISABLED, 
					1u => SignalBlendingEnum.ENABLED, 
					_ => SignalBlendingEnum.InvalidSignalBlendingValue, 
				};
			}

			public static uint SignalBlendingToValue(SignalBlendingEnum enumItem)
			{
				return enumItem switch
				{
					SignalBlendingEnum.DISABLED => 0u, 
					SignalBlendingEnum.ENABLED => 1u, 
					_ => uint.MaxValue, 
				};
			}

			public static string SignalBlendingToString(SignalBlendingEnum enumItem)
			{
				return enumItem switch
				{
					SignalBlendingEnum.DISABLED => "Disable signal blending feature", 
					SignalBlendingEnum.ENABLED => "Enable blending feature which varies with main signal strength", 
					_ => "Invalid SignalBlending Value", 
				};
			}

			public static string SignalBlendingToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = Disable signal blending feature");
				stringBuilder.AppendLine("0x1 = Enable blending feature which varies with main signal strength");
				return stringBuilder.ToString();
			}
		}

		public enum InterferenceBlendingEnum
		{
			DISABLED,
			ENABLED,
			InvalidInterferenceBlendingValue
		}

		public static class InterferenceBlendingInfo
		{
			public static InterferenceBlendingEnum ValueToInterferenceBlending(uint value)
			{
				return value switch
				{
					0u => InterferenceBlendingEnum.DISABLED, 
					1u => InterferenceBlendingEnum.ENABLED, 
					_ => InterferenceBlendingEnum.InvalidInterferenceBlendingValue, 
				};
			}

			public static uint InterferenceBlendingToValue(InterferenceBlendingEnum enumItem)
			{
				return enumItem switch
				{
					InterferenceBlendingEnum.DISABLED => 0u, 
					InterferenceBlendingEnum.ENABLED => 1u, 
					_ => uint.MaxValue, 
				};
			}

			public static string InterferenceBlendingToString(InterferenceBlendingEnum enumItem)
			{
				return enumItem switch
				{
					InterferenceBlendingEnum.DISABLED => "Disable interference blending feature", 
					InterferenceBlendingEnum.ENABLED => "Enable blending feature which varies with interference level", 
					_ => "Invalid InterferenceBlending Value", 
				};
			}

			public static string InterferenceBlendingToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = Disable interference blending feature");
				stringBuilder.AppendLine("0x1 = Enable blending feature which varies with interference level");
				return stringBuilder.ToString();
			}
		}

		public enum MonoStereoSwitchEnum
		{
			DISABLED,
			ENABLED,
			InvalidMonoStereoSwitchValue
		}

		public static class MonoStereoSwitchInfo
		{
			public static MonoStereoSwitchEnum ValueToMonoStereoSwitch(uint value)
			{
				return value switch
				{
					0u => MonoStereoSwitchEnum.DISABLED, 
					1u => MonoStereoSwitchEnum.ENABLED, 
					_ => MonoStereoSwitchEnum.InvalidMonoStereoSwitchValue, 
				};
			}

			public static uint MonoStereoSwitchToValue(MonoStereoSwitchEnum enumItem)
			{
				return enumItem switch
				{
					MonoStereoSwitchEnum.DISABLED => 0u, 
					MonoStereoSwitchEnum.ENABLED => 1u, 
					_ => uint.MaxValue, 
				};
			}

			public static string MonoStereoSwitchToString(MonoStereoSwitchEnum enumItem)
			{
				return enumItem switch
				{
					MonoStereoSwitchEnum.DISABLED => "Disable mono-stereo switching feature", 
					MonoStereoSwitchEnum.ENABLED => "Enable mono-stereo switching feature", 
					_ => "Invalid MonoStereoSwitch Value", 
				};
			}

			public static string MonoStereoSwitchToDescription()
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("0x0 = Disable mono-stereo switching feature");
				stringBuilder.AppendLine("0x1 = Enable mono-stereo switching feature");
				return stringBuilder.ToString();
			}
		}

		private uint _StereoMode;

		private uint _SignalBlending;

		private uint _InterferenceBlending;

		private uint _MonoStereoSwitch;

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

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

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

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

		public StereoModeEnum GetStereoModeAsStereoModeEnum()
		{
			return StereoModeInfo.ValueToStereoMode(_StereoMode);
		}

		public void SetStereoModeAsStereoModeEnum(StereoModeEnum enumItem)
		{
			StereoMode = StereoModeInfo.StereoModeToValue(enumItem);
		}

		public SignalBlendingEnum GetSignalBlendingAsSignalBlendingEnum()
		{
			return SignalBlendingInfo.ValueToSignalBlending(_SignalBlending);
		}

		public void SetSignalBlendingAsSignalBlendingEnum(SignalBlendingEnum enumItem)
		{
			SignalBlending = SignalBlendingInfo.SignalBlendingToValue(enumItem);
		}

		public InterferenceBlendingEnum GetInterferenceBlendingAsInterferenceBlendingEnum()
		{
			return InterferenceBlendingInfo.ValueToInterferenceBlending(_InterferenceBlending);
		}

		public void SetInterferenceBlendingAsInterferenceBlendingEnum(InterferenceBlendingEnum enumItem)
		{
			InterferenceBlending = InterferenceBlendingInfo.InterferenceBlendingToValue(enumItem);
		}

		public MonoStereoSwitchEnum GetMonoStereoSwitchAsMonoStereoSwitchEnum()
		{
			return MonoStereoSwitchInfo.ValueToMonoStereoSwitch(_MonoStereoSwitch);
		}

		public void SetMonoStereoSwitchAsMonoStereoSwitchEnum(MonoStereoSwitchEnum enumItem)
		{
			MonoStereoSwitch = MonoStereoSwitchInfo.MonoStereoSwitchToValue(enumItem);
		}
	}

	private const uint _Opcode = 19462u;

	private Type[] expectedResponseTypes = new Type[1] { typeof(CommandCompleteForSetStereoMode) };

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

	public uint Opcode => 19462u;

	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;
		}
		UserFields.StereoMode = bitBuilder.RemoveBitsAsUint(8);
		UserFields.SignalBlending = bitBuilder.RemoveBitsAsUint(8);
		UserFields.InterferenceBlending = bitBuilder.RemoveBitsAsUint(8);
		UserFields.MonoStereoSwitch = 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.StereoMode, 8);
		bitBuilder.AddBitsAsUint(UserFields.SignalBlending, 8);
		bitBuilder.AddBitsAsUint(UserFields.InterferenceBlending, 8);
		bitBuilder.AddBitsAsUint(UserFields.MonoStereoSwitch, 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.StereoMode > 1)
		{
			list.Add("Maximum allowed value for Stereo Mode is 0x1");
		}
		if (UserFields.SignalBlending > 1)
		{
			list.Add("Maximum allowed value for Signal Blending is 0x1");
		}
		if (UserFields.InterferenceBlending > 1)
		{
			list.Add("Maximum allowed value for Interference Blending is 0x1");
		}
		if (UserFields.MonoStereoSwitch > 1)
		{
			list.Add("Maximum allowed value for Mono Stereo Switch is 0x1");
		}
		return list;
	}
}
