using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Text.Formatting;
using GamecraftModdingAPI.Blocks;
using GamecraftModdingAPI.Engines;
using GamecraftModdingAPI.Players;
using HarmonyLib;
using RobocraftX.GUI.Debug;
using Svelto.ECS;
using Svelto.ECS.Experimental;

namespace GamecraftModdingAPI.Utility
{
    public class DebugInterfaceEngine : IApiEngine
    {
        private static Dictionary<string, Func<string>> _extraInfo=new Dictionary<string, Func<string>>();
        public void Ready()
        {
        }

        public EntitiesDB entitiesDB { get; set; }

        public void Dispose()
        {
        }

        public void SetInfo(string id, Func<string> contentGetter) => _extraInfo[id] = contentGetter;
        public bool RemoveInfo(string id) => _extraInfo.Remove(id);

        public string Name { get; } = "GamecraftModdingAPIDebugInterfaceGameEngine";
        public bool isRemovable { get; } = true;

        [HarmonyPatch]
        private class Patch
        {
            public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
            {
                var list = new List<CodeInstruction>(instructions);
                try
                {
                    //Before setting the text from the StringBuffer
                    int index = list.FindLastIndex(inst => inst.opcode == OpCodes.Ldfld);
                    var array = new CodeInstruction[]
                    {
                        new CodeInstruction(OpCodes.Ldloc_0), //StringBuffer
                        new CodeInstruction(OpCodes.Call, ((Action<StringBuilder>)AddInfo).Method)
                    };
                    list.InsertRange(index - 1, array); //-1: ldloc.1 ("local") before ldfld
                }
                catch (Exception e)
                {
                    Logging.LogWarning("Failed to inject AddInfo method for the debug display!\n" + e);
                }

                return list;
            }

            public static void AddInfo(StringBuilder sb)
            {
                foreach (var info in _extraInfo)
                {
                    try
                    {
                        string text = info.Value().Trim();
                        if (text.Length != 0)
                            sb.Append(text + "\n");
                    }
                    catch (Exception e)
                    {
                        Logging.LogWarning("Unable to get info for " + info.Key + "\n" + e);
                    }
                }
            }

            public static MethodInfo TargetMethod()
            {
                return AccessTools.Method("RobocraftX.GUI.Debug.DebugDisplayEngine:UpdateDisplay");
            }
        }
    }
}