using GadgetCore;
using GadgetCore.API;
using HarmonyLib;
using QuickStack.ConfigEnums;
using System;
using System.Collections;
using System.Reflection;
using UnityEngine;

namespace QuickStack.Patches
{

  [HarmonyPatch(typeof(GameScript))]
  [HarmonyPatch("Update")]
  [HarmonyGadget("QuickStack")]
  public static class Patch_GameScript_Update
  {
    [HarmonyPrefix]
    public static void Prefix(GameScript __instance, Item[] ___inventory, ref Item[] ___storage, int ___storageLevel, int ___curStoragePage)
    {
      try
      {
        if (MenuScript.player)
        {
          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("button_quick_stack"))
              {
                for (int slot = 0; slot < 36; slot++)
                {
                  bool updateSlot = false;
                  int startPage = Core.settingStackRange == StackRangeEnum.OpenPage ? ___curStoragePage : 0;
                  int endPage = Core.settingStackRange == StackRangeEnum.OpenPage ? ___curStoragePage + 1 : ___storageLevel + 1;
                  for (int page = startPage; page < endPage; page++)
                  {
                    bool contains = false;
                    Item item = ___inventory[slot];
                    for (int slotPage = 0; slotPage < 30; slotPage++)
                      if (___storage[page * 30 + slotPage].id == item.id)
                        contains = true;

                    bool potion = item.id >= 60 && item.id <= 73;
                    bool shouldTake = true;
                    if (potion)
                    {
                      if (slot < 6 && Core.settingStackPotionsSource == StackSourceInventoryPotionsEnum.OnlyMainInventory || Core.settingStackPotionsSource == StackSourceInventoryPotionsEnum.None)
                        shouldTake = false;
                      if (slot > 6 && Core.settingStackPotionsSource == StackSourceInventoryPotionsEnum.OnlyToolbar || Core.settingStackPotionsSource == StackSourceInventoryPotionsEnum.None)
                        shouldTake = false;
                    }
                    else
                    {
                      if (slot < 6 && Core.settingStackSource == StackSourceInventoryEnum.OnlyMainInventory)
                        shouldTake = false;
                      if (slot > 6 && Core.settingStackSource == StackSourceInventoryEnum.OnlyToolbar)
                        shouldTake = false;
                    }

                    if ((contains || Core.settingStackMode == ConfigEnums.StackModeEnum.FillPageAll) && shouldTake)
                    {
                      ItemInfo slotInfo = ItemRegistry.Singleton.GetEntry(item.id);
                      ItemType slotItemType = slotInfo != null ? (slotInfo.Type & (ItemType.EQUIP_MASK | ItemType.TYPE_MASK)) : ItemRegistry.GetDefaultTypeByID(item.id);
                      if ((slotItemType & ItemType.NONSTACKING) == ItemType.STACKING)
                      {
                        for (int slotPage = 0; slotPage < 30; slotPage++)
                          if (GadgetCoreAPI.CanItemsStack(___storage[page * 30 + slotPage], item))
                          {
                            while (___storage[page * 30 + slotPage].q < 9999 && item.q > 0)
                            {
                              ___storage[page * 30 + slotPage].q++;
                              item.q--;
                              updateSlot = true;
                            }
                          }
                        if (item.q == 0)
                          ___inventory[slot] = new Item(0, 0, 0, 0, 0, new int[3], new int[3]);
                        else if (Core.settingStackMode != ConfigEnums.StackModeEnum.StackingOnly)
                        {
                          for (int slotPage = 0; slotPage < 30; slotPage++)
                            if (___storage[page * 30 + slotPage].id == 0)
                            {
                              ___storage[page * 30 + slotPage] = item;
                              ___inventory[slot] = new Item(0, 0, 0, 0, 0, new int[3], new int[3]);
                              updateSlot = true;
                              break;
                            }
                        }
                      }
                      else if (Core.settingStackMode != ConfigEnums.StackModeEnum.StackingOnly)
                      {
                        for (int slotPage = 0; slotPage < 30; slotPage++)
                          if (___storage[page * 30 + slotPage].id == 0)
                          {
                            ___storage[page * 30 + slotPage] = item;
                            ___inventory[slot] = new Item(0, 0, 0, 0, 0, new int[3], new int[3]);
                            updateSlot = true;
                            break;
                          }
                      }
                    }
                  }

                  if (updateSlot)
                    typeof(GameScript).GetMethod("RefreshSlot", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { slot });
                }
                __instance.GetComponent<AudioSource>().PlayOneShot((AudioClip)Resources.Load("Au/CLICK3"), Menuu.soundLevel / 10f);
                __instance.StartCoroutine((IEnumerator)typeof(GameScript).GetMethod("RefreshStoragePage", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { ___curStoragePage }));
              }
            }
          }
        }
      }
      catch (Exception e) { Core.logger.LogConsole(e.Message); }
    }
  }
}