-- 绝对时间排行榜活动 中心服逻辑
local LuaMongo = _G.lua_mongo
local InnerMsg = require("core.InnerMsg")
local Util = require("common.Util")
local HtmlUtil = require("common.HtmlUtil")
local Lang = require("common.Lang")
local CommonDB = require("common.CommonDB")
local Msg = require("core.Msg")
local ObjHuman = require("core.ObjHuman")
local Broadcast = require("broadcast.Broadcast")
local Grid = require("bag.Grid")
local BagLogic = require("bag.BagLogic")
local ItemDefine = require("bag.ItemDefine")
local MiddleManager	= require("middle.MiddleManager")
local AbsActDefine = require("absAct.AbsActDefine")
local AbsActLogic = require("absAct.AbsActLogic")
local Log = require("common.Log")
local AbsActExcel = require("excel.absAct")
local RoleLogic = require("role.RoleLogic")
local DB = require("common.DB")
local Log = require("common.Log")
local MailManager = require("mail.MailManager")
local MiddleLogic = require("middle.MiddleLogic")
local MailExcel = require("excel.mail")
local Lang  = require("common.Lang")
local Broadcast = require("broadcast.Broadcast")
local YunYingLogic = require("yunying.YunYingLogic")

db = db or {}

-- 加载排行榜
function loadBoard()
    -- 角色
    local cnt = 0
    LuaMongo.find(DB.db_abs_billboard, fields)
    while true do
        local data = { }
        if not LuaMongo.next(data) then
            break
        end

        cnt = cnt + 1
        if cnt % 1000 == 0 then
            _G.collectgarbage("step", 100000)
        end

        -- 充值榜
        updateData(data, true)
    end

end

-- 启动后初始化
function initAfterStart()
    if _G.is_middle ~= true then return end

    loadBoard()
end

-- 初始data
function initData()
	local data = {}
	data.value1 = 0
	data.value2 = 0
	data.time = 0
	data.uuid = nil
	return data
end

-- 获取
function getBoard(mainId,actId, nosort)
	local board = db[mainId] and db[mainId][actId] or nil
    if not board then
        initBoard(mainId,actId)
        board = db[mainId] and db[mainId][actId] or nil
    end

	if board and board.dirty and (not nosort) then
		board.dirty = nil
		updateRank(board)
	end

	return board
end

-- 初始化
function initBoard(mainId,actId)
    db[mainId] = db[mainId] or {}
	local board = {}
	board.uuid2rank = {} 		-- 根据UUID获取名次		
	board.rank2data = {}			-- 根据名次获取DATA
	board.dirty = nil 			-- 是否改变过
	board.actId = actId 	-- 类型
	board.mainId = mainId 	-- 类型
	db[mainId][actId] = board
end

-- 刷新上榜时间
function refreshTime(data)
	data.billboard = data.billboard or {}
	data.billboard[data.mainId] = data.billboard[data.mainId] or {}
	data.billboard[data.actId] = os.time()
end

-- 获取上榜时间
function getTime(data)
	if not data.billboard or not data.billboard[data.mainId] then
		return
	end
	return data.billboard[data.mainId][data.actId]
end

-- 排序
function updateRank(board)
	if not board then return end
	for uuid in pairs(board.uuid2rank) do
		board.uuid2rank[uuid] = nil
	end
	for rank, data in ipairs(board.rank2data) do
		board.uuid2rank[data.uuid] = rank
	end
end

-- 获取排名名次
function getRank(mainId,actId, uuid)
    local board = getBoard(mainId,actId)
    if not board then return end
    return board.uuid2rank[uuid]
end

-- 根据名次获取信息
function getRankData(mainId,actId, rank)
    local board = getBoard(mainId,actId)
    if not board then return end
    return board.rank2data[rank]
end

-- 排名值
function getValues(db)
    return db.param
end

