using System;
using System.Linq;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using HarmonyLib.Tools;
using static TavernData;

namespace BlacksmithMaster {
    [BepInPlugin(PluginGuid, PluginName, PluginVersion)]
    public class Main : BaseUnityPlugin {
        private const string PluginGuid = "Cykasmith";
        private const string PluginName = "Cykasmith";
        private const string PluginVersion = "1.0.0";

        public static ConfigEntry<bool> debug;
        public static ConfigEntry<bool> debugXp;
        public static ConfigEntry<bool> debugMoney;
        public static ConfigEntry<bool> debugResearch;
        public static ConfigEntry<bool> debugSalary;
        public static ConfigEntry<bool> debugCustomers;
        public static ConfigEntry<bool> debugDecorations;
        public static ConfigEntry<bool> debugSpeed;
        public static ConfigEntry<bool> debugHiring;
        // public static ConfigEntry<bool> debugMining;

        public static ConfigEntry<float> xpMultiplier;
        public static ConfigEntry<float> moneyMultiplier;
        public static ConfigEntry<float> researchMultiplier;
        public static ConfigEntry<float> salaryMultiplier;
        public static ConfigEntry<float> dailyCustomerMultiplier;
        public static ConfigEntry<float> dailyCustomerOffset;
        public static ConfigEntry<float> decorationAdditionMultiplier;
        public static ConfigEntry<float> decorationAdditionOffset;
        public static ConfigEntry<float> globalSpeedMultiplier;
        public static ConfigEntry<float> globalSpeedOffset;
        public static ConfigEntry<float> hiringCostMultiplier;
        // public static ConfigEntry<float> miningMultiplier;
        public static ConfigEntry<bool> alwaysEvenly;
        public static ConfigEntry<bool> alwaysChad;

        public void Awake() {
            debug = Config.Bind("Debug", "Global Debug", false);
            debugXp = Config.Bind("Debug", "XP Debug", false);
            debugMoney = Config.Bind("Debug", "Money Debug", false);
            debugResearch = Config.Bind("Debug", "Research Debug", false);
            debugSalary = Config.Bind("Debug", "Salary Debug", false);
            debugCustomers = Config.Bind("Debug", "Customers Debug", false);
            debugDecorations = Config.Bind("Debug", "Decorations Debug", false);
            debugSpeed = Config.Bind("Debug", "Speed Debug", false);
            debugHiring = Config.Bind("Debug", "Hiring Debug", false);
            // debugMining = Config.Bind("Debug", "Mining Debug", false);

            xpMultiplier =
                Config.Bind("General", "XP Multiplier", 1f,
                            new ConfigDescription("XP Multiplier", new AcceptableValueRange<float>(0.01f, 1024f)));
            moneyMultiplier =
                Config.Bind("General", "Money Multiplier", 1f,
                            new ConfigDescription("Money Multiplier", new AcceptableValueRange<float>(0.01f, 1024f)));
            researchMultiplier = Config.Bind(
                "General", "Research Multiplier", 1f,
                new ConfigDescription("Research Multiplier", new AcceptableValueRange<float>(0.01f, 1024f)));
            salaryMultiplier =
                Config.Bind("General", "Salary Multiplier", 1f,
                            new ConfigDescription("Salary Multiplier", new AcceptableValueRange<float>(0.01f, 1024f)));
            dailyCustomerMultiplier = Config.Bind(
                "General", "Daily Customer Multiplier", 1f,
                new ConfigDescription("Daily Customer Multiplier", new AcceptableValueRange<float>(0.01f, 1024f)));
            dailyCustomerOffset = Config.Bind(
                "General", "Daily Customer Offset", 0f,
                new ConfigDescription("Daily Customer Offset", new AcceptableValueRange<float>(-1024f, 1024f)));
            decorationAdditionMultiplier = Config.Bind(
                "General", "Decoration Addition Multiplier", 1f,
                new ConfigDescription("Decoration Addition Multiplier", new AcceptableValueRange<float>(0.01f, 1024f)));
            decorationAdditionOffset = Config.Bind(
                "General", "Decoration Addition Offset", 0f,
                new ConfigDescription("Decoration Addition Offset", new AcceptableValueRange<float>(-1024f, 1024f)));
            globalSpeedMultiplier = Config.Bind(
                "General", "Global Speed Multiplier", 1f,
                new ConfigDescription("Global Speed Multiplier", new AcceptableValueRange<float>(0.01f, 1024f)));
            globalSpeedOffset = Config.Bind(
                "General", "Global Speed Offset", 0f,
                new ConfigDescription("Global Speed Offset", new AcceptableValueRange<float>(-1024f, 1024f)));
            hiringCostMultiplier = Config.Bind(
                "General", "Hiring Cost Multiplier", 1f,
                new ConfigDescription("Hiring Cost Multiplier", new AcceptableValueRange<float>(0.01f, 1024f)));
            // miningMultiplier =
            //     Config.Bind("General", "Mining Multiplier", 1f,
            //                 new ConfigDescription("Mining Multiplier", new AcceptableValueRange<float>(0.01f, 1024f)));
            alwaysEvenly =
                Config.Bind("General", "Always Evenly", false,
                            new ConfigDescription("Always Evenly", new AcceptableValueRange<bool>(false, true)));
            alwaysChad = Config.Bind("General", "Always Chad", false,
                                     new ConfigDescription("Always Chad", new AcceptableValueRange<bool>(false, true)));

            Logger.LogInfo("Cykasmith loaded");
            HarmonyFileLog.Enabled = true;
            Harmony harmony = new Harmony(PluginGuid);
            harmony.PatchAll();
            var originalMethods = harmony.GetPatchedMethods();
            Logger.LogInfo("Patched " + originalMethods.Count() + " methods");
        }

