local Msg = require("core.Msg")
local Util = require("common.Util")
local Grid = require("bag.Grid")
local ItemDefine = require("bag.ItemDefine")
local TuJianExcel = require("excel.equip").tujian
local EquipExcel = require("excel.equip").equip
local ItemExcel = require("excel.item").item
local EquipLogicGrid = require("equip.EquipLogicGrid")
local Log = require("common.Log")
local LogDefine = require("common.LogDefine")
local Lang  = require("common.Lang")
local Broadcast = require("broadcast.Broadcast")
local MailManager = require("mail.MailManager")
local MailExcel = require("excel.mail")
local HeroLogic = require("hero.HeroLogic")
local TriggerDefine = require("trigger.TriggerDefine")
local TriggerLogic = require("trigger.TriggerLogic")
local effectCfg = require("excel.equip").texiao
local HeroDefine = require("hero.HeroDefine")

EQUIP_BAG_MAX_CNT = 500
EQUIP_BAG_OP_ADD = 1 -- 增
EQUIP_BAG_OP_DEL = 2 -- 删
EQUIP_BAG_OP_CHANGE = 3 -- 改

EQUIP_QUALITY_MAX = 5
EQUIP_QUALITY = { 5000, 3000, 1500, 500 }
EQUIP_QUALITY_WEIGHT = 10000
EQUIP_QUALITY_BASE_RATE = { 7000, 8000, 9000, 10000, 12000 }


local EQUIP_HEROEXCLUSIVE_WEIGHT = 4000         --戒指、护符随机出英雄专属属性权重
local EQUIP_NO_HEROEXCLUSIVE_WEIGHT = 6000      --戒指、护符随不出英雄专属属性权重

-- 转换装备洗练数据格式
function AttrHashToArray(attrData)
    local _,  attrInfo = next(attrData)
    if type(attrInfo) == "table" then
        return attrData
    end


    local len = 0
    local attrArray = {}
    for attrType, attrVal in pairs(attrData) do
        len = len + 1
        attrArray[len] = {attrType, attrVal, EquipLogicGrid.EQUIP_COLOR_3}
    end
    return attrArray
end




-- 随出单条洗练属性的品质 和 倍数
local function randAttrValMul()
    local totalWeight = 0
    for _, weight in ipairs(EquipLogicGrid.EQUIPWASH_COLOR_WEIGHT) do
        totalWeight = totalWeight + weight
    end

    local color = 0
    local mul = 0
    local randNum = math.random(1, totalWeight)

    local weight = 0
    for k, v in ipairs(EquipLogicGrid.EQUIPWASH_COLOR_WEIGHT) do
        weight = weight + v
        if randNum <= weight then
            color = k
            break
        end
    end

    assert(color > 0, "============装备洗练配置错误===============")

    local mulTbl = EquipLogicGrid.EQUIPWASH_COLOR_MUL[color]
    mul = math.random(mulTbl[1], mulTbl[2]) / 100
    return color, mul
end

-- 随机装备品质
local function randColor(randomAttrCfg)
    local color = 0
    local random = math.random(1, EQUIP_QUALITY_WEIGHT)
    for i = 1, #EQUIP_QUALITY do
        local weight = EQUIP_QUALITY[i]
        if random <= weight then
            color = i > #randomAttrCfg and #randomAttrCfg or i
            break
        else
            random = random - weight
        end
    end
    return color
end


