using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Comfort.Common;
using EFT;
using EFT.InventoryLogic;
using UnityEngine;

public class ItemFactory
{
	public class ContainerCollection
	{
		private static Type _containerCollectionType;

		private static PropertyInfo _containersProperty;

		private static MethodInfo _getContainerMethod;

		private static MethodInfo _tryFindItemMethod;

		public IEnumerable<IContainer> Containers
		{
			get
			{
				if (_containersProperty != null)
				{
					return (IEnumerable<IContainer>)_containersProperty.GetValue(this);
				}
				return null;
			}
		}

		static ContainerCollection()
		{
			LoadContainerCollectionType();
		}

		private static void LoadContainerCollectionType()
		{
			Assembly assembly = Assembly.Load("Assembly-CSharp");
			if (assembly == null)
			{
				Log("Log: Failed to load Assembly-CSharp.");
				return;
			}
			Type[] types = assembly.GetTypes();
			foreach (Type type in types)
			{
				if (type.Name == "\uecea")
				{
					_containerCollectionType = type;
					break;
				}
			}
			if (!(_containerCollectionType == null))
			{
				_containersProperty = _containerCollectionType.GetProperty("Containers", BindingFlags.Instance | BindingFlags.Public);
				_getContainerMethod = _containerCollectionType.GetMethod("GetContainer", BindingFlags.Instance | BindingFlags.Public);
				_tryFindItemMethod = _containerCollectionType.GetMethod("TryFindItem", BindingFlags.Instance | BindingFlags.Public);
			}
		}

		public IContainer GetContainer(string containerId)
		{
			if (_getContainerMethod != null)
			{
				return (IContainer)_getContainerMethod.Invoke(this, new object[1] { containerId });
			}
			return null;
		}

		public bool TryFindItem(string itemId, out Item item)
		{
			item = null;
			if (_tryFindItemMethod != null)
			{
				object[] array = new object[2] { itemId, null };
				bool result = (bool)_tryFindItemMethod.Invoke(this, array);
				item = (Item)array[1];
				return result;
			}
			return false;
		}

		public static void Log(string message)
		{
			using StreamWriter streamWriter = new StreamWriter(Path.Combine(Application.persistentDataPath, "log.txt"), append: true);
			streamWriter.WriteLine($"{DateTime.Now}: {message}");
		}
	}

	public class GridHelper
	{
		public LocationInGrid FindFreeSpace(Item item, dynamic grid)
		{
			_E374 obj = item.CalculateCellSize();
			int x = obj.X;
			int y = obj.Y;
			int num = grid.GridWidth;
			int num2 = grid.GridHeight;
			dynamic val = grid.ItemCollection;
			dynamic occupiedSpaces = GetOccupiedSpaces(val);
			LocationInGrid locationInGrid = TryFindLocation(x, y, num, num2, occupiedSpaces);
			if (locationInGrid == null && x != y)
			{
				locationInGrid = TryFindLocation(y, x, num, num2, occupiedSpaces);
			}
			if (locationInGrid == null)
			{
				locationInGrid = HandleStretching(x, y, grid, num, num2);
			}
			return locationInGrid;
		}

		private Dictionary<(int, int), bool> GetOccupiedSpaces(dynamic itemCollection)
		{
			Dictionary<(int, int), bool> dictionary = new Dictionary<(int, int), bool>();
			foreach (dynamic item in itemCollection.Values)
			{
				dynamic val = item.Position;
				dynamic val2 = item.CalculateCellSize();
				int num = val2.X;
				int num2 = val2.Y;
				for (int i = val.X; i < val.X + num; i++)
				{
					for (int j = val.Y; j < val.Y + num2; j++)
					{
						dictionary[(i, j)] = true;
					}
				}
			}
			return dictionary;
		}

		private LocationInGrid TryFindLocation(int itemWidth, int itemHeight, int gridWidth, int gridHeight, Dictionary<(int, int), bool> occupiedSpaces)
		{
			for (int i = 0; i <= gridWidth - itemWidth; i++)
			{
				for (int j = 0; j <= gridHeight - itemHeight; j++)
				{
					if (IsSpaceAvailable(i, j, itemWidth, itemHeight, occupiedSpaces))
					{
						return new LocationInGrid(i, j, ItemRotation.Horizontal);
					}
				}
			}
			return null;
		}

		private bool IsSpaceAvailable(int startX, int startY, int itemWidth, int itemHeight, Dictionary<(int, int), bool> occupiedSpaces)
		{
			for (int i = startX; i < startX + itemWidth; i++)
			{
				for (int j = startY; j < startY + itemHeight; j++)
				{
					if (occupiedSpaces.ContainsKey((i, j)))
					{
						return false;
					}
				}
			}
			return true;
		}

		private LocationInGrid HandleStretching(int itemWidth, int itemHeight, dynamic grid, int gridWidth, int gridHeight)
		{
			if (grid.CanStretchHorizontally && gridHeight >= gridWidth + itemWidth)
			{
				return new LocationInGrid(gridWidth, 0, ItemRotation.Horizontal);
			}
			if (grid.CanStretchVertically && (itemWidth <= gridWidth || grid.CanStretchHorizontally))
			{
				return new LocationInGrid(0, gridHeight, ItemRotation.Vertical);
			}
			return null;
		}
	}

	private static string _logFilePath;

	private static Type _itemFactoryType;

	private static MethodInfo _createItemMethod;

	private static object _singletonInstance;

	static ItemFactory()
	{
		LoadItemFactoryType();
	}

	private static void LoadItemFactoryType()
	{
		Assembly assembly = Assembly.Load("Assembly-CSharp");
		if (assembly == null)
		{
			return;
		}
		Type[] types = assembly.GetTypes();
		foreach (Type type in types)
		{
			_createItemMethod = type.GetMethod("CreateItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (_createItemMethod != null)
			{
				_itemFactoryType = type;
				break;
			}
		}
		if (!(_itemFactoryType == null))
		{
			PropertyInfo property = typeof(Singleton<>).MakeGenericType(_itemFactoryType).GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);
			if (property != null)
			{
				_singletonInstance = property.GetValue(null);
			}
		}
	}

	public Item CreateItem(string id)
	{
		if (_createItemMethod == null || _singletonInstance == null)
		{
			return null;
		}
		string text = MongoID.Generate();
		object[] parameters = new object[3] { text, id, null };
		object obj = _createItemMethod.Invoke(_singletonInstance, parameters);
		if (obj != null)
		{
			return (Item)obj;
		}
		return null;
	}

	public Item CreateItemWithParent(string itemId, string parentId)
	{
		if (_createItemMethod == null || _singletonInstance == null)
		{
			return null;
		}
		string text = ((!string.IsNullOrEmpty(parentId)) ? parentId : ((string)MongoID.Generate()));
		object[] parameters = new object[3] { text, itemId, null };
		object obj = _createItemMethod.Invoke(_singletonInstance, parameters);
		if (obj != null)
		{
			return (Item)obj;
		}
		return null;
	}

	public static void Log(string message)
	{
		_logFilePath = Path.Combine(Application.persistentDataPath, "log.txt");
		using StreamWriter streamWriter = new StreamWriter(_logFilePath, append: true);
		streamWriter.WriteLine($"{DateTime.Now}: {message}");
	}
}