        public static void LogDebug(string message, ConfigEntry<bool> debugFlag = null) {
            if (debug.Value || (debugFlag != null && debugFlag.Value))
                Console.WriteLine(message);
        }
    }

    [HarmonyPatch(typeof(StaffBase), "AddXp")]
    public class TavernData_AddXp {
        public static void Prefix(ref int amount) {
            Main.LogDebug("Original XP amount: " + amount, Main.debugXp);
            amount = (int)((float)amount * Main.xpMultiplier.Value);
            Main.LogDebug("Modified XP amount: " + amount, Main.debugXp);
        }
    }

    [HarmonyPatch(typeof(TavernModel), "ChangeMoney")]
    public class TavernModel_ChangeMoney {
        public static void Prefix(ref int value) {
            Main.LogDebug("Original money amount: " + value, Main.debugMoney);
            if (value > 0)
                value = (int)((float)value * Main.moneyMultiplier.Value);
            Main.LogDebug("Modified money amount: " + value, Main.debugMoney);
        }
    }

    [HarmonyPatch(typeof(ResourcesModel), "ChangeResearchPoints")]
    public class ResourcesModel_ChangeResearchPoints {
        public static void Prefix(ref int value) {
            Main.LogDebug("Original research amount: " + value, Main.debugResearch);
            if (value > 0)
                value = (int)((float)value * Main.researchMultiplier.Value);
            Main.LogDebug("Modified research amount: " + value, Main.debugResearch);
        }
    }

    [HarmonyPatch(typeof(StaffInfo), "Salary", MethodType.Getter)]
    public class StaffInfo_GetSalary {
        public static void Postfix(ref int __result) {
            Main.LogDebug("Original salary: " + __result, Main.debugSalary);
            __result = (int)((float)__result * Main.salaryMultiplier.Value);
            Main.LogDebug("Modified salary: " + __result, Main.debugSalary);
        }
    }