-- 随机出装备洗练属性
local function randAttrArray(randomAttrCfg, equipColor, excludeAttrList)
    --品质
    equipColor = equipColor or randColor(randomAttrCfg)

    -- 排除特定属性
    if excludeAttrList then
        for idx, attrInfo in pairs(randomAttrCfg) do
            local attrType = attrInfo[1]
            if excludeAttrList[attrType] then
                randomAttrCfg[idx] = nil
            end
        end
    end


    -- 计算总权重
    local totalWeight = 0
    for k, v in pairs(randomAttrCfg) do
        totalWeight = totalWeight + v[3]
    end

    local len = 0
    local attr = {}
    local MathRandom = math.random

    -- for i = 1, equipColor do
    --     local weight = 0
    --     local randmWeight = MathRandom(1, totalWeight)
    --     for _, v in ipairs(randomAttrCfg) do
    --         weight = weight + v[3]
    --         if randmWeight <= weight then
    --             len = len + 1
    --             local attrColor, mul = randAttrValMul()
    --             local finalVal = math.floor(v[2] * mul)
    --             attr[len] = {v[1], finalVal, attrColor}
    --             break
    --         end
    --     end
    -- end

    for z = 1, equipColor do
        local randmWeight = MathRandom(1, totalWeight)
        for k, v in pairs(randomAttrCfg) do
            local key = v[1]
            local value = v[2]
            local weight = v[3]
            if randmWeight <= weight then
                len = len + 1

                local attrColor, mul = randAttrValMul()
                local finalVal = math.floor(value * mul)
                attr[len] = {key, finalVal, attrColor}

                randomAttrCfg[k] = nil
                -- 排除这个权重
                totalWeight = totalWeight - weight
                break
            else
                randmWeight = randmWeight - weight
            end
        end
    end



    return attr
end

---------------------------------------------------------戒指、护符随机特效---------------------------------------------------

local function generateRandData(excludeTypeList)
    local totalWeight = 0
    local type2List = {}

    for k,v in ipairs(effectCfg) do
        local tp = v.type
        if not excludeTypeList or not excludeTypeList[tp] then
            local weight = v.weight
            type2List[tp] = type2List[tp] or {weight = 0, typeList = {}}
            type2List[tp].weight = type2List[tp].weight + weight
            table.insert(type2List[tp].typeList, {id = k, weight = weight})
            totalWeight = totalWeight + weight
        end
    end

    local len = 0
    local randList = {}
    for _, tpData in pairs(type2List) do
        len = len + 1
        randList[len] = tpData
    end

    return totalWeight, randList
end

local function getIndexByRand(totalWeight, randList)
    local tpList
    local weight = 0
    local randWeight = math.random(0, totalWeight)
    for _,v in ipairs(randList) do
        weight = weight + v.weight
        if randWeight <= weight then
            tpList = v
            break
        end
    end

    weight = 0
    randWeight = math.random(0, tpList.weight)
    for _,v in ipairs(tpList.typeList) do
        weight = weight + v.weight
        if randWeight <= weight then
            return v.id
        end
    end
end

-- 随机出戒指、护符的特效
function randEffectAttrList(equipId)
    local equipCfg = EquipExcel[equipId]

    if equipCfg.subType ~= ItemDefine.EQUIP_SUBTYPE_RING and equipCfg.subType ~= ItemDefine.EQUIP_SUBTYPE_AMULET then
        return
    end

    local excludeTypeList
    local noEffectTimes = 0
    local effectList = {}
    for i=1, 3 do
        local totalWeight, randList = generateRandData(excludeTypeList)
        local effctId = getIndexByRand(totalWeight, randList)

        if effctId == 1 then
            noEffectTimes = noEffectTimes + 1
        else
            effectList[effctId] = 1
            excludeTypeList = excludeTypeList or {}

            local excludeType = effectCfg[effctId].type
            excludeTypeList[excludeType] = 1
        end

        -- 保底要有一条特效
        if noEffectTimes >= 2 then
            excludeTypeList = excludeTypeList or {}
            local excludeType = effectCfg[1].type
            excludeTypeList[excludeType] = 1
        end
    end

    return effectList
end

--------------------------------------------------------------------------------------------------------------------------------



---------------------------------------------------------戒指、护符随机英雄专属---------------------------------------------------


function randHeroExclusive(equipId)
    local equipCfg = EquipExcel[equipId]

    if equipCfg.subType ~= ItemDefine.EQUIP_SUBTYPE_RING and equipCfg.subType ~= ItemDefine.EQUIP_SUBTYPE_AMULET then
        return
    end

    local randWeight = math.random(0, (EQUIP_HEROEXCLUSIVE_WEIGHT + EQUIP_NO_HEROEXCLUSIVE_WEIGHT))
    if randWeight > EQUIP_HEROEXCLUSIVE_WEIGHT then
        return
    end

    local heroList = HeroDefine.GetAllHighQualityHero()
    local len = #heroList
    if len <= 0 then
        return
    end

    local idx = math.random(1, len)
    return heroList[idx]