-- 比较
function cmpValues(data1, data2)
    if data1.value1 ~= data2.value1 then
        return data1.value1 > data2.value1
    end
    if data1.value2 ~= data2.value2 then
        return data1.value2 > data2.value2
    end
    if (data1.time or 0) ~=(data2.time or 0) then
        return(data1.time or 0) <(data2.time or 0)
    end
    return true
end

-- 设置值
function setValues(tempData, data, value1, value2)
    tempData.uuid = data.uuid
    tempData.value1 = value1
    tempData.value2 = value2 or 0
    tempData.time = getTime(data)
end

--
local TempData = nil
function updateData(data, isInit)
    local board = getBoard(data.mainId,data.actId, isInit)
    if not board then return end

    local value1 = getValues(data)
    if not value1 then return end

    local dbrank = board.uuid2rank[data.uuid]
    local dbdata = dbrank and board.rank2data[dbrank]
    if dbdata then
        if dbdata.value1 == value1 and dbdata.value2 ==(value2 or 0) then
            return
            -- 优化，原来值跟新值一样
        end
        table.remove(board.rank2data, dbrank)
    end

    if not isInit then
        -- 刷新上榜时间
        refreshTime(data)
    end

    local maxRank = #board.rank2data
    local rank = maxRank + 1
    TempData = TempData or initData()
    setValues(TempData, data, value1, value2)
    for i = maxRank, 1, -1 do
        local tdata = board.rank2data[i]
        if cmpValues(tdata, TempData) then
            break
        end
        board.rank2data[i + 1] = tdata
        rank = i
    end

    if rank > AbsActDefine.BILLBOARD_MAX_CNT then return end
    local data2 = nil
    if maxRank < AbsActDefine.BILLBOARD_MAX_CNT then
        data2 = initData()
    else
        data2 = board.rank2data[AbsActDefine.BILLBOARD_MAX_CNT + 1]
    end
    setValues(data2, data, value1, value2)
    board.rank2data[rank] = data2
    board.rank2data[AbsActDefine.BILLBOARD_MAX_CNT + 1] = nil
    if rank ~= dbrank then
        board.dirty = true
    end
    return true
end



-----------------------------------------------------------------------
--绝对时间活动 数据库操作 -start
local tempTb = {}
local queryByUuid = { uuid = nil }
local auTb = {}
local billboardData = {}

-- 加入队列
function add(msg)
	Util.cleanTable(auTb)
    auTb.uuid = msg.roleBase.uuid
    auTb.roleBase = {}
	RoleLogic.makeRoleBase(msg.roleBase,auTb.roleBase)
    auTb.svrIndex = msg.svrIndex
    auTb.svrName = msg.svrName
    auTb.mainId = msg.mainId
    auTb.actId = msg.actId

    local data = query(msg.roleBase.uuid)
    if data ~= nil then
		queryByUuid.uuid = msg.roleBase.uuid
		tempTb["$set"] = nil
        tempTb["$set"] = auTb
        LuaMongo.update(DB.db_abs_billboard, queryByUuid, tempTb)
        return auTb
    end
	LuaMongo.insert(DB.db_abs_billboard, auTb)

    return auTb
end

-- 查询队列
function query(uuid, fileds)
    queryByUuid.uuid = uuid
    local data={}
    LuaMongo.find(DB.db_abs_billboard, queryByUuid, fileds)
	if not LuaMongo.next(data) then
		return nil
	end
    return data
end

-- 更新
function chargeUpdate(uuid, param,actId,mainId)
	queryByUuid.uuid = uuid
	local updateTb = {["param"] = param,["actId"] = actId,["mainId"] = mainId}
	tempTb["$set"] = nil
	tempTb["$set"] = updateTb
	LuaMongo.update(DB.db_abs_billboard, queryByUuid, tempTb)
end


--绝对时间活动 数据库操作  -end


------------------------------------------------------------------------
--绝对时间 排行榜  start
function billboardSet(fd, msg)
   -- 加入数据库
   local data = add(msg)
   -- 更新数据
  
   chargeUpdate(msg.roleBase.uuid, msg.op.param,msg.actId,msg.mainId)

   data.param = msg.op.param

   updateData(data)
