local TABAS_ContextMenuCommon = {}

local TABAS_Utils = require("TABAS_Utils")

TABAS_ContextMenuCommon.usingTooltipText = "<RGB:1,0.5,0.5>" .. getText("ContextMenu_TABAS_CurrentlyUsing")
TABAS_ContextMenuCommon.notPipedTooltipText = "<RGB:1,0.5,0.5>" .. getText("ContextMenu_TABAS_NotPiped")
function TABAS_ContextMenuCommon.formatWaterAmount(label, setX, value, maxValue)
	-- Water tiles have waterAmount=9999
	-- Piped water has waterAmount=10000
	if maxValue >= 9999 then
		return string.format("%s: <SETX:%d> %s", label, setX, getText("Tooltip_WaterUnlimited"))
	end
    return string.format("%s: <SETX:%d> %s / %s", label, setX, round(value, 2) .. "L", round(maxValue, 2) .. "L")
	-- return string.format("%s: <SETX:%d> %s <LINE> %s: <SETX:%d> %s", label, setX, round(value, 2) .. "L", getText("Tooltip_container_Capacity"), setX, round(maxValue, 2) .. "L")
end

function TABAS_ContextMenuCommon.formatLabelAndBoolean(label, setX, value)
    if value then
        return string.format("%s: <SETX:%d> %s", label, setX, getText("UI_Yes"))
    else
        return string.format("%s: <SETX:%d> %s", label, setX, getText("UI_No"))
    end
end

function TABAS_ContextMenuCommon.formatLabelAndValue(label, setX, value)
    return string.format("%s: <SETX:%d> %s", label, setX, value)
end

function TABAS_ContextMenuCommon.formatLabelAndInteger(label, setX, value, maxValue)
    if maxValue then
        return string.format("%s: <SETX:%d> %s / %s", label, setX, value, maxValue)
    else
        return string.format("%s: <SETX:%d> %s", label, setX, value)
    end
end

local function canStand(sqr)
    if not sqr or sqr:Is(IsoFlagType.solid) then return false end
    if sqr:Is(IsoFlagType.solidtrans) then
        if not (sqr:isAdjacentToWindow() or sqr:isAdjacentToHoppable()) then
            return false
        end
    end
    if not sqr:TreatAsSolidFloor() then
        return false
    end
    return true
end

local function choicesSquare(square, directions)
    local choices = {}
    local adjacent = nil
    for i=1, #directions do
        local dir = directions[i]
        adjacent = square:getAdjacentSquare(dir)
        if adjacent and canStand(adjacent) and not square:isBlockedTo(adjacent) then
            table.insert(choices, adjacent)
        end
    end
    return choices
end

local function choicesFreeSquare(square, directions)
    local choices = {}
    local adjacent = nil
    for i=1, #directions do
        local dir = directions[i]
        adjacent = square:getAdjacentSquare(dir)
        if adjacent and canStand(adjacent) and not square:isBlockedTo(adjacent) and not adjacent:getProperties():Is("BlocksPlacement") then
            table.insert(choices, adjacent)
        end
    end
    return choices
end

local function choicesClosestSquare(playerObj, choices)
    if #choices == 0 then return nil end

    local minDist = 10000
    local closestSqr = nil
    for i=1, #choices do
        local targetSqr = choices[i]
        local dist = targetSqr:DistToProper(playerObj)
        if dist < minDist then
            minDist = dist
            closestSqr = targetSqr
        end
    end
    return closestSqr
end

-- taking other side of the wall if we're behind a collidable item -- this function by luautils.
local function getCorrectSquareForWall(playerObj, square)
    if square:Is(IsoFlagType.collideW) and playerObj:getX() < square:getX() then
        return getCell():getGridSquare(square:getX() + 1, square:getY(), square:getZ())
    end
    if square:Is(IsoFlagType.collideN) and playerObj:getY() < square:getY() then
        return getCell():getGridSquare(square:getX(), square:getY() + 1, square:getZ())
    end
    return square
end

function TABAS_ContextMenuCommon.FindFrontFreeSquare(square, facing)
    local dir = IsoDirections[facing]
    local adjacent = square:getAdjacentSquare(dir)
    if adjacent and canStand(adjacent) and not square:isBlockedTo(adjacent) then
        local props = adjacent:getProperties()
        if props and not props:Is("BlocksPlacement") then
            return adjacent
        end
    end
    return nil
end

function TABAS_ContextMenuCommon.FindClosestAdjacent3Square(playerObj, square, facing)
    local choices
    if facing == "S" then
        choices = choicesSquare(square, {IsoDirections.S, IsoDirections.E, IsoDirections.W})
    elseif facing == "E" then
        choices = choicesSquare(square, {IsoDirections.E, IsoDirections.N, IsoDirections.S})
    elseif facing == "N" then
        choices = choicesSquare(square, {IsoDirections.N, IsoDirections.E, IsoDirections.W})
    else
        choices = choicesSquare(square, {IsoDirections.W, IsoDirections.N, IsoDirections.S})
    end
    local adjacent = choicesClosestSquare(playerObj, choices)
    if adjacent then return adjacent end
    return false
end

function TABAS_ContextMenuCommon.FindClosestAdjacentFreeSquare(playerObj, square, facing)
    local choices
    if facing == "S" then
        choices = choicesFreeSquare(square, {IsoDirections.E, IsoDirections.W, IsoDirections.SE, IsoDirections.SW})
    elseif facing == "E" then
        choices = choicesFreeSquare(square, {IsoDirections.N, IsoDirections.S, IsoDirections.SE, IsoDirections.NE})
    elseif facing == "N" then
        choices = choicesFreeSquare(square, {IsoDirections.E, IsoDirections.W, IsoDirections.NE, IsoDirections.NW})
    else
        choices = choicesFreeSquare(square, {IsoDirections.N, IsoDirections.S, IsoDirections.SW, IsoDirections.NW})
    end
    local adjacent = choicesClosestSquare(playerObj, choices)
    if adjacent then return adjacent end
    return false
