-- Bundled by luabundle {"version":"1.6.0"}
local __bundle_require, __bundle_loaded, __bundle_register, __bundle_modules = (function(superRequire)
	local loadingPlaceholder = {[{}] = true}

	local register
	local modules = {}

	local require
	local loaded = {}

	register = function(name, body)
		if not modules[name] then
			modules[name] = body
		end
	end

	require = function(name)
		local loadedModule = loaded[name]

		if loadedModule then
			if loadedModule == loadingPlaceholder then
				return nil
			end
		else
			if not modules[name] then
				if not superRequire then
					local identifier = type(name) == 'string' and '\"' .. name .. '\"' or tostring(name)
					error('Tried to require ' .. identifier .. ', but no such module has been registered')
				else
					return superRequire(name)
				end
			end

			loaded[name] = loadingPlaceholder
			loadedModule = modules[name](require, loaded, register, modules)
			loaded[name] = loadedModule
		end

		return loadedModule
	end

	return require, loaded, register, modules
end)(nil)
__bundle_register("__root", function(require, _LOADED, __bundle_register, __bundle_modules)
require("accessories/HandHelper")
end)
__bundle_register("accessories/HandHelper", function(require, _LOADED, __bundle_register, __bundle_modules)
local playmatAPI = require("playermat/PlaymatApi")

local buttonParamaters          = {}
buttonParamaters.function_owner = self

-- saving "playerColor" and "des"
function onSave() return JSON.encode({ playerColor, des}) end

function onLoad(saved_data)
    -- loading saved data
    local loaded_data = JSON.decode(saved_data)
    playerColor       = loaded_data[1] or Player.getAvailableColors()[1]
    des               = loaded_data[2] or false

    -- index 0: button as hand size label
    buttonParamaters.hover_color    = "White"
    buttonParamaters.click_function = "none"
    buttonParamaters.position       = { 0, 0.11, -0.4 }
    buttonParamaters.height         = 0
    buttonParamaters.width          = 0
    buttonParamaters.font_size      = 500
    buttonParamaters.font_color     = "White"
    self.createButton(buttonParamaters)

    -- index 1: button to toggle "des"
    buttonParamaters.label          = "DES: " .. (des and "✓" or "✗")
    buttonParamaters.click_function = "toggleDES"
    buttonParamaters.position       = { 0.475, 0.11, 0.25 }
    buttonParamaters.height         = 175
    buttonParamaters.width          = 440
    buttonParamaters.font_size      = 90
    buttonParamaters.font_color     = "Black"
    self.createButton(buttonParamaters)

    -- index 2: button to discard a card
    buttonParamaters.label          = "discard random card"
    buttonParamaters.click_function = "discardRandom"
    buttonParamaters.position       = { 0, 0.11, 0.7 }
    buttonParamaters.width          = 900
    self.createButton(buttonParamaters)

    -- index 3: button to select color
    buttonParamaters.label          = playerColor
    buttonParamaters.color          = playerColor
    buttonParamaters.hover_color    = playerColor
    buttonParamaters.click_function = "changeColor"
    buttonParamaters.tooltip        = "change color"
    buttonParamaters.position       = { -0.475, 0.11, 0.25 }
    buttonParamaters.width          = 440
    self.createButton(buttonParamaters)

    -- start loop to update card count
    loopId = Wait.time(||updateValue(), 1, -1)

    -- context menu to quickly bind color
    self.addContextMenuItem("Bind to my color", function(color)
        changeColor(_, _, _, color)
    end)

    -- context menu to display additional information
    self.addContextMenuItem("More Information", function()
        printToAll("------------------------------", "White")
        printToAll("Hand Helper by Chr1Z", "Orange")
        printToAll("original by Tikatoy", "White")
        printToAll("Note: 'Hidden' cards can't be randomly discarded.", "Yellow")
        printToAll("Set them aside beforehand!", "Yellow")
    end)

    -- initialize the pseudo random number generator
    math.randomseed(os.time())
end

function onObjectHover(hover_color, obj)
    -- only continue if correct player hovers over "self"
    if obj ~= self or hover_color ~= playerColor then return end

    -- stop loop, toggle "des" and displayed value briefly, then start new loop
    Wait.stop(loopId)
    des = not des
    updateValue()
    des = not des
    loopId = Wait.time(||updateValue(), 1, -1)
end

-- toggle "des" and update button label
function toggleDES()
    des = not des
    self.editButton({index = 1, label = "DES: " .. (des and "✓" or "✗")})
    updateValue()
end

-- count cards in hand (by name for DES)
function updateValue()
    if not playerExists(playerColor) then return end

    local hand = Player[playerColor].getHandObjects()
    local size = 0

    if des then
        local cardHash = {}
        for _, obj in pairs(hand) do
            if obj.tag == "Card" then
                local name = obj.getName()
                local title = string.match(name, '(.+)(%s%(%d+%))') or name
                cardHash[title] = obj
            end
        end
        for _, obj in pairs(cardHash) do
            size = size + 1
        end
    else
        for _, obj in pairs(hand) do
            if obj.tag == "Card" then size = size + 1 end
        end
    end
    -- change button label and color
    self.editButton({index = 0, font_color = des and "Green" or "White", label = size})
end

-- allows change of color via external call
function externalColorChange(newColor)
    changeColor(_, _, _, newColor)
end

-- get index of current color and move up one step (or down for right-click)
function changeColor(_, _, isRightClick, color)
    if color then
        playerColor = color
    else
        local COLORS = Player.getAvailableColors()
        local pos = indexOf(COLORS, playerColor)

        if isRightClick then
            if pos == nil or pos == 1 then pos = #COLORS
            else pos = pos - 1 end
        else
            if pos == nil or pos == #COLORS then pos = 1
            else pos = pos + 1 end
        end

        -- update playerColor
        playerColor = COLORS[pos]
    end

    -- update "change color" button (note: remove and create instantly updates hover_color)
    buttonParamaters.label          = playerColor
    buttonParamaters.color          = playerColor
    buttonParamaters.hover_color    = playerColor
    self.removeButton(3)
    self.createButton(buttonParamaters)
end

---------------------------------------------------------
-- discards a random card from hand
---------------------------------------------------------

function discardRandom()
    if not playerExists(playerColor) then return end

    -- error handling: hand is empty
    local hand = Player[playerColor].getHandObjects()
    if #hand == 0 then
        broadcastToAll("Cannot discard from empty hand!", "Red")
    else
        local searchPos = Player[playerColor].getHandTransform().position

        local discardPos = playmatAPI.getDiscardPosition(playmatAPI.getMatColorByPosition(searchPos))
        if discardPos == nil then
            broadcastToAll("Couldn't retrieve discard position from playermat!", "Red")
            return
        end

        local num = math.random(1, #hand)
        hand[num].setPosition(discardPos)
        broadcastToAll(playerColor .. " randomly discarded card " .. num .. "/" .. #hand .. ".", "White")
    end
end

---------------------------------------------------------
-- helper functions
---------------------------------------------------------

-- helper to search array
function indexOf(array, value)
    for i, v in ipairs(array) do
        if v == value then return i end
    end
end

-- helper to check if player exists
function playerExists(color)
    local COLORS = Player.getAvailableColors()
    return indexOf(COLORS, color) and true or false
end
end)
__bundle_register("playermat/PlaymatApi", function(require, _LOADED, __bundle_register, __bundle_modules)
do
  local PlaymatApi = { }
  local internal = { }

  local MAT_IDS = {
    White  = "8b081b",
    Orange = "bd0ff4",
    Green  = "383d8b",
    Red    = "0840d5"
  }

  local CLUE_COUNTER_GUIDS = {
    White  = "37be78",
    Orange = "1769ed",
    Green  = "032300",
    Red    = "d86b7c"
  }

  local CLUE_CLICKER_GUIDS = {
    White  = "db85d6",
    Orange = "3f22e5",
    Green  = "891403",
    Red    = "4111de"
  }

  -- Returns the color of the by position requested playermat as string
  ---@param startPos Table Position of the search, table get's roughly cut into 4 quarters to assign a playermat
  PlaymatApi.getMatColorByPosition = function(startPos)
    if startPos.x < -42 then
      if startPos.z > 0 then
        return "White"
      else
        return "Orange"
      end
    else
      if startPos.z > 0 then
        return "Green"
      else
        return "Red"
      end
    end
  end

  -- Returns the draw deck of the requested playmat
  ---@param matColor String Color of the playermat
  PlaymatApi.getDrawDeck = function(matColor)
    local mat = getObjectFromGUID(MAT_IDS[matColor])
    mat.call("getDrawDiscardDecks")
    return mat.getVar("drawDeck")
  end

  -- Returns the position of the discard pile of the requested playmat
  ---@param matColor String Color of the playermat
  PlaymatApi.getDiscardPosition = function(matColor)
    local mat = getObjectFromGUID(MAT_IDS[matColor])
    return mat.call("returnGlobalDiscardPosition")
  end

  -- Sets the requested playermat's snap points to limit snapping to matching card types or not.  If
  -- matchTypes is true, the main card slot snap points will only snap assets, while the
  -- investigator area point will only snap Investigators.  If matchTypes is false, snap points will
  -- be reset to snap all cards.
  ---@param matchCardTypes Boolean.  Whether snap points should only snap for the matching card
  --     types.
  ---@param matColor String for one of the active player colors - White, Orange, Green, Red.  Also
  --     accepts "All" as a special value which will apply the setting to all four mats.
  PlaymatApi.setLimitSnapsByType = function(matchCardTypes, matColor)
    for _, mat in ipairs(internal.getMatForColor(matColor)) do
      mat.call("setLimitSnapsByType", matchCardTypes)
    end
  end

  -- Sets the requested playermat's draw 1 button to visible
  ---@param isDrawButtonVisible Boolean.  Whether the draw 1 button should be visible or not
  ---@param matColor String for one of the active player colors - White, Orange, Green, Red.  Also
  --     accepts "All" as a special value which will apply the setting to all four mats.
  PlaymatApi.showDrawButton = function(isDrawButtonVisible, matColor)
    for _, mat in ipairs(internal.getMatForColor(matColor)) do
      mat.call("showDrawButton", isDrawButtonVisible)
    end
  end

  -- Shows or hides the clickable clue counter for the requested playermat
  ---@param showCounter Boolean.  Whether the clickable counter should be present or not
  ---@param matColor String for one of the active player colors - White, Orange, Green, Red.  Also
  --     accepts "All" as a special value which will apply the setting to all four mats.
  PlaymatApi.clickableClues = function(showCounter, matColor)
    for _, mat in ipairs(internal.getMatForColor(matColor)) do
      mat.call("clickableClues", showCounter)
    end
  end

  -- Removes all clues (to the trash for tokens and counters set to 0) for the requested playermat
  ---@param matColor String for one of the active player colors - White, Orange, Green, Red.  Also
  --     accepts "All" as a special value which will apply the setting to all four mats.
  PlaymatApi.removeClues = function(matColor)
    for _, mat in ipairs(internal.getMatForColor(matColor)) do
      mat.call("removeClues")
    end
  end

  -- Reports the clue count for the requested playermat
  ---@param useClickableCounters Boolean Controls which type of counter is getting checked
  PlaymatApi.getClueCount = function(useClickableCounters, matColor)
    local count = 0
    for _, mat in ipairs(internal.getMatForColor(matColor)) do
      count = count + tonumber(mat.call("getClueCount", useClickableCounters))
    end
    return count
  end

  -- Convenience function to look up a mat's object by color, or get all mats.
  ---@param matColor String for one of the active player colors - White, Orange, Green, Red.  Also
  --     accepts "All" as a special value which will return all four mats.
  ---@return: Array of playermat objects.  If a single mat is requested, will return a single-element
  --     array to simplify processing by consumers.
  internal.getMatForColor = function(matColor)
    local targetMatGuid = MAT_IDS[matColor]
    if targetMatGuid != nil then
      return { getObjectFromGUID(targetMatGuid) }
    end
    if matColor == "All" then
      return {
        getObjectFromGUID(MAT_IDS.White),
        getObjectFromGUID(MAT_IDS.Orange),
        getObjectFromGUID(MAT_IDS.Green),
        getObjectFromGUID(MAT_IDS.Red),
      }
    end
  end

  return PlaymatApi
end
end)
return __bundle_require("__root")