end

--------------------------------------------------------------------------------------------------------------------------------



-- 随机属性
local attrCheck = {}
function checkAttr(equipGrid)
    local quality = equipGrid.quality
    local len = 0

--    for key, value in pairs(equipGrid.attr) do
--       len = len + 1
--       attrCheck[len] = {key, value}
--    end

    for k, v in ipairs(equipGrid.attr) do
        len = len + 1
        attrCheck[len] = {v[1], v[2], v[3]}
    end


    -- 砍掉后面的
    if quality < len then   
        equipGrid.attr = {}   
        for z = 1, quality do
            -- equipGrid.attr[attrCheck[z][1]] = attrCheck[z][2]
            equipGrid.attr[z] = {
                attrCheck[z][1],
                attrCheck[z][2],
                attrCheck[z][3],
            }
        end
    end
end

-- 随机属性
function randomAttr(itemID, isRandom, otherData, excludeAttrList)
    local equipConfig = EquipExcel[itemID]
    if not equipConfig then return end

    -- 固定属性
    local quality = 1
    -- local attr = {}

    -- 所有装备的随机属性使用同一套规则
    -- if equipConfig.random == 1 and not isRandom then
    --     quality = #equipConfig.randomAttr
    --     if quality > EQUIP_QUALITY_MAX then
    --        quality = EQUIP_QUALITY_MAX
    --     end

    --     for i = 1, quality do
    --         local key = equipConfig.randomAttr[i][1]
    --         local value = equipConfig.randomAttr[i][2]
    --         attr[key] = attr[key] or 0
    --         attr[key] = attr[key] + value
    --     end
    --     return attr, quality
    -- end

    if not otherData then
        -- 随机品质
        quality = randColor(equipConfig.randomAttr)
    else
       if type(otherData) == "number"  then
          otherData = otherData < 0 and 1 or otherData
          quality = otherData > #equipConfig.randomAttr and #equipConfig.randomAttr or otherData 
       end
    end

    if quality > EQUIP_QUALITY_MAX then
       quality = EQUIP_QUALITY_MAX
    end


    -- 计算总权重
    -- local totalWeight = 0
    -- for k, v in pairs(equipConfig.randomAttr) do
    --     totalWeight = totalWeight + v[3]
    -- end

    -- 随机条目属性
    -- local MathRandom = math.random
    local randomAttr = Util.copyTable(equipConfig.randomAttr)

    -- for z = 1, quality do
    --     local randmWeight = MathRandom(1, totalWeight)
    --     for k, v in pairs(randomAttr) do
    --         local key = v[1]
    --         local value = v[2]
    --         local weight = v[3]
    --         if randmWeight <= weight then
    --             attr[key] = attr[key] or 0
    --             attr[key] = attr[key] + value
    --             randomAttr[k] = nil
    --             -- 排除这个权重
    --             totalWeight = totalWeight - weight
    --             break
    --         else
    --             randmWeight = randmWeight - weight
    --         end
    --     end
    -- end

    local attr = randAttrArray(randomAttr, quality, excludeAttrList)

    return attr, quality
end




-- 检查背包空间
function checkEmptyCnt(human, itemCnt)
   if itemCnt > getEmptyCnt(human) then
      Broadcast.sendErr(human, Lang.COMMON_BAG_FULL)
      return 
   end
   return true
end


-- 获取装备对基础属性的影响
function getEquipBaseRate(quality)
    local baseRate = EQUIP_QUALITY_BASE_RATE[quality]
    if not baseRate then return 1 end
    return baseRate / 10000
end

-- 获取装备品质
function getEquipMaxQuality(equipConfig)
    if not equipConfig.randomAttr then return 0 end

    local maxQuality = 0
    if equipConfig.random == 1 then
        maxQuality = #equipConfig.randomAttr
    else
        maxQuality = equipConfig.quality or 0
    end
    return maxQuality
end

