--新商业化活动——秘境翻牌
--db
--[=[
    human.db.absAct[id] = {
        freeCnt = nil, 当日免费抽取次数，为0时表示没有，为其他表示可以免费抽取一次
        normalAwardIdxTbl --普通奖励,value为配置表的Index
        normalAwardRecord = { --普通奖励获得记录，key为 normalAwardIdxTbl 中的索引，有值则表示获得了
            [1] = '1',
            [3] = '1',
        }，

        lineAwardIdxTbl= = nil,  --当前横排(上方)大奖Index列表, value为配置表的Index
        lineAwardRecord = {  --横排大奖(上方)获得记录，key为 lineAwardRecord 中的索引，有值则表示获得了
            [1] = '1',
            [3] = '1',
        },

        rowAwardIdxTbl = nil,  --当前竖排(右边)大奖Index列表, value为配置表的Index
        rowAwardRecord = {  --竖排大奖(右边)获得记录，key为 rowAwardIdxTbl 中的索引，有值则表示获得了
            [1] = '1',
            [3] = '1',
        }
    }
]=]--

local Msg = require("core.Msg")
local Grid = require("bag.Grid")
local BagLogic = require("bag.BagLogic")
local AbsActLogic = require("absAct.AbsActLogic")
local Broadcast = require("broadcast.Broadcast")
local Lang = require("common.Lang")
local AbsActExcel = require("excel.absAct")
local YunYingLogic = require("yunying.YunYingLogic")
local ItemDefine = require("bag.ItemDefine")
local TriggerDefine = require("trigger.TriggerDefine")
local TriggerLogic = require("trigger.TriggerLogic")
local CycleActivityLogic = require("yunying.CycleActivity")

local LOGTAG = "AbsLotteryCardLogic"    --日志标识
local LOTTERYCOSTTYPE = ItemDefine.ITEM_ZUANSHI_ID --抽奖消耗道具ID
local LOTTERY1COSTCNT = 400            --单抽消耗的数量
local LOTTERY10COSTCNT = 4000          --十连消耗的数量
local RESETCOSTCNT = 1000               --重置需要消耗的数量
local FOUR = 4

--是否是GM模式, 为true时, 每次抽取只会获得没有抽到的奖励, 抽够一定次数, 则一定会获得所有奖励
local isGmMode = false


--生成奖励
local function generateAwardByWeight(awardConfig, awardNum)
    local totalWeight = 0
    for _, v in pairs(awardConfig) do
        totalWeight = totalWeight + v[3]
    end

    local weight, randWeight = 0, 0
    local awardIdxTbl = {}

    for i=1, awardNum do
        weight = 0
        randWeight = math.random(0, totalWeight)
        for idx, cfg in ipairs(awardConfig) do
            weight = weight + cfg[3]
            if randWeight <= weight then
                awardIdxTbl[i] = idx
                break
            end
        end
    end
    return awardIdxTbl
end

--封装奖励协议数据结构
local function populateAwardMsg(net, awardCfg, awardRecordData, indexTbl)
    net[0] = #indexTbl
    for k, awardIdx in ipairs(indexTbl) do
        net[k].idx = k
        net[k].getState = 0

        if awardRecordData and awardRecordData[k] then
            net[k].getState = 1
        end

        local itemInfo = awardCfg[awardIdx]
        Grid.makeItem(net[k].item, itemInfo[1], itemInfo[2])
    end
end

--封装协议数据结构
local function populateMsg(msgRet, actData)
    msgRet.freeCnt = 0
    local freeCnt = actData.freeCnt
    if not freeCnt or freeCnt ~= 0 then
        msgRet.freeCnt = 1
    end

    local config = AbsActExcel.AbsLotteryCardLogic
    --普通奖励
    populateAwardMsg(msgRet.normalAwardInfo, config[1].award, actData.normalAwardRecord, actData.normalAwardIdxTbl)

    --横排大奖
    populateAwardMsg(msgRet.lineAwardInfo, config[2].award, actData.lineAwardRecord,  actData.lineAwardIdxTbl)

    --竖排大奖
    populateAwardMsg(msgRet.rowAwardInfo, config[3].award, actData.rowAwardRecord, actData.rowAwardIdxTbl)
