local BattleBoardTouchHelper = require "app/module/battle/helper/battle_board_touch_helper"
local BoardHelper = {}
local BattleConst = GConst.BattleConst

function BoardHelper:getEmptyTable()
    if not self.tempEmptyTables then
        self.tempEmptyTables = {}
    end
    if not self.tempEmptyTables[1] then
        table.insert(self.tempEmptyTables, {})
    end
    return table.remove(self.tempEmptyTables)
end

function BoardHelper:recycleedEmptyTable(emptyTable)
    if not emptyTable then
        return
    end
    emptyTable = table.clear(emptyTable)
    if self.tempEmptyTables then
        table.insert(self.tempEmptyTables, emptyTable)
    end
end

function BoardHelper:findPvpLinkOptimalSolution(battleController, startRow, endRow, elementTypeCoefficient, minCount)
    local battleData = battleController.battleData
    local gridMap = BoardHelper:getEmptyTable()
    local gridEntities = BoardHelper:getEmptyTable()
    local step = 1
    if startRow > endRow then
        step = -1
    end

    for row = startRow, endRow, step do -- 遍历所有的可使用格子
        for column = 1, BattleConst.COLUMN_COUNT do
            local posId = ModuleManager.BattleManager:getPosId(row, column)
            local gridEntity = battleData:getGridEnties()[posId]
            if gridEntity and gridEntity:canLink() then
                table.insert(gridEntities, posId)
                gridMap[posId] = gridEntity
            end
        end
    end

    local maxPath
    local maxPathCount = 0
    local newHaveSkill = false
    local lastMainElementType
    if not elementTypeCoefficient then
        elementTypeCoefficient = BoardHelper:getEmptyTable()
    end
    for _, posId in pairs(gridEntities) do
        local entity = gridMap[posId]
        local mainElementType
        if not entity:getSkillId() then
            mainElementType = entity:getElementType()
            local tree = BoardHelper:getEmptyTable()
            self:getCanlinkTree(posId, gridMap, tree, mainElementType)

            local checked = BoardHelper:getEmptyTable()
            local haveSkill = false
            local path, getSkill = self:findMaxPath(posId, tree, checked, haveSkill, gridMap)
            local count = #path
            if minCount <= count then
                if getSkill and not newHaveSkill then
                    maxPath = path
                    maxPathCount = count
                    newHaveSkill = getSkill
                    lastMainElementType = mainElementType
                else
                    local curCoefficient = elementTypeCoefficient[mainElementType] or 0
                    local lastCoefficient = elementTypeCoefficient[lastMainElementType] or 0
                    if not getSkill and newHaveSkill then
                        BoardHelper:recycleedEmptyTable(path)
                    else
                        if count * curCoefficient > maxPathCount * lastCoefficient then
                            maxPath = path
                            maxPathCount = count
                            newHaveSkill = getSkill
                            lastMainElementType = mainElementType
                        else
                            BoardHelper:recycleedEmptyTable(path)
                        end
                    end
                end
            else
                BoardHelper:recycleedEmptyTable(path)
            end

            for posId, info in pairs(tree) do
                BoardHelper:recycleedEmptyTable(info)
            end
            BoardHelper:recycleedEmptyTable(tree)
            BoardHelper:recycleedEmptyTable(checked)
        end
    end

    BoardHelper:recycleedEmptyTable(elementTypeCoefficient)
    BoardHelper:recycleedEmptyTable(gridMap)

    return maxPath
end

function BoardHelper:findMaxPath(posId, tree, checked, haveSkill, gridMap)
    if not checked[posId] and tree[posId] then
        local newPath
        local newPathCount = 0
        local newHaveSkill = false
        local newChecked = GFunc.getTable(checked)
        newChecked[posId] = true
        for nextPosId, _ in pairs(tree[posId]) do
            if BattleBoardTouchHelper:judgeGridEdgeCanLink(posId, nextPosId) then
                local entity = gridMap[nextPosId]
                if not entity:getSkillId() or not haveSkill then
                    if entity:getSkillId() then
                        haveSkill = true
                    end
                    local p, getSkill = self:findMaxPath(nextPosId, tree, newChecked, haveSkill, gridMap)
                    if p then
                        local count = #p
                        if getSkill and not newHaveSkill then
                            newPath = GFunc.getTable(p)
                            newPathCount = count
                            newHaveSkill = getSkill
                        else
                            if not getSkill and newHaveSkill then
                                BoardHelper:recycleedEmptyTable(p)
                            else
                                if count > newPathCount then
                                    newPath = GFunc.getTable(p)
                                    newPathCount = count
                                    newHaveSkill = getSkill
                                else
                                    BoardHelper:recycleedEmptyTable(p)
                                end
                            end
                        end
                    end
                end
            end

        end
        if not newPath then
            newPath = BoardHelper:getEmptyTable()
        end
        table.insert(newPath, 1, posId)
        if not newHaveSkill then
            newHaveSkill = gridMap[posId]:getSkillId() ~= nil
        end

        return newPath, newHaveSkill
    end
end

function BoardHelper:getCanlinkTree(posId, gridMap, tree, mainElementType)
    if tree[posId] then
        return
    end

    local ids = self:getAroundPosIds(posId, gridMap, mainElementType)
    tree[posId] = ids
    for aroundPosId, status in pairs(ids) do
        self:getCanlinkTree(aroundPosId, gridMap, tree, mainElementType)
    end
end

function BoardHelper:getAroundPosIds(posId, gridMap, mainElementType)
    local ids = BoardHelper:getEmptyTable()
    local aroundPosIds = BattleConst.GRID_OUT_LINE_POS_ID[posId]
    if aroundPosIds then
        for id, status in pairs(aroundPosIds) do
            if gridMap[id] and (gridMap[id]:getElementType() == mainElementType or gridMap[id]:getSkillId()) then
                ids[id] = true
            end
        end
    end
    return ids
end

function BoardHelper:hasGridEdgeBetween(battleController, posId1, posId2)
    local direction = ModuleManager.BattleManager:getPosDirection(posId1, posId2)
    local reverseDirection = ModuleManager.BattleManager:getReverseDirection(direction)
    if not reverseDirection then
        return false
    end

    local gridEdgeEntity = battleController.battleData:getGridEdgeEntity(posId1, direction)
    if gridEdgeEntity and not gridEdgeEntity:getIsIdle() then
        return true
    end

    local gridEdgeEntity = battleController.battleData:getGridEdgeEntity(posId2, reverseDirection)
    if gridEdgeEntity and not gridEdgeEntity:getIsIdle() then
        return true
    end

    return false
end

return BoardHelper