local BattleBoardTouchHelper = class("BattleBoardTouchHelper")
local BattleConst = GConst.BattleConst
local BOARD_RANGE_TYPE = BattleConst.BOARD_RANGE_TYPE
local ELIMINATION_TOUCH_EVENT = GConst.ELIMINATION_TOUCH_EVENT

local CLEAR_SEQUENCE_TIME = 1

function BattleBoardTouchHelper:init(battleController)
    self.battleController = battleController
    self.battleUI = battleController.battleUI
    self.battleData = battleController.battleData
end

function BattleBoardTouchHelper:onTouchEvent(eventType, posId, isVirtual)
    if self.battleController.roundStep ~= BattleConst.BATTLE_ROUND_STEP.ON_ELIMINATION then
        return
    end
    local entity = self.battleData:getGridEntity(posId)
    if not entity or not entity:canLink() then
        return
    end

    if eventType == ELIMINATION_TOUCH_EVENT.DOWN then
        self:onLinkStart(entity, posId, isVirtual)
        self.battleController:showTouchCancel()
    elseif eventType == ELIMINATION_TOUCH_EVENT.ENTER then
        if self.battleData:getIsVirtual() and not isVirtual then
            return
        end

        self:onLinkEnter(entity, posId, isVirtual)
    elseif eventType == ELIMINATION_TOUCH_EVENT.EXIT then

    else -- 取消和抬起
        self:onLinkCancelOrUp(entity, posId, isVirtual)
        self.battleController:hideTouchCancel()
    end
end

function BattleBoardTouchHelper:onLinkStart(entity, posId, isVirtual)
    if DataManager.TutorialData:getIsInTutorial() then
        local elementList = DataManager.TutorialData:getTargetElement()
        if elementList then
            local find = false
            for _, curPosId in ipairs(elementList) do
                if curPosId == posId then
                    find = true
                    break
                end
            end
            if not find then
                return
            end
        end
    end

    if not isVirtual then
        self.battleUI:showTutorialFinger()
    end
    if #self.battleData:getGridSequence() > 0 then
        self.battleController:clearGridSequence()
    end
    self.battleData:insertGridSequence(posId, self.battleController:snapshotBoard(), isVirtual)
    local skillEntity = self.battleController:getSkillEntityBySkillId(entity:getSkillId())
    local maskElementType = entity:getElementType(skillEntity)
    self.battleUI:showBoardMask(maskElementType, skillEntity and entity:getPosId())
    self.battleController:findSkillInfluenceGrids()
    self.battleController:onLinkChange()

    if not isVirtual then
        AudioManager:playEffect(AudioManager.EFFECT_ID.LINK_BO_1)
        if skillEntity then
            AudioManager:playEffect(AudioManager.EFFECT_ID.LINK_SKILL)
        end
    end

    self.clearSequenceTime = 0
end