end

--计算一个值在4 x 4 矩阵中 横排和竖排的位置
local function calcLineRowPos(num)
    local linePos, rowPos = 0, 0

    rowPos = num % FOUR
    if rowPos == 0 then
        rowPos = FOUR
    end

    linePos = math.ceil(num / FOUR)
    return linePos, rowPos
end

--判断是否获得横排(上方)大奖
local function isGetLineAward(pos, awardRecordData)
    -- if pos % FOUR == 0 then
    --     pos = FOUR
    -- end

    local isGet = true
    for i=1, FOUR do
        if not awardRecordData[pos] then
            isGet = false
            break
        end
        pos = pos + FOUR
    end
    return isGet
end

--判断是否获得竖排(右边)大奖
local function isGetRowAward(pos, awardRecordData)
    local isGet = true
    local startPos = (pos- 1) * FOUR + 1
    for i=1, FOUR do
        if not awardRecordData[startPos] then
            isGet = false
            break
        end
        startPos = startPos + 1
    end
    return isGet
end

--是否需要重置奖励
local function isReset(lineTbl, rowTbl)
    local lineNum, rowNum = 0,0
    for _,_ in pairs(lineTbl or {}) do
        lineNum = lineNum + 1
    end

    if lineNum < FOUR then
        return false
    end

    for _,_ in pairs(rowTbl or {}) do
        rowNum = rowNum + 1
    end

    if rowNum < FOUR then
        return false
    end
    return true
end

--随机普通奖励,返回的是normalAwardIdxTbl的key
local function randAwardIdx(normalAwardIdxTbl, normalAwardRecord, normalAwardCfg)
    local weight, randIdx, randWeight, totalWeight = 0,0,0,0
    local len = 0
    local subAwardIdxVec = {}

    for i, cfgIndex in ipairs(normalAwardIdxTbl) do
        if isGmMode and normalAwardRecord then     --GM模式随机,剔除掉已经获得的奖励, 在剩下奖励中随机
            if not normalAwardRecord[i] then
                len = len + 1
                totalWeight = totalWeight + normalAwardCfg[cfgIndex][3]
                subAwardIdxVec[len] = {normalAwardCfg[cfgIndex][3], i}
            end
        else
            len = len + 1
            totalWeight = totalWeight + normalAwardCfg[cfgIndex][3]
            subAwardIdxVec[len] = {normalAwardCfg[cfgIndex][3], i}
        end
    end

    randWeight = math.random(0, totalWeight)
    for _, data in ipairs(subAwardIdxVec) do
        weight = weight + data[1]
        if randWeight <= weight then
            randIdx = data[2]
            break
        end
    end

    return randIdx
end

--重置奖励
local function reset(actData)
    actData.normalAwardRecord = nil
    actData.lineAwardRecord = nil
    actData.rowAwardRecord = nil

    local config = AbsActExcel.AbsLotteryCardLogic
    actData.lineAwardIdxTbl = generateAwardByWeight(config[2].award, FOUR)
    actData.rowAwardIdxTbl = generateAwardByWeight(config[3].award, FOUR)
end

