-- luacheck: globals Character MyModGlobal Timer CLIENT
if not CLIENT then return end
local quickstack = require("Cyka.quickstack")
local utils = require("Cyka.utils")

local targetInventory = nil
local slotThrottle = {}
local function tryStackCursorItem()
	local slots, err = utils.getSlotsUnderCursor()
	if err then
		-- MyModGlobal.debugPrint(string.format("Error getting inventory slot: %s", err))
		return
	end

	if not slots or #slots == 0 then
		-- MyModGlobal.debugPrint("No items in slot")
		return
	end

	local inventory = targetInventory
	-- MyModGlobal.debugPrint(string.format("Target inventory: %s", tostring(inventory)))
	if not inventory then
		local controlledCharacter = Character.Controlled
		if not controlledCharacter then
			-- MyModGlobal.debugPrint("No controlled character found")
			return
		end
		local cinventory = controlledCharacter.Inventory
		if not cinventory or not cinventory.slots then
			-- MyModGlobal.debugPrint("No inventory found")
			return
		end
		local bagSlot = cinventory.slots[MyModGlobal.BAG_SLOT]
		if not bagSlot or not bagSlot.items or not bagSlot.items[1] then
			-- MyModGlobal.debugPrint("No bag slot found")
			return
		end
		local bagItem = bagSlot.items[1]
		if not bagItem or not bagItem.OwnInventory then
			-- MyModGlobal.debugPrint("Bag item has no own inventory")
			return
		end
		local bagInventory = bagItem.OwnInventory
		if not bagInventory or not bagInventory.slots then
			-- MyModGlobal.debugPrint("Bag inventory has no slots")
			return
		end
		inventory = bagInventory
	end
	if not inventory then
		-- MyModGlobal.debugPrint("No inventory found")
		return
	end

	local itemTree
	itemTree, err = quickstack.buildItemTree(inventory)
	if err then
		-- MyModGlobal.debugPrint(string.format("Error building item tree: %s", err))
		return
	end
	itemTree = quickstack.sortItemTree(itemTree)

	local itemsToMove = {}
	local now = Timer.GetTime()
	for _, slot in ipairs(slots) do
		local runAfter = slotThrottle[slot] or 0
		if now < runAfter then
			goto continue
		end
		-- MyModGlobal.debugPrint(string.format("Enqueuing slot: %s, before: %d", tostring(slot), #itemsToMove))
		utils.enqueueSlot(slot.slot, itemsToMove)
		-- MyModGlobal.debugPrint(string.format("Enqueuing slot: %s, after: %d", tostring(slot), #itemsToMove))
		slotThrottle[slot] = now + 1
		::continue::
	end
	-- for _, item in ipairs(itemsToMove) do
	-- 	MyModGlobal.debugPrint(string.format("Enqueued item: %s", tostring(item)))
	-- end
	-- -- MyModGlobal.debugPrint(string.format("Enqueued %d items from the inventory slot", #itemsToMove))
	-- MyModGlobal.DumpTable(itemTree)

	quickstack.tryMoveItems(itemsToMove, itemTree, true)
	-- local errors = quickstack.tryMoveItems(itemsToMove, itemTree, true)
	-- for _, error in ipairs(errors) do
	-- 	MyModGlobal.debugPrint(string.format("Error moving item: %s", error))
	-- end
end

local function setTargetInventory()
	local slots, err = utils.getSlotsUnderCursor()
	if err then
		MyModGlobal.debugPrint(string.format("Error getting inventory slot: %s", err))
		return
	end
	if not slots or #slots == 0 then
		MyModGlobal.debugPrint("No inventory slots found")
		return
	end
	-- Yes we do this in a loop
	-- The idea is if we get one slot we're golden, great!
	-- If we get multiple we'll use the first valid one
	-- Although everything is valid to us...
	for _, slot in ipairs(slots) do
		local item
		local items = slot.slot.items
		if not items or #items == 0 then
			print(string.format("Slot is empty, setting target inventory to %s", tostring(slot.inventory)))
			targetInventory = slot.inventory
			goto continue
		end
		item = items[1]
		if not item then
			print(string.format("Item in slot is nil, setting target inventory to %s", tostring(slot.inventory)))
			targetInventory = slot.inventory
			goto continue
		end
		if not item.OwnInventory then
			print(string.format("Item has no own inventory, setting target inventory to %s", tostring(slot.inventory)))
			targetInventory = slot.inventory
			goto continue
		end
		print(string.format("Item has own inventory, setting target inventory to %s", tostring(item.OwnInventory)))
		targetInventory = item.OwnInventory
		break
		::continue::
	end
end

return {
	tryStackCursorItem = tryStackCursorItem,
	setTargetInventory = setTargetInventory,
}
