using GadgetCore;
using GadgetCore.API;
using HarmonyLib;
using System;
using System.Reflection;
using UnityEngine;

namespace CombatChipChest.Patches
{

  [HarmonyPatch(typeof(GameScript))]
  [HarmonyPatch("Update")]
  [HarmonyGadget("CombatChipChest")]
  public static class Patch_GameScript_Update
  {
    [HarmonyPrefix]
    public static void Prefix(GameScript __instance, ref Item ___holdingItem, ref int ___curhoveringstat, ref bool ___holdingCombatChip, bool ___exitingcombatmode)
    {
      try
      {
        if (MenuScript.player)
        {
          if (GameScript.inventoryOpen)
          {
            var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 5f))
            {
              if (hit.transform.gameObject.name.StartsWith("combat_storage_slot"))
              {
                var slot = int.Parse(hit.transform.gameObject.name.Substring("combat_storage_slot".Length));
                HoverCombatChipChest(__instance, slot, ref ___curhoveringstat);
              }
            }
          }
          if (!GameScript.pausing && Input.GetMouseButtonDown(0) && GameScript.inventoryOpen)
          {
            var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, 7f))
            {
              if (hit.transform.gameObject.name.StartsWith("combat_storage_slot"))
              {
                var slot = int.Parse(hit.transform.gameObject.name.Substring("combat_storage_slot".Length));
                if (slot >= 0 && slot < 16)
                {
                  if (___holdingItem.id != 0)
                  {
                    if (Core.combatChipStore.ChipIDs[slot] != ___holdingItem.id)
                    {
                      if (Core.combatChipStore.ChipIDs[slot] == 0)
                      {
                        Place(__instance, slot, ref ___holdingItem, ref ___holdingCombatChip);
                      }
                      else
                      {
                        Swap(__instance, slot, ref ___holdingItem);
                      }
                    }
                  }
                  else if (Core.combatChipStore.ChipIDs[slot] != 0)
                  {
                    Select(__instance, slot, ref ___holdingItem, ref ___holdingCombatChip, ___exitingcombatmode);
                  }
                }
              }
            }
          }
        }
      }
      catch (Exception e) { Core.logger.LogConsole(e.Message); }
    }

    public static void HoverCombatChipChest(GameScript __instance, int slot, ref int ___curhoveringstat)
    {
      try
      {
        if (slot >= 0 && slot < 16)
        {

          if (slot != ___curhoveringstat)
          {
            ___curhoveringstat = slot;
            if (Core.combatChipStore.ChipIDs[slot] != 0)
            {
              __instance.GetComponent<AudioSource>().PlayOneShot((AudioClip)Resources.Load("Au/hover"), Menuu.soundLevel / 10f);
            }
          }
          Core.combatChipStore.UpdateText(Core.combatChipStore.ChipIDs[slot]);
        }
      }
      catch { }
    }

    private static void Swap(GameScript __instance, int slot, ref Item ___holdingItem)
    {
      try
      {
        if (slot >= 0 && slot < 16)
        {
          if (slot >= 0 && slot < 16)
          {
            __instance.GetComponent<AudioSource>().PlayOneShot((AudioClip)Resources.Load("Au/CLICK1"), Menuu.soundLevel / 10f);
            int id = ___holdingItem.id;

            ___holdingItem.id = Core.combatChipStore.ChipIDs[slot];

            Core.combatChipStore.ChipIDs[slot] = id;

            __instance.RefreshCombatChipMenu();
            __instance.RefreshHoldingSlot();

            Core.combatChipStore.UpdateLatestUI();

            __instance.UpdateHP();
            __instance.UpdateMana();
          }
        }
      }
      catch (Exception e) { Core.logger.LogConsole(e.Message); }
    }

    private static void Select(GameScript __instance, int slot, ref Item ___holdingItem, ref bool ___holdingCombatChip, bool ___exitingcombatmode)
    {
      try
      {
        if (slot >= 0 && slot < 16)
        {
          if (!___exitingcombatmode)
          {
            __instance.GetComponent<AudioSource>().PlayOneShot((AudioClip)Resources.Load("Au/CLICK1"), Menuu.soundLevel / 10f);
            
            ___holdingItem = __instance.EmptyItem();

            ___holdingCombatChip = true;
            
            ___holdingItem.id = Core.combatChipStore.ChipIDs[slot];
            
            Core.combatChipStore.ChipIDs[slot] = 0;
            
            __instance.RefreshCombatChipMenu();
            __instance.RefreshHoldingSlot();
            
            Core.combatChipStore.UpdateLatestUI();
            
            __instance.UpdateHP();
            __instance.UpdateMana();
          }
        }
      }
      catch (Exception e) { Core.logger.LogConsole(e.Message); }
    }

    private static void Place(GameScript __instance, int slot, ref Item ___holdingItem, ref bool ___holdingCombatChip)
    {
      try
      {
        if (slot >= 0 && slot < 16)
        {
          __instance.GetComponent<AudioSource>().PlayOneShot((AudioClip)Resources.Load("Au/CLICK1"), Menuu.soundLevel / 10f);

          Core.combatChipStore.ChipIDs[slot] = ___holdingItem.id;

          ___holdingItem = __instance.EmptyItem();
          __instance.RefreshCombatChipMenu();
          ___holdingCombatChip = false;
          __instance.RefreshHoldingSlot();
          Core.combatChipStore.UpdateLatestUI();

          __instance.UpdateHP();
          __instance.UpdateMana();
        }
      }
      catch (Exception e) { Core.logger.LogConsole(e.Message); }
    }

    private static void set(GameScript __instance, string prop, object o)
    {
      var field = typeof(GameScript).GetField(prop, BindingFlags.NonPublic | BindingFlags.Instance);
      field.SetValue(__instance, o);
    }

    private static T get<T>(GameScript __instance, string prop)
    {
      var field = typeof(GameScript).GetField(prop, BindingFlags.NonPublic | BindingFlags.Instance);
      return (T)field.GetValue(__instance);
    }

    private static object call(GameScript __instance, string meth, object[] o = null)
    {
      MethodInfo dynMethod = __instance.GetType().GetMethod(meth, BindingFlags.NonPublic | BindingFlags.Instance);
      return dynMethod.Invoke(__instance, o ?? new object[0]);
    }
  }
}