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

namespace RecipeMenuCore.Patches
{
  [HarmonyPatch(typeof(GameScript))]
  [HarmonyPatch("Update")]
  [HarmonyGadget("RecipeMenuCore")]
  public static class Patch_GameScript_Update
  {
    [HarmonyPrefix]
    public static bool Prefix(GameScript __instance, int ___craftType, int ___curRecipePage, Item[] ___inventory, Item[] ___craft)
    {
      bool acted = false;
      if (MenuScript.player)
      {
        if (!GameScript.pausing)
        {
          if (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.layer == 16)
              {
                if (hit.transform.gameObject.tag == "recipe")
                {
                  var slotID = int.Parse(hit.transform.gameObject.name);
                  MonoBehaviour.print("hit recipe");
                  if (___craftType == 0 && (___curRecipePage >= 6 || Core.pageGearForgeInfoListVanilla[___curRecipePage] != null))
                  {
                    __instance.StartCoroutine(QuickCraft(__instance, ___curRecipePage, slotID, ___craftType, ___inventory, ___craft));
                    acted = true;
                  }
                  else if (___craftType == 1 && (___curRecipePage >= 2 || Core.pageAlchemyStationInfoListVanilla[___curRecipePage] != null))
                  {
                    __instance.StartCoroutine(QuickCraft(__instance, ___curRecipePage, slotID, ___craftType, ___inventory, ___craft));
                    acted = true;
                  }
                  else if (___craftType == 2 && (___curRecipePage >= 6 || Core.pageUltimateForgeInfoListVanilla[___curRecipePage] != null))
                  {
                    acted = true;
                  }
                  else if (___craftType == MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID())
                  {
                    __instance.StartCoroutine(QuickCraft(__instance, ___curRecipePage, slotID, ___craftType, ___inventory, ___craft));
                    acted = true;
                  }
                }
              }
            }
          }
        }
      }
      if (acted)
        return false;
      return true;
    }

    private static IEnumerator QuickCraft(GameScript __instance, int ___curRecipePage, int slot, int ___craftType, Item[] ___inventory, Item[] ___craft)
    {
      FieldInfo quickCraftingField = typeof(GameScript).GetField("quickCrafting", BindingFlags.NonPublic | BindingFlags.Instance);
      FieldInfo holdingItemField = typeof(GameScript).GetField("holdingItem", BindingFlags.NonPublic | BindingFlags.Instance);

      if (!(bool)quickCraftingField.GetValue(__instance))
      {
        quickCraftingField.SetValue(__instance, true);
        try
        {
          int craftingItemID = 0;
          int craftingItemAmount = 1;
          List<int> price = new List<int>();
          List<int> takePlayerInventory = new List<int>();
          List<int> takeCraftingInventory = new List<int>();
          bool hasAllItems = true;
          if (___craftType == 0)
          {
            var recipePageEntry = ___curRecipePage >= 6 ? Core.pageGearForgeInfoList[___curRecipePage - 6].GetRecipePageEntries()[slot] : Core.pageGearForgeInfoListVanilla[___curRecipePage].GetRecipePageEntries()[slot];
            craftingItemID = recipePageEntry.ItemIdBase;
            craftingItemAmount = recipePageEntry.MinAmount + Random.Range(0, 1 + recipePageEntry.MaxBonusAmount);
            for (int i = 0; i < recipePageEntry.ItemIdExtension.Length; i++)
            {
              var itemID = recipePageEntry.ItemIdExtension[i];
              if (itemID > 0)
                price.Add(itemID);
            }
          }
          else if (___craftType == 1)
          {
            var recipePageEntry = ___curRecipePage >= 2 ? Core.pageAlchemyStationInfoList[___curRecipePage - 2].GetRecipePageEntries()[slot] : Core.pageAlchemyStationInfoListVanilla[___curRecipePage].GetRecipePageEntries()[slot];
            craftingItemID = recipePageEntry.ItemIdBase;
            craftingItemAmount = recipePageEntry.MinAmount + Random.Range(0, 1 + recipePageEntry.MaxBonusAmount);
            for (int i = 0; i < recipePageEntry.ItemIdExtension.Length; i++)
            {
              var itemID = recipePageEntry.ItemIdExtension[i];
              if (itemID > 0)
                price.Add(itemID);
            }
          }
          else if (___craftType == MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID())
          {
            var recipePageEntry = Core.pageUniversalCrafterInfoList[___curRecipePage].GetRecipePageEntries()[slot];
            craftingItemID = recipePageEntry.ItemIdBase;
            craftingItemAmount = recipePageEntry.MinAmount + Random.Range(0, 1 + recipePageEntry.MaxBonusAmount);
            for (int i = 0; i < recipePageEntry.ItemIdExtension.Length; i++)
            {
              var itemID = recipePageEntry.ItemIdExtension[i];
              if (itemID > 0)
                price.Add(itemID);
            }
          }
          if (craftingItemID == 0 
            || !(___craftType == MenuRegistry.Singleton["Gadget Core:Crafter Menu"].GetID()
            ? ((CraftMenuInfo)MenuRegistry.Singleton["Gadget Core:Crafter Menu"]).IsRecipeUnlocked(craftingItemID)
            : __instance.RecipeCraftedAlready(craftingItemID, 0) ))
          {
            yield break;
          }
          for (int i = 0; i < price.Count; i++)
          {
            int itemSlotPlayerInventory = __instance.ItemExistsSlot(price[i]);
            int itemSlotCraftingInventory = __instance.ItemExistsCraft(price[i]);
            if (itemSlotPlayerInventory == -1 && itemSlotCraftingInventory == -1)
            {
              hasAllItems = false;
              break;
            }
            else if (itemSlotPlayerInventory != -1)
              takePlayerInventory.Add(itemSlotPlayerInventory);
            else if (itemSlotCraftingInventory != -1)
              takeCraftingInventory.Add(itemSlotCraftingInventory);
          }
          if (hasAllItems)
          {
            bool hasCrafted = false;
            Item tempItem = (Item)holdingItemField.GetValue(__instance);
            if (tempItem == null || tempItem.id == 0 || tempItem.id == craftingItemID)
            {
              ItemInfo itemInfo = ItemRegistry.GetItem(craftingItemID);
              ItemType slotItemType = itemInfo != null ? (itemInfo.Type & (ItemType.EQUIP_MASK | ItemType.TYPE_MASK)) : ItemRegistry.GetDefaultTypeByID(craftingItemID);
              if ((slotItemType & ItemType.NONSTACKING) == ItemType.STACKING)
              {
                if (tempItem == null || tempItem.id == 0)
                {
                  holdingItemField.SetValue(__instance, new Item(craftingItemID, craftingItemAmount, 0, 0, 0, new int[3], new int[3]));
                  hasCrafted = true;
                }
                else if (tempItem.q < 9999)
                {
                  tempItem.q += craftingItemAmount;
                  if (tempItem.q > 9999)
                    tempItem.q = 9999;
                  hasCrafted = true;
                }
              }
              else
              {
                if (tempItem == null || tempItem.id == 0)
                {
                  holdingItemField.SetValue(__instance, new Item(craftingItemID, 1, 0, __instance.GetRandomTier(), 0, new int[3], new int[3]));
                  hasCrafted = true;
                }
              }
            }
            if (hasCrafted)
            {
              Object.Instantiate(Resources.Load("clickBurst"), new Vector3(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y, 0f), Quaternion.identity);
              __instance.GetComponent<AudioSource>().PlayOneShot((AudioClip)Resources.Load("Au/create"), Menuu.soundLevel / 10f);

              for (int i = 0; i < takePlayerInventory.Count; i++)
              {
                ___inventory[takePlayerInventory[i]].q--;
                __instance.RefreshSlot(takePlayerInventory[i]);
              }
              for (int i = 0; i < takeCraftingInventory.Count; i++)
              {
                ___craft[takeCraftingInventory[i]].q--;
                __instance.RefreshSlotCraft(takeCraftingInventory[i]);
              }
            }
            __instance.RefreshHoldingSlot();
          }
          else
            __instance.Error(6);
        }
        catch (System.Exception e) { Core.logger.Log(e); }
        finally
        {
          quickCraftingField.SetValue(__instance, false);
        }
      }
      yield break;
    }
  }
}