function BattleBoardTouchHelper:onLinkEnter(entity, posId, isVirtual)
    local sequence = self.battleData:getGridSequence()
    local sequenceCount = #sequence
    local info = sequence[sequenceCount]
    local lastPosId = info and info.posId
    if not lastPosId then
        return
    end

    if not self:judgeGridEdgeCanLink(lastPosId, posId) then
        return
    end

    if self.battleData:alreadyInsertSequence(posId) and sequenceCount > 1 then
        local info = sequence[#sequence - 1]
        local beforePosId = info and info.posId
        if beforePosId == posId then -- 进入的是倒数第二个，则移除倒数第一个
            self:clearSequenceByPosId(beforePosId)
        else -- 如果不是倒数第二个，则记录时间
            self.clearSequencePosId = posId
            self.clearSequenceTime = CLEAR_SEQUENCE_TIME
        end
        return
    end
    self.clearSequenceTime = 0

    local outLineMap = BattleConst.GRID_OUT_LINE_POS_ID[lastPosId]
    if not outLineMap or not outLineMap[posId] then
        return
    end

    local skillId = entity:getSkillId()
    local skillEntity = self.battleController:getSkillEntityBySkillId(skillId)
    local elementType = entity:getElementType(skillEntity)

    local lastEntity = self.battleData:getGridEntity(lastPosId)
    local lastSkillId = lastEntity:getSkillId()
    local lastSkillEntity = self.battleController:getSkillEntityBySkillId(lastSkillId)
    local lastElementType = lastEntity:getElementType(lastSkillEntity)

    local hadSkillId, skillPosId = self.battleData:getSequenceHadSkill()
    if skillEntity and hadSkillId then
        return
    end

    if not elementType or not lastElementType then
    else
        if lastElementType ~= elementType then
            return
        end
    end

    local maskElementType = elementType or lastElementType
    if not skillPosId then
        if skillId then
            skillPosId = posId
        end
    end

    self.battleData:insertGridSequence(posId, self.battleController:snapshotBoard(), isVirtual)
    if lastEntity:getNeedChangePos() and not entity:getNeedChangePos() then -- 需要移动到队列末尾
        local lastSkillId = lastEntity:getSkillId()
        local skillId = entity:getSkillId()
        self.battleController:setGridSkillId(lastPosId, skillId)
        self.battleController:setGridSkillId(posId, lastSkillId)
        skillPosId = posId
    end

    local newElementType = elementType or lastElementType
    if newElementType then
        entity:setElementType(newElementType)
        lastEntity:setElementType(newElementType)
    end
    self.battleUI:showBoardMask(maskElementType, skillPosId)

    entity:addLinkSkillCount()

    self.battleController:findSkillInfluenceGrids()
    self.battleController:onLinkChange()

    if not isVirtual then
        if sequenceCount + 1 == self.battleController:getMinEliminationCount() then
            AudioManager:playEffect(AudioManager.EFFECT_ID.LINK_READY)
        end
        AudioManager:playEffect(AudioManager:getBoEffectID(sequenceCount + 1))
        if skillEntity then
            AudioManager:playEffect(AudioManager.EFFECT_ID.LINK_SKILL)
        end
    end
end

function BattleBoardTouchHelper:onLinkCancelOrUp(entity, posId, isVirtual)
    if isVirtual then
        return
    end

    local tutorialElementList
    if DataManager.TutorialData:getIsInTutorial() then
        tutorialElementList = DataManager.TutorialData:getTargetElement()
    end

    self.battleUI:showBoardMask(nil)
    local sequence = self.battleData:getGridSequence()
    local count = #sequence
    if count < self.battleController:getMinEliminationCount() then
        self.battleController:clearGridSequence()

        AudioManager:playEffect(AudioManager.EFFECT_ID.LINK_CANCEL)
        if tutorialElementList then
            self.battleUI:showTutorialFinger(tutorialElementList)
        end
        return
    end

    AudioManager:playEffect(AudioManager.EFFECT_ID.LINK_OVER)

    if tutorialElementList then
        local posIdmap = {}
        for _, info in ipairs(sequence) do
            posIdmap[info.posId] = true
        end
        EventManager:dispatchEvent(EventManager.CUSTOM_EVENT.ELIMINATION_OVER, posIdmap)
    else
        self.battleController:onLinkOver()
    end
end

function BattleBoardTouchHelper:tick(dt)
    if self.clearSequenceTime and self.clearSequenceTime > 0 then
        self.clearSequenceTime = self.clearSequenceTime - dt
        if self.clearSequenceTime <= 0 then
            self.clearSequenceTime = 0
            if self.clearSequencePosId and self.clearSequencePosId > 0 then
                self:clearSequenceByPosId(self.clearSequencePosId)
            end
        end
    end
end

function BattleBoardTouchHelper:clearSequenceByPosId(posId)
    if not posId then
        return
    end

    local sequence = self.battleData:getGridSequence()
    local targetIndex = 0
    for index, info in ipairs(sequence) do
        if info.posId == posId then
            targetIndex = index
            break
        end
    end
    targetIndex = targetIndex + 1
    if targetIndex <= 1 then -- 没找到
        return
    end

    local snapshot = self.battleData:removeGridSequenceByIndex(targetIndex)
    if not snapshot then
        return
    end

    for posId, info in pairs(snapshot) do
        self.battleData:setInfoBySnapshop(posId, info)
    end
    local gridEntity = self.battleData:getGridEntity(posId)
    local skillEntity = self.battleController:getSkillEntityBySkillId(gridEntity:getSkillId())
    local maskElementType = gridEntity:getElementType(skillEntity)

    local _, skillPosId = self.battleData:getSequenceHadSkill()
    self.battleUI:showBoardMask(maskElementType, skillPosId)

    self.battleController:findSkillInfluenceGrids()
    self.battleController:onLinkChange()
end

function BattleBoardTouchHelper:judgeGridEdgeCanLink(lastPosId, posId)
    if not posId or not lastPosId then
        return
    end

    local direction = ModuleManager.BattleManager:getPosDirection(lastPosId, posId)
    if direction == BOARD_RANGE_TYPE.UP then
        local entity = self.battleData:getGridEdgeEntity(lastPosId, BOARD_RANGE_TYPE.UP)
        if entity and not entity:getIsIdle() then
            return
        end
        entity = self.battleData:getGridEdgeEntity(posId, BOARD_RANGE_TYPE.DOWN)
        if entity and not entity:getIsIdle() then
            return
        end
    elseif direction == BOARD_RANGE_TYPE.DOWN then
        local entity = self.battleData:getGridEdgeEntity(lastPosId, BOARD_RANGE_TYPE.DOWN)
        if entity and not entity:getIsIdle() then
            return
        end
        entity = self.battleData:getGridEdgeEntity(posId, BOARD_RANGE_TYPE.UP)
        if entity and not entity:getIsIdle() then
            return
        end
    elseif direction == BOARD_RANGE_TYPE.LEFT then
        local entity = self.battleData:getGridEdgeEntity(lastPosId, BOARD_RANGE_TYPE.LEFT)
        if entity and not entity:getIsIdle() then
            return
        end
        entity = self.battleData:getGridEdgeEntity(posId, BOARD_RANGE_TYPE.RIGHT)
        if entity and not entity:getIsIdle() then
            return
        end
    elseif direction == BOARD_RANGE_TYPE.RIGHT then
        local entity = self.battleData:getGridEdgeEntity(lastPosId, BOARD_RANGE_TYPE.RIGHT)
        if entity and not entity:getIsIdle() then
            return
        end
        entity = self.battleData:getGridEdgeEntity(posId, BOARD_RANGE_TYPE.LEFT)
        if entity and not entity:getIsIdle() then
            return
        end
    elseif direction == BOARD_RANGE_TYPE.LEFT_UP then
        if not self:judgeGridEdgeCanLinkOblique(BOARD_RANGE_TYPE.UP, BOARD_RANGE_TYPE.LEFT, lastPosId, posId) then
            return
        end
    elseif direction == BOARD_RANGE_TYPE.RIGHT_UP then
        if not self:judgeGridEdgeCanLinkOblique(BOARD_RANGE_TYPE.UP, BOARD_RANGE_TYPE.RIGHT, lastPosId, posId) then
            return
        end
    elseif direction == BOARD_RANGE_TYPE.LEFT_DOWN then
        if not self:judgeGridEdgeCanLinkOblique(BOARD_RANGE_TYPE.DOWN, BOARD_RANGE_TYPE.LEFT, lastPosId, posId) then
            return
        end
    elseif direction == BOARD_RANGE_TYPE.RIGHT_DOWN then
        if not self:judgeGridEdgeCanLinkOblique(BOARD_RANGE_TYPE.DOWN, BOARD_RANGE_TYPE.RIGHT, lastPosId, posId) then
            return
        end
    end

    return true
end

function BattleBoardTouchHelper:judgeGridEdgeCanLinkOblique(verticalDirection, horizontalDirection, lastPosId, posId)
    local reverseVD = ModuleManager.BattleManager:getReverseDirection(verticalDirection)
    local reverseHD = ModuleManager.BattleManager:getReverseDirection(horizontalDirection)
    local entity1 = self.battleData:getGridEdgeEntity(lastPosId, horizontalDirection)
    local entity2 = self.battleData:getGridEdgeEntity(lastPosId, verticalDirection)
    if entity1 and entity2 and not entity1:getIsIdle() and not entity2:getIsIdle() then
        return
    end

    local entity3 = self.battleData:getGridEdgeEntity(posId, reverseHD)
    local entity4 = self.battleData:getGridEdgeEntity(posId, reverseVD)
    if entity3 and entity4 and not entity3:getIsIdle() and not entity4:getIsIdle() then
        return
    end

    if entity1 and entity3 and not entity1:getIsIdle() and not entity3:getIsIdle() then
        return
    end

    if entity2 and entity4 and not entity2:getIsIdle() and not entity4:getIsIdle() then
        return
    end

    local entity5, entity6
    local aroundId = ModuleManager.BattleManager:getPosByDirection(lastPosId, verticalDirection)
    if aroundId then
        entity5 = self.battleData:getGridEdgeEntity(aroundId, horizontalDirection)
        entity6 = self.battleData:getGridEdgeEntity(aroundId, reverseVD)
        if entity5 and entity4 and not entity5:getIsIdle() and not entity4:getIsIdle() then
            return
        end

        if entity1 and entity6 and not entity1:getIsIdle() and not entity6:getIsIdle() then
            return
        end

        if entity5 and entity1 and not entity5:getIsIdle() and not entity1:getIsIdle() then
            return
        end

        if entity6 and entity4 and not entity6:getIsIdle() and not entity4:getIsIdle() then
            return
        end
    end
    local aroundId = ModuleManager.BattleManager:getPosByDirection(lastPosId, horizontalDirection)
    if aroundId then
        local entity7 = self.battleData:getGridEdgeEntity(aroundId, reverseHD)
        local entity8 = self.battleData:getGridEdgeEntity(aroundId, verticalDirection)
        if entity7 and entity2 and not entity7:getIsIdle() and not entity2:getIsIdle() then
            return
        end

        if entity7 and entity6 and not entity7:getIsIdle() and not entity6:getIsIdle() then
            return
        end

        if entity8 and entity3 and not entity8:getIsIdle() and not entity3:getIsIdle() then
            return
        end

        if entity8 and entity5 and not entity8:getIsIdle() and not entity5:getIsIdle() then
            return
        end

        if entity8 and entity2 and not entity8:getIsIdle() and not entity2:getIsIdle() then
            return
        end

        if entity8 and entity6 and not entity8:getIsIdle() and not entity6:getIsIdle() then
            return
        end

        if entity7 and entity3 and not entity7:getIsIdle() and not entity3:getIsIdle() then
            return
        end

        if entity7 and entity5 and not entity7:getIsIdle() and not entity5:getIsIdle() then
            return
        end
    end

    return true
end

return BattleBoardTouchHelper