using System;
using System.Text;
using System.Reflection;

using RobocraftX.Common;
using RobocraftX.SaveAndLoad;
using Svelto.DataStructures;
using Svelto.ECS;
using Svelto.ECS.Serialization;

using GamecraftModdingAPI.Utility;
using HarmonyLib;

namespace GamecraftModdingAPI.Persistence
{
	[HarmonyPatch]
    class SaveGameEnginePatch
    {
		private static readonly byte[] frameStart = Encoding.UTF8.GetBytes("\0\0\0GamecraftModdingAPI\0\0\0");

		public static void Postfix(ref ISerializationData serializationData, EntitiesDB entitiesDB, IEntitySerialization entitySerializer)
		{
			Logging.MetaDebugLog("Running Postfix on SerializeGameToBuffer: serializing custom components...");
			if (SerializerManager.GetSerializersCount() == 0)
			{
				Logging.MetaDebugLog("Skipping component serialization: no serializers registered!");
				return;
			}
			serializationData.data.ExpandBy((uint)frameStart.Length);
			BinaryBufferWriter bbw = new BinaryBufferWriter(serializationData.data.ToArrayFast(out uint buffLen), serializationData.dataPos);
			uint originalPos = serializationData.dataPos;
			Logging.MetaDebugLog($"dataPos: {originalPos}");
            // Add frame start so it's easier to find GamecraftModdingAPI-serialized components
			for (int i = 0; i < frameStart.Length; i++)
			{
				bbw.Write(frameStart[i]);
			}
			Logging.MetaDebugLog($"dataPos (after frame start): {bbw.Position}");
			serializationData.data.ExpandBy(4u);
			bbw.Write((uint)SerializerManager.GetSerializersCount());
			string[] serializerKeys = SerializerManager.GetSerializerNames();
			for (uint c = 0; c < serializerKeys.Length; c++)
			{
				Logging.MetaDebugLog($"dataPos (loop start): {bbw.Position}");
				// write component info
				serializationData.data.ExpandBy(4u + (uint)serializerKeys[c].Length);
				bbw.Write((uint)serializerKeys[c].Length);
				Logging.MetaDebugLog($"dataPos (now): {bbw.Position}");
				byte[] nameBytes = Encoding.UTF8.GetBytes(serializerKeys[c]);
				for (int i = 0; i < nameBytes.Length; i++)
				{
					bbw.Write(nameBytes[i]);
				}
				Logging.MetaDebugLog($"dataPos (now): {bbw.Position}");
				serializationData.data.ExpandBy(4u);
				serializationData.dataPos = bbw.Position + 4u;
				Logging.MetaDebugLog($"dataPos (now): {bbw.Position}");
				Logging.MetaDebugLog($"dataPos (appears to be): {serializationData.dataPos}");
				// serialize component
				IEntitySerializer serializer = SerializerManager.GetSerializer(serializerKeys[c]);
				if (!serializer.Serialize(ref serializationData, entitiesDB, entitySerializer))
				{
					Logging.MetaDebugLog("Component serialization failed!");
				}
				Logging.MetaDebugLog($"dataPos (now): {bbw.Position}");
				bbw.Write((uint)serializationData.dataPos);
				Logging.MetaDebugLog($"dataPos (now): {bbw.Position}");
				bbw = new BinaryBufferWriter(serializationData.data.ToArrayFast(out buffLen), serializationData.dataPos);
				Logging.MetaDebugLog($"dataPos (loop end): {bbw.Position}");
			}
			serializationData.data.Trim();
			Logging.MetaDebugLog($"dataPos (end): {bbw.Position}");
			Logging.MetaDebugLog("Serialization complete");
		}

        public static MethodBase TargetMethod()
		{
			return typeof(SaveGameEngine).GetMethod("SerializeGameToBuffer");
		}
    }
}