using System;
using System.Collections.Generic;
using HarmonyLib;

namespace TerraTech {
    [HarmonyPatch]
    public class ThrusterPropertiesManager {
        private static Dictionary<ModuleBooster, Dictionary<BoosterJet, float>> boosters = new Dictionary<ModuleBooster, Dictionary<BoosterJet, float>>();

        [HarmonyPrefix]
        [HarmonyPatch(typeof(ModuleBooster), "OnAttached")]
        static void PostfixCreate(ModuleBooster __instance) {
            // Console.WriteLine("ModuleBooster.OnAttached");
            if (!boosters.ContainsKey(__instance)) {
                boosters.Add(__instance, Map(__instance));
                // Console.WriteLine("Patching {0}; force: {1}", __instance.name, GetForceAsString(__instance));
                DoPatchSingle(__instance);
                // Console.WriteLine("Patched {0}; force: {1}", __instance.name, GetForceAsString(__instance));
            }
        }

        [HarmonyPrefix]
        [HarmonyPatch(typeof(ModuleBooster), "OnDetaching")]
        static void PostfixDestroy(ModuleBooster __instance) {
            // Console.WriteLine("ModuleBooster.OnDetaching");
            // Console.WriteLine("Restoring {0}; force: {1}", __instance.name, GetForceAsString(__instance));
            DoRestoreSingle(__instance);
            // Console.WriteLine("Restored {0}; force: {1}", __instance.name, GetForceAsString(__instance));
            boosters.Remove(__instance);
        }

        public static void DoPatch() {
            // Console.WriteLine("Modifying {0} ModuleBooster", boosters.Count);
            foreach (KeyValuePair<ModuleBooster, Dictionary<BoosterJet, float>> keyValuePair in boosters) {
                DoRestoreSingle(keyValuePair.Key);
                DoPatchSingle(keyValuePair.Key);
            }
        }

        static void DoPatchSingle(ModuleBooster moduleBooster) {
            List<BoosterJet> jets = GetValue(moduleBooster);
            for (var i = 0; i < jets.Count; i++) {
                boosters[moduleBooster][jets[i]] = GetValue(jets[i]);
                SetValue(jets[i], GetValue(jets[i]) * Main.jetThrustMultiplier.Value);
            }
            SetValue(moduleBooster, jets);
        }

        static void DoRestoreSingle(ModuleBooster moduleBooster) {
            if (boosters.ContainsKey(moduleBooster)) {
                foreach (BoosterJet boosterJet in GetValue(moduleBooster)) {
                    SetValue(boosterJet, boosters[moduleBooster][boosterJet]);
                }
            }
        }

        private static Dictionary<BoosterJet, float> Map(ModuleBooster moduleBooster) {
            Dictionary<BoosterJet, float> jets = new Dictionary<BoosterJet, float>();
            foreach (BoosterJet boosterJet in GetValue(moduleBooster)) {
                jets.Add(boosterJet, GetValue(boosterJet));
            }
            return jets;
        }

        private static List<BoosterJet> GetValue(ModuleBooster moduleBooster) {
            return Traverse.Create(moduleBooster).Field("jets").GetValue() as List<BoosterJet>;
        }

        private static void SetValue(ModuleBooster moduleBooster, List<BoosterJet> value) {
            Traverse.Create(moduleBooster).Field("jets").SetValue(value);
        }

        private static float GetValue(BoosterJet boosterJet) {
            return Traverse.Create(boosterJet).Field("m_Force").GetValue() as float? ?? 0f;
        }

        private static void SetValue(BoosterJet boosterJet, float value) {
            Traverse.Create(boosterJet).Field("m_Force").SetValue(value);
        }
        
        private static string GetForceAsString(ModuleBooster moduleBooster) {
            string result = "";
            foreach (BoosterJet boosterJet in GetValue(moduleBooster)) {
                result += GetValue(boosterJet) + ", ";
            }
            return result;
        }
    }
}