end


function LW_ABS_ACT_BILLBOARD_DB(fd,msg)
    local board = getBoard(msg.mainId,msg.actId)
    if not board then
        return
    end 
    local msgRet = InnerMsg.wl.WL_ABS_ACT_BILLBOARD_DB_RETURN
    msgRet.actId = msg.actId
    msgRet.mainId = msg.mainId
    msgRet.rankDb = Util.copyTable(board)
    InnerMsg.sendMsg(fd,msgRet)
end


-- 数据查询
function billboardQuery(fd, msg)
    local board = getBoard(msg.mainId,msg.actId)
    if board == nil then
        return
    end

    local boardLen = #board.rank2data
    boardLen = math.min(boardLen, AbsActDefine.BILLBOARD_MAX_CNT)

    local msgRet = InnerMsg.wl.WL_ABS_ACT_BILLBOARD_QUERY
    msgRet.uuid = msg.uuid
    msgRet.actId = msg.actId
    msgRet.mainId = msg.mainId
    msgRet.list = {}
    local len = 0
    for i = 1, boardLen do
        local data = board.rank2data[i]
        local uuid = data and data.uuid

        local db = query(uuid, fields)

        len = len + 1

        msgRet.list[len] = {}
        local net = msgRet.list[len]
        net.roleBase = net.roleBase or {}
		RoleLogic.makeRoleBase(db.roleBase,net.roleBase)
        net.rank = i
        net.param = db.param
        net.svrName = db.svrName
    end

    msgRet.list[0] = len

    InnerMsg.sendMsg(fd, msgRet)
end

--[[
function billboardReward()
    --
    for k,v in pairs(db) do
        local state, endTime, starTime = AbsActLogic.isStarted(human, k)
        local absConfig = AbsActExcel.absActivity[k]
        for actId,data in pairs(v) do
            -- 如果活动开启状态为未开启，或者排行榜数据活动ID与当前开启活动ID不一致，则认为排行榜中活动已结束，该发放奖励
            if actId ~= absConfig.actId or not state then 
                local config = Util.copyTable(AbsActExcel.billboard)
                if not config then return end
                local boardLen = #data.rank2data
                local configLen = #config
                if boardLen > 0 then
                    boardLen = math.min(boardLen, AbsActDefine.BILLBOARD_MAX_CNT)
                    for i = 1, boardLen do
                        local dbData = board.rank2data[i]
                        local uuid = dbData and dbData.uuid

                        local pDb = query(uuid, fields)
                        local dcId = 0
                        
                        -- 选出所在档次
                        for i = 1,configLen do
                            if config[i].actId == actId and config[i].mainId == k then
                                if pDb.param >= config[i].param and config[i].cnt > 0 then
                                    if dcId == 0 then
                                        dcId = i
                                    else
                                        dcId = dcId > i and i or dcId
                                    end
                                end
                            end
                        end

                        if dcId ~= 0 then
                            config[dcId].cnt = config[dcId].cnt - 1
                         	local mailConfig = MailExcel.mail[config[dcId].mailId]
		                    local title = mailConfig.title
		                    local senderName = mailConfig.senderName
                            local content = Util.format(mailConfig.content, pDb.param, rank)
                            MiddleLogic.sendWLMail(MailManager.SYSTEM, uuid, title, content, config[dcId].reward, senderName, pDb.svrIndex)
                        else
                            Log.write(Log.LOGID_DEBUG, "billboardReward: "..dcId.." uuid: "..uuid.." rank: "..i)
                        end
                    end
                    initBoard(id)
                end
                -- 清空数据库
                LuaMongo.remove(DB.db_abs_billboard,{["mainId"] = k,["actId"] = actId})
            end
        end
    end
end]]

function LW_ABS_ACT_BILLBOARD_DB_CLEAN(fd,msg)
    initBoard(msg.mainId,msg.actId)
    LuaMongo.remove(DB.db_abs_billboard,{["mainId"] = msg.mainId,["actId"] = msg.actId})
end