    [HarmonyPatch(typeof(TavernModel), "GetNumberOfCustomersPerDay")]
    public class TavernModel_GetNumberOfCustomersPerDay {
        public static void Postfix(ref int __result) {
            Main.LogDebug("Original number of customers per day: " + __result, Main.debugCustomers);
            __result = (int)(__result * Main.dailyCustomerMultiplier.Value + Main.dailyCustomerOffset.Value);
            Main.LogDebug("Modified number of customers per day: " + __result, Main.debugCustomers);
        }
    }

    [HarmonyPatch(typeof(TavernModel), "GetBonusPercentageFromDecorations")]
    public class TavernModel_GetBonusPercentageFromDecorations {
        public static void Postfix(ref int __result) {
            Main.LogDebug("Original bonus percentage from decorations: " + __result, Main.debugDecorations);
            __result = (int)(__result * Main.decorationAdditionMultiplier.Value + Main.decorationAdditionOffset.Value);
            Main.LogDebug("Modified bonus percentage from decorations: " + __result, Main.debugDecorations);
        }
    }

    [HarmonyPatch(typeof(Economy), "GetWalkingSpeed")]
    public class Economy_GetWalkingSpeed {
        public static void Postfix(ref float __result) {
            Main.LogDebug("Original walking speed: " + __result, Main.debugSpeed);
            __result = __result * Main.globalSpeedMultiplier.Value + Main.globalSpeedOffset.Value;
            Main.LogDebug("Modified walking speed: " + __result, Main.debugSpeed);
        }
    }

    [HarmonyPatch(typeof(StaffModel), "GetCostToHire")]
    public class StaffModel_GetCostToHire {
        public static void Postfix(ref int __result) {
            Main.LogDebug("Original hiring cost: " + __result, Main.debugHiring);
            __result = (int)(__result * Main.hiringCostMultiplier.Value);
            Main.LogDebug("Modified hiring cost: " + __result, Main.debugHiring);
        }
    }

    [HarmonyPatch(typeof(StaffUtil), "FillBasicInfo")]
    public class StaffUtil_FillBasicInfo {
        public static void Postfix(TavernData.StaffType staffType, Random rnd, ref TavernData.StaffInfo newPerson) {
            Main.LogDebug("Setting skill assignment strategy to evenly", Main.debug);
            if (Main.alwaysEvenly.Value)
                newPerson.SkillAssignmentStrategy = TavernData.SkillAssignmentStrategyType.Balanced;
        }
    }

    [HarmonyPatch(typeof(HireData), "GetStaffInfo")]
    public class TavernData_GetStaffInfo {
        public static void Prefix(Random rnd, int id, string staffName, bool isMale, ref bool shouldBeSuperWorker,
                                  ref EliteTraitType forcedEliteTrait) {
            Main.LogDebug("Setting shouldBeSuperWorker to true", Main.debug);
            if (Main.alwaysChad.Value)
                shouldBeSuperWorker = true;
        }
    }

    // Does not work, I don't know why...
    // [HarmonyPatch(typeof(MineBoxController), "AddMineralPiece")]
    // public class MineBoxController_AddMineralPiece {
    //     private static int before;
    //     public static void Prefix(ref MineBoxController __instance) {
    //         var trav = Traverse.Create(__instance);
    //         var piecesInsideAmount = trav.Field("PiecesInsideAmount");
    //         Main.LogDebug("Original pieces: " + piecesInsideAmount.GetValue<int>(), Main.debugMining);
    //         before = piecesInsideAmount.GetValue<int>();
    //     }

    //     public static void Postfix(ref MineBoxController __instance) {
    //         var trav = Traverse.Create(__instance);
    //         var piecesInsideAmount = trav.Field("PiecesInsideAmount");
    //         Main.LogDebug("Original pieces: " + piecesInsideAmount.GetValue<int>(), Main.debugMining);
    //         var delta = piecesInsideAmount.GetValue<int>() - before;
    //         piecesInsideAmount.SetValue(before + (int)(delta * Main.miningMultiplier.Value));
    //         Main.LogDebug("Modified pieces: " + piecesInsideAmount.GetValue<int>(), Main.debugMining);
    //     }
    // }
}
