local BattleHelper = require "app/module/battle/helper/battle_helper"
local board_heler = require "app/module/battle/helper/board_helper"
local BattleBaseController = require "app/module/battle/controller/battle_base_controller"
local BattleControllerPVP = class("BattleControllerPVP", BattleBaseController)
local BattleConst = GConst.BattleConst
local SIDE_ATK = BattleConst.SIDE_ATK
local SIDE_DEF = BattleConst.SIDE_DEF

-- *************各个子模块的战斗需要重写的方法 START*************
function BattleControllerPVP:getBoardConfig()
    return {}
end

function BattleControllerPVP:getChapterConfig()
    return {}
end

function BattleControllerPVP:getChapterId()
    return 0
end

function BattleControllerPVP:getBuffs()
    return {}
end

-- 战斗对应的ui
function BattleControllerPVP:getBattleUIPath()
	return "app/ui/battle/battle_ui_pvp"
end

-- 战斗结束
function BattleControllerPVP:controllBattleEnd()
end

-- 一共有多少波
function BattleControllerPVP:getMaxWave()
    return 1
end

function BattleControllerPVP:findNextDefUnit()
    self:enterRoundEnd(true)
end

function BattleControllerPVP:postWaveOver(atkDead, isQuit)

end

function BattleControllerPVP:postFightStart()

end

function BattleControllerPVP:getMaxRoundCount()
    return 1
end

-- *************各个子模块的战斗需要重写的方法 END*************

function BattleControllerPVP:ctor()
    self.battleData = DataManager.BattlePVPData
end

function BattleControllerPVP:initDefUnits(callback)
    local defTeamEntity = self.battleData:getDefTeam()
    local count = 0
    local totalCount = defTeamEntity:getMembersCount()
    local function onloadFinished()
		count = count + 1
		if count == totalCount then
            self.battleUI:refreshAtkHp(defTeamEntity:getHp(), defTeamEntity:getHpPercent())
			callback()
		end
	end
    local members = defTeamEntity:getAllMembers()
    for k, v in pairs(members) do
        local modelId = v:getModelId()
        BattleHelper:loadBattleHeroModel(modelId, self.battleUI:getBattleNode(), function(spineObject)
			local heroComp = spineObject:addLuaComponent(BattleConst.TYPEOF_LUA_COMP.BATTLE_HERO_COMPONENT)
			heroComp:initWithEntity(modelId, v, self)
            if v:getIsMainUnit() then
                self.defTeam:addUnit(heroComp, true)
            else
                self.defTeam:addUnit(heroComp)
                heroComp:hideOutsideScreen()
            end
			onloadFinished()
		end)
    end
    if totalCount == 0 then
        callback()
    end
end

function BattleControllerPVP:onLoadComplete(...)
    -- 处理技能
    local unlockAllSkill = function(side)
        local skillPool = self.battleData:getSkillPool(side)
        if skillPool then
            for elementType, list in pairs(skillPool) do -- 先遍历一下未解锁的技能
                if not self.battleData:isUnlockedSkillElementType(elementType, side) then
                    local skillEntity = self.battleData:getSkillEntityByElement(elementType, side)
                    if skillEntity then
                        local skillId = skillEntity:getUnlockId()
                        if skillId then
                            self:dealSelectSkill(skillId, nil, side)
                        end
                    end
                    for _, skillId in ipairs(list) do
                        self:dealSelectSkill(skillId, nil, side)
                    end
                end
            end
            self.battleUI:refreshSkill(nil, nil, side)
        end
    end
    unlockAllSkill(SIDE_ATK)
    unlockAllSkill(SIDE_DEF)

    BattleBaseController.onLoadComplete(self, ...)
end