end

function TABAS_ContextMenuCommon.FindAdjacentTubSquare(playerObj, object, facing)
    if not TABAS_Utils.isBathObject(object) then return end

    local square = object:getSquare()
    local choices
    if facing == "S" or facing == "N" then
        choices = choicesFreeSquare(square, {IsoDirections.E, IsoDirections.W})
    else
        choices = choicesFreeSquare(square, {IsoDirections.S, IsoDirections.N})
    end
    local adjacent = choicesClosestSquare(playerObj, choices)
    if adjacent then return adjacent end
    return false
end

function TABAS_ContextMenuCommon.walkToAdjTub(playerObj, object, keepActions)
    local targetSquare = object:getSquare()
    local facing = TABAS_Utils.getObjectFacing(object)
    if not targetSquare or not facing then return end

    if not keepActions then
		ISTimedActionQueue.clear(playerObj)
	end
    local square = getCorrectSquareForWall(playerObj, targetSquare)
    if square then
        local diffX = math.abs(square:getX() + 0.5 - playerObj:getX())
        local diffY = math.abs(square:getY() + 0.5 - playerObj:getY())
        if diffX <= 1.6 and diffY <= 1.6 and playerObj:getSquare():canReachTo(square) then
            return true
        end
    end
    local adjacent = TABAS_ContextMenuCommon.FindClosestAdjacentFreeSquare(playerObj, targetSquare, facing)
    if adjacent then
        ISTimedActionQueue.add(ISWalkToTimedAction:new(playerObj, adjacent))
        return true
    end
    return false
end

function TABAS_ContextMenuCommon.doWalkInTheTubMenu(player, facucetObj, tubObj, subMenu)
    local playerObj = getSpecificPlayer(player)
    if playerObj:getModData().isBathing then return end

    local currentSquare = playerObj:getCurrentSquare()
    if currentSquare:isSolidTrans() then
        local targetSquare = facucetObj:getSquare()
        if currentSquare:getX() == targetSquare:getX() and currentSquare:getY() == targetSquare:getY() then
            targetSquare = tubObj:getSquare()
        end
        if targetSquare then
            subMenu:addOption("Walk In The Tub", playerObj, TABAS_ContextMenuCommon.onWalkInTheTub, facucetObj, tubObj, targetSquare)
        end
    end
end

function TABAS_ContextMenuCommon.onWalkInTheTub(playerObj, facucetObj, tubObj, targetSquare)
    ISTimedActionQueue.add(TABAS_WalkInTheTubAction:new(playerObj, facucetObj, targetSquare, tubObj))
end

function TABAS_ContextMenuCommon.vanillaFluidMenu(player, worldObjects, test, bathingObj, context)
	if bathingObj:hasFluid() then
		ISWorldObjectContextMenu.doDrinkWaterMenu(bathingObj, player, context)
		ISWorldObjectContextMenu.doFillFluidMenu(bathingObj, player, context)
	end
	if bathingObj:hasWater() then
		ISWorldObjectContextMenu.doWashClothingMenu(bathingObj, player, context)
	end
	-- if bathingObj:hasFluid() and bathingObj:getFluidCapacity() < 9999 then	-- capacity >= 9999 means infinite water.
	-- 	context:addOption(getText("Fluid_Empty"), player, ISWorldObjectContextMenu.onFluidEmpty, bathingObj:getFluidContainer());
	-- end
end

function TABAS_ContextMenuCommon.setTemperatureMenu(player, object, context)
    local playerObj = getSpecificPlayer(player)
    local option = context:addOption(getText("ContextMenu_TABAS_SetTemperature"), object, TABAS_ContextMenuCommon.onOpenSetTempeUI, playerObj)
    local icon = "media/ui/Icons/tabas_temperatureSetting.png"
    option.iconTexture = getTexture(icon)
end

function TABAS_ContextMenuCommon.onOpenSetTempeUI(object, playerObj)
    if TABAS_ContextMenuCommon.walkToAdjTub(playerObj, object, true) then
        ISTimedActionQueue.add(TABAS_OpenSetTemperatureUIAction:new(playerObj, object))
    end
end

local function animTest(player)
    local playerObj = getSpecificPlayer(player)
    ISTimedActionQueue.add(TABAS_AnimTest:new(playerObj))
end

local function test(_object)
    local tfcBase = TABAS_Utils.getTfcBaseOnBathObject(_object)
    if not tfcBase then
        return
    end
    local overlay = tfcBase.bathObject:getAttachedAnimSprite()
    local overlay2 = tfcBase.linkedBathObject:getAttachedAnimSprite()

    tfcBase.linkedBathObject:setOverlaySprite("fixtures_01_31")
end

function TABAS_ContextMenuCommon.doDebugMenu(player, object, context)
    local mainMenu = context:addDebugOption("TABAS Debug:")
    local subMenu = ISContextMenu:getNew(context)
    context:addSubMenu(mainMenu, subMenu)

    local toggleUsing = function(object)
        if not object:getModData().using then
            object:getModData().using = true
        else 
            object:getModData().using = nil
        end
    end
    subMenu:addOption("Toggle Using", object, toggleUsing)
    -- subMenu:addOption("Anim Test", player, animTest)
    subMenu:addOption("Test", object, test)
    return subMenu
end


return TABAS_ContextMenuCommon