using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;

namespace QCRPG.Framework;

public static class PacketStringTranslator
{
	public static bool StringToPacket(string textString, PacketBase packet)
	{
		string[] array = textString.Split(new char[1] { ':' }, 2, StringSplitOptions.RemoveEmptyEntries);
		string text = ((array.Length > 0) ? array[0].Trim() : string.Empty);
		Type type = packet.GetType();
		if (type.Name.ToLower() != text.ToLower())
		{
			return false;
		}
		Type nestedType1 = type.GetNestedType("UserFieldsWrapper");
		Type nestedType2 = null;
		if (nestedType1 == null)
		{
			return true;
		}
		PropertyInfo propertyInfo2 = type.GetProperties().First((PropertyInfo propertyInfo) => propertyInfo.PropertyType == nestedType1);
		PropertyInfo[] properties = nestedType1.GetProperties();
		List<PropertyInfo> nestedFieldsInfos = null;
		object value = propertyInfo2.GetValue(packet, null);
		IList subFieldList = null;
		PropertyInfo[] array2 = properties;
		foreach (PropertyInfo propertyInfo3 in array2)
		{
			ClearProperty(propertyInfo3, value, ref nestedType2, ref nestedFieldsInfos, ref subFieldList);
			_ = nestedType2 != null;
		}
		packet.SetDefaultValues();
		if (array.Length < 2)
		{
			return true;
		}
		List<string> list = new List<string>(array[1].Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries));
		int num = 0;
		int num2 = 0;
		int num3 = 0;
		foreach (string item in list)
		{
			string[] array3 = item.Split(new char[1] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries);
			string parameterName = ((array3.Length > 0) ? array3[0].Trim() : string.Empty);
			string parameterValueString = ((array3.Length == 2) ? array3[1].Trim() : string.Empty);
			PropertyInfo propertyInfo4 = properties.FirstOrDefault((PropertyInfo propertyInfo) => propertyInfo.Name == parameterName + (propertyInfo.PropertyType.IsGenericType ? "List" : ""));
			if (propertyInfo4 != null)
			{
				SetProperty(propertyInfo4, value, parameterValueString, (packet.Info.FieldInfoList.Find((PacketFieldInfo packetFieldInfo) => string.Join("", from s in packetFieldInfo.ParameterName.Replace('_', ' ').Replace('-', ' ').Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
					select char.ToUpper(s[0]) + s.ToLower().Remove(0, 1)) == parameterName) ?? packet.Info.FieldInfoList.Find((PacketFieldInfo packetFieldInfo) => packetFieldInfo.ParameterName.Contains('[') && string.Join("", from s in packetFieldInfo.ParameterName.Remove(packetFieldInfo.ParameterName.IndexOf('[')).Replace('_', ' ').Replace('-', ' ')
						.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
					select char.ToUpper(s[0]) + s.ToLower().Remove(0, 1)) == parameterName)).DataEntryMode);
				num++;
			}
			else
			{
				int num4 = nestedFieldsInfos.FindIndex((PropertyInfo propertyInfo) => propertyInfo.Name == parameterName + (propertyInfo.PropertyType.IsGenericType ? "List" : ""));
				PropertyInfo propertyInfo5 = nestedFieldsInfos[num4];
				int num5 = 1 << num4;
				if ((num3 & num5) == num5)
				{
					num2++;
					num3 = 0;
				}
				SetProperty(propertyInfo5, subFieldList[num2], parameterValueString, packet.Info.FieldInfoList.Find((PacketFieldInfo packetFieldInfo) => packetFieldInfo.ParameterName.Contains('[') && string.Join("", from s in packetFieldInfo.ParameterName.Remove(packetFieldInfo.ParameterName.IndexOf('[')).Replace('_', ' ').Replace('-', ' ')
						.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
					select char.ToUpper(s[0]) + s.ToLower().Remove(0, 1)) == parameterName).DataEntryMode);
				num3 |= num5;
				num++;
			}
			packet.Info.UpdateFieldInfoFromPacket();
		}
		return num == list.Count;
	}

	private static void ClearProperty(PropertyInfo propertyInfo, object member, ref Type nestedType, ref List<PropertyInfo> nestedFieldsInfos, ref IList subFieldList)
	{
		if (propertyInfo.PropertyType.IsGenericType)
		{
			IList list = (IList)propertyInfo.GetValue(member, null);
			Type type = propertyInfo.PropertyType.GetGenericArguments()[0];
			if (type.IsValueType)
			{
				for (int i = 0; i < list.Count; i++)
				{
					list[i] = 0u;
				}
				return;
			}
			nestedType = type;
			nestedFieldsInfos = new List<PropertyInfo>(nestedType.GetProperties());
			subFieldList = list;
			Type nestedType2 = null;
			List<PropertyInfo> nestedFieldsInfos2 = null;
			IList subFieldList2 = null;
			for (int j = 0; j < list.Count; j++)
			{
				foreach (PropertyInfo nestedFieldsInfo in nestedFieldsInfos)
				{
					ClearProperty(nestedFieldsInfo, list[j], ref nestedType2, ref nestedFieldsInfos2, ref subFieldList2);
				}
			}
		}
		else if (propertyInfo.CanWrite)
		{
			propertyInfo.SetValue(member, 0u, null);
		}
	}

	private static void SetProperty(PropertyInfo propertyInfo, object member, string parameterValueString, DataEntryMode dataEntryMode)
	{
		Type propertyType = propertyInfo.PropertyType;
		string fieldName = (propertyType.IsGenericType ? propertyInfo.Name.Remove(propertyInfo.Name.Length - 4) : propertyInfo.Name);
		IEnumerator<MethodInfo> enumerator = (from methodInfo in member.GetType().GetMethods()
			where methodInfo.Name.StartsWith($"Set{fieldName}As")
			select methodInfo).GetEnumerator();
		object[] parameterValues;
		bool valuesAreEnums;
		if (propertyType.IsGenericType)
		{
			IList list = (IList)propertyInfo.GetValue(member, null);
			ConvertToValues(parameterValueString, propertyType, list.Count, dataEntryMode, enumerator, out parameterValues, out valuesAreEnums);
			if (valuesAreEnums)
			{
				for (int i = 0; i < list.Count; i++)
				{
					object[] parameters = new object[2]
					{
						i,
						parameterValues[i]
					};
					enumerator.Current.Invoke(member, parameters);
				}
			}
			else
			{
				for (int j = 0; j < list.Count; j++)
				{
					list[j] = parameterValues[j];
				}
			}
		}
		else
		{
			if (Regex.IsMatch(parameterValueString, "^[0-9]+$"))
			{
				parameterValues = new object[1] { Convert.ChangeType(parameterValueString, propertyType) };
				valuesAreEnums = false;
			}
			else
			{
				ConvertToValues(parameterValueString, propertyType, 1, dataEntryMode, enumerator, out parameterValues, out valuesAreEnums);
			}
			if (valuesAreEnums)
			{
				enumerator.Current.Invoke(member, parameterValues);
			}
			else
			{
				propertyInfo.SetValue(member, parameterValues[0], null);
			}
		}
	}

	private static void ConvertToValues(string parameterValueString, Type fieldType, int fieldCount, DataEntryMode dataEntryMode, IEnumerator<MethodInfo> setMethod, out object[] parameterValues, out bool valuesAreEnums)
	{
		parameterValues = new object[fieldCount];
		while (setMethod.MoveNext())
		{
			string[] array = new string[fieldCount];
			array[0] = parameterValueString;
			ParameterInfo parameterInfo2;
			if (setMethod.Current.Name.EndsWith("Collection"))
			{
				parameterInfo2 = setMethod.Current.GetParameters().Single((ParameterInfo parameterInfo) => !parameterInfo.ParameterType.IsValueType);
				PropertyInfo[] properties = parameterInfo2.ParameterType.GetProperties();
				if (fieldType.IsGenericType)
				{
					Regex.Split(parameterValueString, "(?<![\\s|=])\\s+(?![\\s|=])").CopyTo(array, 0);
				}
				try
				{
					for (int i = 0; i < fieldCount; i++)
					{
						parameterValues[i] = Activator.CreateInstance(parameterInfo2.ParameterType);
						string[] array2 = array[i].Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries);
						foreach (string text in array2)
						{
							string[] maskDetails = text.Split(new char[1] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries);
							PropertyInfo propertyInfo2;
							try
							{
								propertyInfo2 = properties.First((PropertyInfo propertyInfo) => propertyInfo.Name.Equals(maskDetails[0].Trim(), StringComparison.OrdinalIgnoreCase));
							}
							catch (InvalidOperationException)
							{
								propertyInfo2 = properties.First((PropertyInfo propertyInfo) => propertyInfo.Name.Equals(maskDetails[0].Trim().Replace("_", ""), StringComparison.OrdinalIgnoreCase));
							}
							Type propertyType = propertyInfo2.PropertyType;
							if (maskDetails.Length == 2)
							{
								maskDetails[1] = maskDetails[1].Trim();
								if (Regex.IsMatch(maskDetails[1], "^[0-9]+$"))
								{
									propertyInfo2.SetValue(parameterValues[i], Convert.ChangeType(maskDetails[1], propertyType), null);
								}
								else if (Regex.IsMatch(maskDetails[1], "^0x[A-Fa-f0-9]*$", RegexOptions.IgnoreCase))
								{
									MethodInfo method = typeof(Convert).GetMethod("To" + propertyType.Name, new Type[2]
									{
										typeof(string),
										typeof(int)
									});
									propertyInfo2.SetValue(parameterValues[i], method.Invoke(null, new object[2]
									{
										maskDetails[1],
										16
									}), null);
								}
								else
								{
									propertyInfo2.SetValue(parameterValues[i], Enum.Parse(propertyType, maskDetails[1], ignoreCase: true), null);
								}
							}
							else
							{
								Type type = propertyType.Assembly.GetType(propertyType.FullName.Replace("Enum", "Info"));
								MethodInfo method2 = type.GetMethod("ValueTo" + propertyType.Name.Replace("Enum", ""), new Type[1] { typeof(uint) });
								propertyInfo2.SetValue(parameterValues[i], method2.Invoke(null, new object[1] { 1u }), null);
							}
						}
					}
					valuesAreEnums = true;
					return;
				}
				catch (InvalidOperationException)
				{
				}
				continue;
			}
			parameterInfo2 = setMethod.Current.GetParameters().Single((ParameterInfo parameterInfo) => parameterInfo.ParameterType.IsEnum);
			if (fieldType.IsGenericType)
			{
				parameterValueString.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries).CopyTo(array, 0);
			}
			try
			{
				for (int k = 0; k < fieldCount; k++)
				{
					parameterValues[k] = Enum.Parse(parameterInfo2.ParameterType, array[k], ignoreCase: true);
				}
				valuesAreEnums = true;
				return;
			}
			catch (ArgumentException)
			{
			}
		}
		if (Regex.IsMatch(parameterValueString, "^0x[A-Fa-f0-9]*$", RegexOptions.IgnoreCase))
		{
			parameterValueString = parameterValueString.Substring(2);
			switch (dataEntryMode)
			{
			case DataEntryMode.RightAlignedHex:
				parameterValueString = parameterValueString.PadLeft(2 * fieldCount, '0');
				break;
			case DataEntryMode.LeftAlignedHex:
				parameterValueString = parameterValueString.PadLeft(parameterValueString.Length + parameterValueString.Length % 2, '0').PadRight(2 * fieldCount, '0');
				break;
			}
			if (fieldType.IsGenericType)
			{
				MethodInfo method3 = typeof(Convert).GetMethod("To" + fieldType.GetGenericArguments()[0].Name, new Type[2]
				{
					typeof(string),
					typeof(int)
				});
				for (int l = 0; l < fieldCount; l++)
				{
					string text2 = parameterValueString.Substring(2 * l, 2);
					parameterValues[l] = method3.Invoke(null, new object[2] { text2, 16 });
				}
			}
			else
			{
				MethodInfo method3 = typeof(Convert).GetMethod("To" + fieldType.Name, new Type[2]
				{
					typeof(string),
					typeof(int)
				});
				parameterValues[0] = method3.Invoke(null, new object[2] { parameterValueString, 16 });
			}
			valuesAreEnums = false;
			return;
		}
		throw new Exception("Failed to convert parameter string " + parameterValueString);
	}
}