-- 获取装备洗练属性
function getEquipTzAttr(equipConfig)
    if not equipConfig.randomAttr then return end
    if equipConfig.random == 1 then
       return equipConfig.randomAttr
    end
    -- local quality
    -- if equipConfig.subType == ItemDefine.EQUIP_SUBTYPE_RING or equipConfig.subType == ItemDefine.EQUIP_SUBTYPE_AMULET then
    --     quality = equipConfig.quality
    -- end

    -- local attr = randAttrArray(Util.copyTable(equipConfig.randomAttr), quality)

    -- return attr
end

-- 返回装备背包空余格子数
function getEmptyCnt(human)
    local emptyCnt = 0
    for i = 1, EQUIP_BAG_MAX_CNT do
        if human.db.equipBag[i] == nil then
            emptyCnt = emptyCnt + 1
        end
    end
    return emptyCnt
end


-- 获得装备背包第一个空格子下标
function getEmptyIndex(human)
    for index = 1, EQUIP_BAG_MAX_CNT do
        local grid = human.db.equipBag[index]
        if grid == nil then
            return index
        end
    end
end

-- 返回装备根据uuid
function getEquipByUuid(human, uuid)
    local emptyCnt = 0
    for i = 1, EQUIP_BAG_MAX_CNT do
        local equipGrid = human.db.equipBag[i]
        if equipGrid and equipGrid.uuid == uuid then
            return equipGrid
        end
    end
end

-- 返回装备根据pos
function getEquipByPos(human, star, pos)
    local emptyCnt = 0
    for i = 1, EQUIP_BAG_MAX_CNT do
        local equipGrid = human.db.equipBag[i]
       
        if equipGrid then
            local conf = EquipExcel[equipGrid.id]
            if conf and conf.subType == pos and star >= conf.star then
               return equipGrid
            end
        end
    end
end

-- 修复老数据
function modifyEquip(human, equipGrid)
   if equipGrid.putUuid == nil then return end
   local heroGrid = HeroLogic.getHeroGridByUuid(human, equipGrid.putUuid)
   if heroGrid == nil then
      equipGrid.putUuid = nil
   end
end


-- 兼容老数据处理 : 修改装备的 wash 和 attr 的数据格式
function TransformEuipAttrData(human)
    for index = 1, EQUIP_BAG_MAX_CNT do
        local equipGrid = human.db.equipBag[index]
        if equipGrid then
            if equipGrid.attr  then
                equipGrid.attr = AttrHashToArray(equipGrid.attr)
            end

            if equipGrid.washAttr  then
                equipGrid.washAttr = AttrHashToArray(equipGrid.washAttr)
            end
        end
    end
end



-- 推送装备背包信息
function sendEquipBagList(human)
    local msgRet = Msg.gc.GC_EQUIP_BAG_LIST
    local len = 0
    for index = 1, EQUIP_BAG_MAX_CNT do
        local equipGrid = human.db.equipBag[index]
        if equipGrid then
            equipGrid.putUuid = nil --处理数据异常的装备

            if not equipGrid.baseRandVal then
                equipGrid.baseRandVal = EquipLogicGrid.GenEquipBaseRandomVal(equipGrid.id)
            end

            len = len + 1
            Grid.makeItem(msgRet.list[len], equipGrid.id, 1, nil, equipGrid, index, Grid.getOpflagAtBag(equipGrid.id))
            if len >= 30 then
                msgRet.list[0] = len
                len = 0
                Msg.send(msgRet, human.fd)
            end
        end
    end
    if len > 0 then
        msgRet.list[0] = len
        Msg.send(msgRet, human.fd)
    end
end

-- 制造一个获得列表
function makeEquipItem(human, nets, len)
    if not human.getEquip then return len end

    for i = 1, #human.getEquip do
        len = len + 1
        if not nets[len] then
            len = len - 1
            break
        end

        local equipGrid = human.getEquip[i]
        Grid.makeItem(nets[len], equipGrid.id, 1, nil, equipGrid)
    end
    human.getEquip = nil

    return len
end

-- 制造一个装备获得
function makeEquipItemOne(human, net)
    if not human.getEquip then return end
    local equipGrid = human.getEquip[1]
    Grid.makeItem(net, equipGrid.id, 1, nil, equipGrid)
    human.getEquip = nil
end