function BattleControllerPVP:onLinkOverDone(skillEntity, linkElementType, lineCount, influenceElementTypeMap, elementTypeMap)
    if linkElementType then
        self:generateInstructions(skillEntity, linkElementType, lineCount, influenceElementTypeMap, elementTypeMap)
        local instructions = self.instructions
        local side = self.curActionSide
        self.instructions = nil
        local action = function()
            if side == SIDE_ATK then
                self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_ATK_STEP
            else
                self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_DEF_STEP
            end
            self.instructions = instructions
            self:exeInstructions(function()
                self:enterNextTeamAction()
            end, side)
        end
        self:addTeamActionList(action, #self.battleTeamActionList + 1)
    end

    local nextSide = self:getCurActionOtherSide()
    local sideCount = self:getSideActionCount(nextSide)
    if sideCount > 0 then
        self:setCurActionSide(nextSide)
        self.battleUI:enterShowBoardAni(function()
            self:enterElimination()
        end, true)
    else
        self.battleUI:enterHideBoardAni(function()
            self:enterBattleStep()
        end)
    end
end

function BattleControllerPVP:enterElimination(needDelay)
    if self.showSelectSkillSid then
        ModuleManager.BattleManager:unscheduleGlobal(self.showSelectSkillSid)
        self.showSelectSkillSid = nil
    end

    if self.battleData:useAddlvCount() then
        self:tryShowSelectSkillComp(needDelay)
        return
    end

    self.battleUI:hideAllBoardSfxs()

    -- 检查棋盘
    local find, pathList = self:findAttention()
    if not find then -- 如果没找到，就要打乱棋盘
        self:shuffleBoard(function()
            self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_ELIMINATION
            if self:skipEliminationAction() then
                return
            end
            self:checkDefBoard()
        end)
    else
        self.attentionList = pathList
        self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_ELIMINATION
        if self:skipEliminationAction() then
            return
        end
        self:checkDefBoard()
    end
end

function BattleControllerPVP:enterBattleStep()
    self.roundStep = BattleConst.BATTLE_ROUND_STEP.ON_TEAM_ACTION
    self:enterNextTeamAction()
end

function BattleControllerPVP:setCurActionSide(side)
    self.curActionSide = side or SIDE_ATK
    self:resduceSideActionCount(self.curActionSide)
end

function BattleControllerPVP:getSkillElementListRow()
    self.skillElementListRow = table.clearOrCreate(self.skillElementListRow)
    local min, max = self:getCurActionBoardRowRange()
    if self.curActionSide == SIDE_ATK then
        for row = max, min, -1 do
            table.insert(self.skillElementListRow, row)
        end
    else
        for row = min, max do
            table.insert(self.skillElementListRow, row)
        end
    end

    return self.skillElementListRow
end

function BattleControllerPVP:onFillBoardOver(...)
    --- 遍历
    local index = 1
    for posId, entity in pairs(self.battleData:getGridEnties()) do
        if self:getPosIdInCurActionBoardRowRange(posId) and entity:getSkillId() then
            if entity:getSkillSide() ~= self.curActionSide then
                local team = self:getSideTeam(self.curActionSide)
                local unitComp = team:getMainUnit()
                local skillMatchType = entity:getSkillMatchType()
                if skillMatchType then
                    local skillEntity = self.battleData:getSkillEntityByElement(skillMatchType, self.curActionSide)
                    if skillEntity then
                        entity:setSkilId(skillEntity:getSkillId(), false, self.curActionSide)
                        self.battleUI:playChangeElementSfx(posId, index)
                        index = index + 1
                        if unitComp.unitEntity then
                            if unitComp.unitEntity:getActiveSkillLimit() then
                                entity:setGridType(BattleConst.GRID_TYPE.LOCK)
                            else
                                entity:setGridType(BattleConst.GRID_TYPE.EMPTY)
                            end
                        else
                            entity:setGridType(BattleConst.GRID_TYPE.EMPTY)
                        end
                    end
                end
            end
        end
    end
    BattleBaseController.onFillBoardOver(self, ...)
end

function BattleControllerPVP:skipEliminationAction()
    local curActionUnitComp = self:getCurActionUnitComp()
    if curActionUnitComp:getIsLimit() then
        if curActionUnitComp:getIsFrozen() then
            GFunc.showToast(I18N:getGlobalText(I18N.GlobalConst.ARENA_BATTLE_DESC_4))
        elseif curActionUnitComp:getIsLethargy() then
            GFunc.showToast(I18N:getGlobalText(I18N.GlobalConst.ARENA_BATTLE_DESC_5))
        elseif curActionUnitComp:getIsStun() then
            GFunc.showToast(I18N:getGlobalText(I18N.GlobalConst.ARENA_BATTLE_DESC_3))
        end
        self:onLinkOverDone()
        return true
    end
    return false
end

function BattleControllerPVP:checkDefBoard()
    if self:getCurActionSide() == SIDE_DEF then
        local elementTypeCoefficient = {}
        local teamEntity = self.battleData:getDefTeam()
        local members = teamEntity:getAllMembers()
        for k, v in pairs(members) do
            elementTypeCoefficient[v:getMatchType()] = v:getAtk()
        end
        local path = board_heler:findPvpLinkOptimalSolution(self, 1, self:getAtkMinRow(), elementTypeCoefficient, self:getMinEliminationCount())
        if path and #path >= self:getMinEliminationCount() then
            if self.showCheckDefBoardSeq then
                self.showCheckDefBoardSeq:Kill()
                self.showCheckDefBoardSeq = nil
            end
            self.showCheckDefBoardSeq = self.battleUI.root:createBindTweenSequence()
            local lastPosId
            for index, posId in ipairs(path) do
                lastPosId = posId
                local time = index * 0.3
                self.showCheckDefBoardSeq:InsertCallback(time, function()
                    local eventType
                    if index == 1 then
                        eventType = GConst.ELIMINATION_TOUCH_EVENT.DOWN
                    else
                        eventType = GConst.ELIMINATION_TOUCH_EVENT.ENTER
                    end
                    self:onTouchEvent(eventType, posId)
                end)
            end
            self.showCheckDefBoardSeq:AppendInterval(0.5)
            self.showCheckDefBoardSeq:AppendCallback(function()
                self:onTouchEvent(GConst.ELIMINATION_TOUCH_EVENT.UP, lastPosId)
            end)
        else -- 没有找到，直接进入下一波
            self.battleUI:enterHideBoardAni(function()
                self:enterNextTeamAction()
            end)
        end
    end
end

function BattleControllerPVP:enterRoundBegin(...)
    local waveIndex = self:getWaveIndex()
    local nextWaveRound = (self.waveRoundCount[waveIndex] or 0) + 1
    if self:getMaxRoundCount() < nextWaveRound then -- 超过最大回合, 直接结算
        self.victory = false
        self:postWaveOver(false)
        self:battleEnd()
        return
    end
    local isFirstWaveFirstRound = false
    if waveIndex == 1 and nextWaveRound == 1 then
        isFirstWaveFirstRound = true
    end
    self:resetSideActionCount()
    self:setCurActionSide(SIDE_ATK)
    self.needWaitingBoardOver = nil
    self.waveRoundCount[waveIndex] = (self.waveRoundCount[waveIndex] or 0) + 1
    self.battleUI:enterShowBoardAni(function()
        self:enterEliminationBegin()
    end, isFirstWaveFirstRound)
    self.battleTeamActionList = table.clearOrCreate(self.battleTeamActionList)
    self:refreshWave()
end

function BattleControllerPVP:refreshWave()
    if not self.battleUI then
        return
    end
    self.battleUI:refreshWave(self.waveRoundCount[self:getWaveIndex()] or 0)
end

function BattleControllerPVP:getRandomGridInfo()
    local list, fixedRandomGrid = self:getInitBoard()
    local fixedRandomList = fixedRandomGrid[self.curBoardIndex]

    local gridType = 0
    local elementType
    if fixedRandomList and fixedRandomList[1] then
        elementType = table.remove(fixedRandomList, 1)
    else
        local map = self.battleData:getElementTypeMap()
        self.getRandomGridInfoIndexs = table.clearOrCreate(self.getRandomGridInfoIndexs)
        self.getRandomGridInfoTypeList = table.clearOrCreate(self.getRandomGridInfoTypeList)
        for typeName, typeNum in pairs(BattleConst.ELEMENT_TYPE) do
            if not self:getSealElementType()[typeNum] and self:getSkillEntityByElement(typeNum) then
                local weight = BattleConst.ELEMENT_WIGHT -- 改为平等权重
                if self.elementWeightMap and self.elementWeightMap[typeNum] then
                    weight = weight + self.elementWeightMap[typeNum]
                end
                if weight > BattleConst.MAX_ELEMENT_WIGHT then
                    weight = BattleConst.MAX_ELEMENT_WIGHT
                end
                table.insert(self.getRandomGridInfoIndexs, weight)
                table.insert(self.getRandomGridInfoTypeList, typeNum)
            end
        end

        local index = GFunc.getRandomIndex(self.getRandomGridInfoIndexs)
        elementType = self.getRandomGridInfoTypeList[index]
    end

    return {gridType = gridType, elementType = elementType}
end

return BattleControllerPVP