--抽奖
local function lottery(human, actData, lotteryCnt, awardVec)
    local config = AbsActExcel.AbsLotteryCardLogic
    local normalAwardCfg = config[1].award
    local normalAwardRecord = actData.normalAwardRecord
    local normalAwardIdxTbl = actData.normalAwardIdxTbl

    local subCnt = -1
    local randPosList = {}
    --local isRepeat = false
    local repeatPosList = {}
    local getNormalAwardCnt = 0
    if normalAwardRecord then
        for _,_ in pairs(normalAwardRecord) do
            getNormalAwardCnt = getNormalAwardCnt + 1
        end
    end

    for i=1, lotteryCnt do
        local randPos = randAwardIdx(normalAwardIdxTbl, normalAwardRecord, normalAwardCfg)
        randPosList[#randPosList+1] = randPos
        local cfgIndex = normalAwardIdxTbl[randPos]
        local itemInfo = normalAwardCfg[cfgIndex]
        awardVec[#awardVec+1] = {itemInfo[1], itemInfo[2]}

        getNormalAwardCnt = getNormalAwardCnt + 1

        --当前抽得普通奖励大于4个且之前未抽到过该位置的奖励
        if getNormalAwardCnt >= FOUR and not normalAwardRecord[randPos] then
            local linePos, rowPos = calcLineRowPos(randPos)
            local lineAwardRecord = actData.lineAwardRecord
            local rowAwardRecord = actData.rowAwardRecord

            --更新普通奖励获得记录
            normalAwardRecord[randPos] = '1'

            local isGetLine, isGetRow = false, false

            --是否获得横排(上方的)大奖
            if not lineAwardRecord or not lineAwardRecord[rowPos] then
                isGetLine = isGetLineAward(rowPos, normalAwardRecord)
                if isGetLine then
                    local cfgIdx = actData.lineAwardIdxTbl[rowPos]
                    local lineAwardItem = config[2].award[cfgIdx]
                    awardVec[#awardVec+1] = {lineAwardItem[1], lineAwardItem[2]}
                    actData.lineAwardRecord = actData.lineAwardRecord or {}
                    actData.lineAwardRecord[rowPos] = '1'
                end
            end

            --是否获得竖排(右方的)大奖
            if not rowAwardRecord or not rowAwardRecord[linePos] then
                isGetRow = isGetRowAward(linePos, normalAwardRecord)
                if isGetRow then
                    local cfgIdx = actData.rowAwardIdxTbl[linePos]
                    local rowAwardItem = config[3].award[cfgIdx]
                    awardVec[#awardVec+1] = {rowAwardItem[1], rowAwardItem[2]}
                    actData.rowAwardRecord = actData.rowAwardRecord or {}
                    actData.rowAwardRecord[linePos] = '1'
                end
            end

            --是否所有奖励都领完, 需要重置奖励
            if isGetLine or isGetRow then
                if isReset(actData.lineAwardRecord, actData.rowAwardRecord) then
                    reset(actData)

                    subCnt = lotteryCnt - i
                    break
                end
            end
        else
            if normalAwardRecord and normalAwardRecord[randPos] then
                --isRepeat = true
                repeatPosList[#repeatPosList+1] = randPos
            else
                normalAwardRecord = normalAwardRecord or {}
                normalAwardRecord[randPos] = '1'
                actData.normalAwardRecord = normalAwardRecord
            end
        end
    end
    return randPosList, repeatPosList, subCnt
end


--GM接口，设置本活动是否使用GM模式, val > 0 表示使用GM模式
function SetMode(val)
    if val > 0 then
        isGmMode = true
    else
        isGmMode = false
    end
end

function isOpen(human, YYInfo, funcConfig)
    -- local state, endTime, startTime = AbsActLogic.isStarted(human, funcConfig.funcID)
    local state, endTime, startTime = CycleActivityLogic.isStarted(human, funcConfig.funcID)
    return state, endTime, startTime
end

function isActive(human, YYInfo, funcConfig)
    local state = isOpen(human, YYInfo, funcConfig)
    return not state
end

--红点判断
function isRed(human, YYInfo, funcConfig)
    local actData = human.db.absAct[funcConfig.funcID]
    if not actData then
        return false
    end

    local freeCnt = actData.freeCnt
    if freeCnt and freeCnt == 0 then
        return false
    end

    return true
end

--跨天函数
function updateDaily(human, id)
    -- local state = AbsActLogic.isStarted(human, id)
    local state = CycleActivityLogic.isStarted(human, id)

    if not state then
        return
    end

    local actData = human.db.absAct[id]
    if not actData then
        return
    end

    actData.freeCnt = 1

    --红点刷新
    YunYingLogic.sendBanner(human)
    local config = AbsActExcel.absActivity[id]
    YunYingLogic.sendGroupUpdate(YYInfo[id], human, config.panelID)
end

--查询
function Query(human, id)
    -- local state = AbsActLogic.isStarted(human, id)
    local state = CycleActivityLogic.isStarted(human, id)
    if not state then
        return Broadcast.sendErr(human, Lang.YUNYING_ERR_TIME)
    end

    local actData = human.db.absAct[id]
    if not actData then
        return Broadcast.sendErr(human, Lang.YUNYING_ERR_TIME)
    end

    local msgRet = Msg.gc.GC_LOTTERYCARD_QUERY

    local config = AbsActExcel.AbsLotteryCardLogic
    if not actData.lineAwardIdxTbl then
        actData.lineAwardIdxTbl = generateAwardByWeight(config[2].award, FOUR)
        actData.rowAwardIdxTbl = generateAwardByWeight(config[3].award, FOUR)
        actData.normalAwardIdxTbl = generateAwardByWeight(config[1].award, 16)
    end

    populateMsg(msgRet, actData)

    Grid.makeItem(msgRet.lottery1Spend, LOTTERYCOSTTYPE, LOTTERY1COSTCNT)
    Grid.makeItem(msgRet.lottery10Spend, LOTTERYCOSTTYPE, LOTTERY10COSTCNT)
    Grid.makeItem(msgRet.resetSpend, LOTTERYCOSTTYPE, RESETCOSTCNT)

    Msg.send(msgRet, human.fd)
end

--抽奖, 可抽到重复奖励, 某行/列的普通奖励都获得时,自动获得对应行列的大奖，所有普通和大奖都获得时，重置奖励
function Lottery(human, id, lotteryCnt)
    -- local state = AbsActLogic.isStarted(human, id)
    local state = CycleActivityLogic.isStarted(human, id)
    if not state then
        return Broadcast.sendErr(human, Lang.YUNYING_ERR_TIME)
    end

    local actData = human.db.absAct[id]
    if not actData then
        return Broadcast.sendErr(human, Lang.YUNYING_ERR_TIME)
    end

    if lotteryCnt ~= 1 and lotteryCnt ~= 10 then
        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
    end

    local itemSpendCnt = LOTTERY1COSTCNT
    if lotteryCnt == 1 then
        if not actData.freeCnt or actData.freeCnt ~= 0 then
            itemSpendCnt = 0
            actData.freeCnt = 0
        end
    else
        itemSpendCnt = LOTTERY10COSTCNT
    end

    if itemSpendCnt > 0 then
        if BagLogic.getItemCnt(human, LOTTERYCOSTTYPE) < itemSpendCnt then
            return Broadcast.sendErr(human, Lang.COMMON_ITEM_NOT_ENOUGH)
        end
        --扣消耗
        BagLogic.delItem(human, LOTTERYCOSTTYPE, itemSpendCnt, LOGTAG)
    end

    --抽奖
    local awardVec = {}
    local randPosList, repeatPosList, subCnt = lottery(human, actData, lotteryCnt, awardVec)

    --全部奖励已获得，还有抽奖次数，需要先重置奖励
    if subCnt > 0 then
        local msgRet = Msg.gc.GC_LOTTERYCARD_RESET
        msgRet.isActive = 1
        populateMsg(msgRet, actData)
        Msg.send(msgRet, human.fd)

        randPosList, repeatPosList = lottery(human, actData, subCnt, awardVec)
    end
    --发放抽到的道具
    BagLogic.addItemList(human, awardVec, LOGTAG)

    local config = AbsActExcel.AbsLotteryCardLogic
    local awardCfg = config[1].award

    local msgRet = Msg.gc.GC_LOTTERYCARD_LOTTERY
    local normalAwardInfo = msgRet.normalAwardInfo
    normalAwardInfo[0] = #randPosList

    --小奖卡牌重复被翻到后，更换该牌的奖励
    local  normalAwardIdxTbl = actData.normalAwardIdxTbl
    local newAwardPosList = generateAwardByWeight(config[1].award, #randPosList)

    for i, dbIdx in ipairs(repeatPosList) do
        --print(string.format("重复随机到奖励位置: %d, 新奖励在配置中位置: %d\n", dbIdx, newAwardPosList[i]))
        local cfgIdx = newAwardPosList[i]
        normalAwardIdxTbl[dbIdx] = cfgIdx
    end


    for i, dbIdx in ipairs(randPosList) do
        normalAwardInfo[i].idx = dbIdx
        normalAwardInfo[i].getState = 1

        local cfgIdx = normalAwardIdxTbl[dbIdx]
        local itemInfo = awardCfg[cfgIdx]
        Grid.makeItem(normalAwardInfo[i].item, itemInfo[1], itemInfo[2])
    end


    --下发数据
    msgRet.isRepeat = #repeatPosList > 0 and 1 or 0
    msgRet.freeCnt = 0
    local freeCnt = actData.freeCnt
    if not freeCnt or freeCnt ~= 0 then
        msgRet.freeCnt = 1
    end

    --普通奖励
    --populateAwardMsg(msgRet.normalAwardInfo, config[1].award, actData.normalAwardRecord, actData.normalAwardIdxTbl)

    --横排大奖
    populateAwardMsg(msgRet.lineAwardInfo, config[2].award, actData.lineAwardRecord, actData.lineAwardIdxTbl)

    --竖排大奖
    populateAwardMsg(msgRet.rowAwardInfo, config[3].award, actData.rowAwardRecord, actData.rowAwardIdxTbl)

    Msg.send(msgRet, human.fd)

    -- for i, idx in ipairs(randIds) do
    --     local cfgIdx = newAwardPosList[i]
    --     normalAwardIdxTbl[idx] = cfgIdx
    -- end

    --全部奖励已获得，没有抽奖次数，最后重置奖励
    if subCnt == 0 then
        local msgRet = Msg.gc.GC_LOTTERYCARD_RESET
        msgRet.isActive = 1
        populateMsg(msgRet, actData)
        Msg.send(msgRet, human.fd)

        -- 代表秘境翻盘完成一次？
        TriggerLogic.PublishEvent(TriggerDefine.SECRET_REALM, human.db._id, 1)
    end


    --更新红点
    if itemSpendCnt <= 0 then
        YunYingLogic.sendBanner(human)
        local config = AbsActExcel.absActivity[id]
        YunYingLogic.sendGroupUpdate(YYInfo[id], human, config.panelID)
    end
end

--重置
function ResetAward(human, id)
    -- local state = AbsActLogic.isStarted(human, id)
    local state = CycleActivityLogic.isStarted(human, id)
    if not state then
        return Broadcast.sendErr(human, Lang.YUNYING_ERR_TIME)
    end

    local actData = human.db.absAct[id]
    if not actData then
        return Broadcast.sendErr(human, Lang.YUNYING_ERR_TIME)
    end

    if BagLogic.getItemCnt(human, LOTTERYCOSTTYPE) < RESETCOSTCNT then
        return Broadcast.sendErr(human, Lang.COMMON_ITEM_NOT_ENOUGH)
    end
    --扣消耗
    BagLogic.delItem(human, LOTTERYCOSTTYPE, RESETCOSTCNT, LOGTAG)

    --重置
    reset(actData)

    --下发数据
    local msgRet = Msg.gc.GC_LOTTERYCARD_RESET
    msgRet.isActive = 0
    populateMsg(msgRet, actData)
    Msg.send(msgRet, human.fd)
end