-- 制造一个装备
function makeEquip(itemID, otherData)
    local equipGrid = EquipLogicGrid.createGrid(itemID)
    if not equipGrid then return end

    local bl = false
    local equipCfg = EquipExcel[equipGrid.id]
    if equipCfg.subType == ItemDefine.EQUIP_SUBTYPE_RING or equipCfg.subType == ItemDefine.EQUIP_SUBTYPE_AMULET then
        otherData = equipCfg.quality
        bl = true
    end

    -- 随机洗练属性
    local attr, quality = randomAttr(itemID, nil, otherData)
    equipGrid.attr = attr


    if not bl then
        equipGrid.quality = quality
    else
        -- 装备特效
        equipGrid.effectList = randEffectAttrList(itemID)

        -- 英雄专属
        equipGrid.exclusiveHeroId = randHeroExclusive(itemID)
    end


    checkAttr(equipGrid)
    return equipGrid
end

-- 添加装备
function addEquip(human, itemID, itemCnt, logType, otherData)
    if not EquipExcel[itemID] then return end

    for i = 1, itemCnt do
        local equipGrid = makeEquip(itemID, otherData)
        if equipGrid then
            addByEquipGrid(human, equipGrid, logType)
            TriggerLogic.PublishEvent(TriggerDefine.EQUIP_GETQUALITY, human.db._id, equipGrid.quality, 1)
        end
    end
end

-- 通过gird添加装备
function addByEquipGrid(human, equipGrid, logType, noSend)
    local index = getEmptyIndex(human)
    if not index then 
       --邮件处理
       local items = {}
	   items[1] = { equipGrid.id, equipGrid }
   	   local title = MailExcel.mail[1000].title
	   local content = MailExcel.mail[1000].content
	   local senderName = MailExcel.mail[1000].senderName
	   MailManager.add(MailManager.SYSTEM, human.db._id, title, content, items, senderName)
       return 
    end

    human.db.equipBag[index] = equipGrid
    sendEquipChange(human, index, equipGrid, EQUIP_BAG_OP_ADD)

    Log.write(Log.LOGID_OSS_EQUIP, human.db._id, human.db.account,
    human.db.name, human.db.lv, LogDefine.DEFINE[logType] + LogDefine.TYPE["equip"], equipGrid.id, 1, equipGrid.uuid)

    if not noSend then
       human.getEquip = human.getEquip or {}
       human.getEquip[#human.getEquip + 1] = equipGrid
    end
    return index
end

-- 从背包删除装备
function delEquip(human, index, logType, sendNotify)
    local equipGrid = human.db.equipBag[index]
    if not equipGrid then return end

    Log.write(Log.LOGID_OSS_EQUIP, human.db._id, human.db.account,
    human.db.name, human.db.lv, LogDefine.DEFINE[logType] + LogDefine.TYPE["equip"], equipGrid.id, -1, equipGrid.uuid)

    human.db.equipBag[index] = nil

    if not sendNotify then
        sendEquipChange(human, index, nil, EQUIP_BAG_OP_DEL)
    end
end

-- 发送装备改变
function sendEquipChange(human, bagIndex, equipGrid, op)
    local msgRet = Msg.gc.GC_EQUIP_BAG_CHANGE
    if op == EQUIP_BAG_OP_ADD or op == EQUIP_BAG_OP_CHANGE then
        msgRet.itemID = equipGrid.id
        msgRet.itemIndex = bagIndex
        msgRet.itemData[0] = 1
        Grid.makeItem(msgRet.itemData[1], equipGrid.id, 1, nil, equipGrid, bagIndex, Grid.getOpflagAtBag(equipGrid.id))
    elseif op == EQUIP_BAG_OP_DEL then
        msgRet.itemID = 0
        msgRet.itemIndex = bagIndex
        msgRet.itemData[0] = 0
    else
        assert(nil)
    end
    Msg.send(msgRet, human.fd)
end


function getNewAttrByItemID(itemID, equipGrid)
    local config = EquipExcel[itemID]
    -- if not config then return end

    -- for _, v in ipairs(config.randomAttr) do
    --     if attr[v[1]] then
    --         attr[v[1]] = v[2]
    --     end
    -- end

    equipGrid.attr = randAttrArray(Util.copyTable(config.randomAttr), equipGrid.quality)
end