local Msg = require("core.Msg")
local Grid = require("bag.Grid")
local BagLogic = require("bag.BagLogic")
local Broadcast = require("broadcast.Broadcast")
local Lang = require("common.Lang")
local Util = require("common.Util")
local ItemDefine = require("bag.ItemDefine")
local BeSkill = require("combat.BeSkill")
local HeroLogic = require("hero.HeroLogic")
local RoleHeadLogic = require("role.RoleHeadLogic")
local SkinExcel = require("excel.skin").skin
local HeroExcel = require("excel.hero").hero
local SkillExcel = require("excel.skin").skill
local OutExcel = require("excel.skin").out
local ItemExcel = require("excel.item").item
local RoleAttr = require("role.RoleAttr")
local CombatDefine = require("combat.CombatDefine")
local CombatImpl = require("combat.CombatImpl")
local RoleDefine = require("role.RoleDefine")
local ObjHuman = require("core.ObjHuman")

local function getBag(human)
	if not (human.skinBag and human.heroSkin) then
		human.skinBag = {}
		human.heroSkin = {}
		human.hasSkin = {}
		for i = 1,human.db.skinBag[0] do
			local data = human.db.skinBag[i] 
			if data then
				if data.heroInd then
					local skinSkillID
					local heroGrid = human.db.heroBag[data.heroInd]
					if not heroGrid then
						data.heroInd = nil
					else
						local heroID = heroGrid.id
						local heroConf = HeroExcel[heroID]
						for _,v in ipairs(heroConf.skin) do
							if v[1] == data.id then
								human.heroSkin[data.heroInd] = {i,tonumber(v[2])}
							end
						end
					end
				end
				human.skinBag[i] = data.id
				human.hasSkin[data.id] = human.hasSkin[data.id] or {}
				human.hasSkin[data.id][i] = 1
			end
		end
	end
	return human.db.skinBag
end

--[[
    skin = {
        ttl = number -- 有效时长 -1表示永久
        state = number -- 0表示未穿戴 1 表示穿戴
    } -- skin 拥有唯一性
]]

-- 获取所有皮肤信息
local function skinListQuery(human)
    local skinBag = human.db.skinBag
    local ret = {}
    for i = 1,#skinBag do 
        local data = skinBag[i]
        ret[data.id] = {
            idx = i,
            id = data.id,
            ttl = data.ttl,
            state = data.state,
        }
    end
    return ret
end

-- 获取皮肤为skinId的皮肤
local function skinQueryById(human,skinId) 
    local skin = human.db.skinBag[skinId]
    if skin then
        return {
            id = skinId,
            ttl = skin.ttl,
            state = skin.state,
        }
    end
end

local function skinQueryIdxById(human,skinId)
    local skinBag = human.db.skinBag
    for i = 1,#skinBag do 
        local data = skinBag[i]
        if data.id == skinId then 
            return i
        end
    end
end

-- 生成发送给客户端的皮肤数据
local function skinNetGen(human,net,id)
    local skinCfg = assert(SkinExcel[id],"invalid skinId is ",id)
    net.id = id
    net.heroId = skinCfg.heroId or 0
    net.name = skinCfg.name
    net.desc = skinCfg.desc
	net.head = skinCfg.head
	net.body = skinCfg.body
	net.icon = skinCfg.icon
	net.camp = skinCfg.camp
	net.order = skinCfg.order
	net.type = skinCfg.type
    net.body1 = skinCfg.body1 or 0
    local attrLen = 0
	for k,v in ipairs(skinCfg.attrs) do
        attrLen = attrLen + 1
        net.attrs[attrLen].key = v[1]
        net.attrs[attrLen].value = v[2]
    end
    net.attrs[0] = attrLen
    net.heroName = HeroExcel[skinCfg.heroId] and HeroExcel[skinCfg.heroId].name or ""
end

-- 皮肤脱下
--[[
    @param2 = heroIdx -- 对应英雄存档的idx
]]
local function skinOff(human,heroIdx)
    local heroId = HeroLogic.getHeroIdByIndex(human,heroIdx)
    local heroGrid = HeroLogic.getHeroGrid(human,heroId,heroIdx)
    local skinId = heroGrid.skinOn
    -- 英雄不存在 或者 英雄未穿戴皮肤
    if not heroGrid or not skinId then 
        return Broadcast.sendErr(human, heroIdx..":heroIdx:"..Lang.SKIN_PARAM_ERR)
    end
    local skinIdx = nil
    for idx,skin in pairs(human.db.skinBag) do 
        if idx > 0 and skin.id == skinId then
            skinIdx = idx
            human.db.skinBag[idx].state = 0
            break 
        end
    end
    assert(skinIdx,"param error")
	-- 对所有heroId相同的英雄操作
	local heroIdxList = HeroLogic.getHeroListById(human,heroId)
    local heroCfg = HeroExcel[heroId]
	for _,idx in ipairs(heroIdxList) do
        -- 脱下皮肤 并且还原默认身体 icon和head
		human.db.heroBag[idx].skinOn = nil
        --local defaultHead = RoleHeadLogic.getDefaultHead(human)
        RoleHeadLogic.setHead(human,heroCfg.head,RoleHeadLogic.HEAD_TYPE_1)

        RoleHeadLogic.setHead(human,heroCfg.body,RoleHeadLogic.HEAD_TYPE_3)
	end

    -- 回复给客户端
    local msgRet = Msg.gc.GC_SKIN_UPDATE
    local data = msgRet.list[1].data
    data.ind = skinIdx
    data.isOn = 0
    skinNetGen(human,data.data,skinId)
    msgRet.list[1].op = 3
    msgRet.list[0] = 1
	Msg.send(msgRet,human.fd)
end

-- 皮肤穿戴
--[[
    @param2 = id -- 皮肤Id
    @param3 = heroIdx -- 对应英雄存档的idx
]]
local function skinOn(human,skinIdx,heroIdx)
    --local idx = skinQueryIdxById(human,skinIdx)
    local skin = human.db.skinBag[skinIdx]
    -- 当前skin不存在 或者 皮肤已经穿戴
    if not skin or skin.state == 1 then
        return Broadcast.sendErr(human, skinIdx..":skinOn:"..Lang.SKIN_PARAM_ERR)
    end

    local heroId = HeroLogic.getHeroIdByIndex(human,heroIdx)
    local heroGrid = HeroLogic.getHeroGrid(human,heroId,heroIdx)
    -- 英雄不存在 或者 英雄已经装备当前皮肤
    if not heroGrid then 
        return Broadcast.sendErr(human, heroIdx..":heroIdx:"..Lang.SKIN_PARAM_ERR)
    end

    if heroGrid.skinOn == skin.id then
        return Broadcast.sendErr(human, Lang.SKIN_DOUBLE_ON)
    end
    
    if  heroGrid.skinOn then 
        skinOff(human,heroIdx)
    end
    
    local skinCfg = SkinExcel[skin.id]
    human.db.skinBag[skinIdx].state = 1
	-- 对所有heroId相同的英雄操作
	local heroIdxList = HeroLogic.getHeroListById(human,heroId)
	for _,idx in ipairs(heroIdxList) do
		human.db.heroBag[idx].skinOn = skin.id
        RoleHeadLogic.setHead(human,skinCfg.head,RoleHeadLogic.HEAD_TYPE_1)
        if skinCfg.body ~= 0 then
            RoleHeadLogic.setHead(human,skinCfg.body,RoleHeadLogic.HEAD_TYPE_3)
        end
	end

     -- 回复给客户端
     local msgRet = Msg.gc.GC_SKIN_UPDATE
     local data = msgRet.list[1].data
     data.ind = skinIdx
     data.isOn = 1
     skinNetGen(human,data.data,skin.id)
     msgRet.list[1].op = 3
     msgRet.list[0] = 1
    Msg.send(msgRet,human.fd)
end

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

function initAfterHot()
	for _,outConf in pairs(OutExcel) do
		outConf.totalWeight = 0
		for _,v in ipairs(outConf.out) do
			outConf.totalWeight = outConf.totalWeight + v[2]
		end
	end
    SkinExcel = require("excel.skin").skin
    HeroExcel = require("excel.hero").hero
    SkillExcel = require("excel.skin").skill
    ItemExcel = require("excel.item").item
end

-- 优先使用皮肤的技能，新版本没有默认返回false
function setSkill(human,heroInd,heroConf,obj)
	return false
	--[[if not human then return end
	if not human.db.skinBag then
	--假人
		return
	end
	local bagDB = getBag(human)
	local skinSkillID = human.heroSkin[heroInd] and human.heroSkin[heroInd][2]
	if not skinSkillID then
		return
	end

	local skillConf = SkillExcel[skinSkillID]
	Skill.setSkill(obj, heroConfig,skillConf)	
	BeSkill.setBeSkill(obj,heroConf,skillConf)
	return true]]
end

function checkHeroSkinById(human,heroId)
    if not human then 
        return
    end
    local heroIdxList = HeroLogic.getHeroListById(human,heroId)
    if not next(heroIdxList) then 
        return
    end
	local idx = heroIdxList[1]
    return human.db.heroBag[idx].skinOn
end

function checkHeroSkin(human, heroInd)
	if not heroInd then return end
	if not human or not human.db or not human.db.heroBag then return end
	local heroId = HeroLogic.getHeroIdByIndex(human,heroInd)
    local heroGrid = HeroLogic.getHeroGrid(human,heroId,heroInd)
	if heroGrid.skinOn then 
		return heroGrid.skinOn,true
	end
	--[[if not human.db.skinBag then
		return
	end
	local bagDB = getBag(human)
	if human.heroSkin[heroInd] then
		local skinInd = human.heroSkin[heroInd][1]
		local skinID = bagDB[skinInd].id
		--local skillID = human.heroSkin[heroInd][2]
		return skinID,true
	else
		return
	end]]
end

-- 检查是否有皮肤body
function getBody(human,heroInd)
    if not heroInd then 
        return
    end
	local heroId = HeroLogic.getHeroIdByIndex(human,heroInd)
    local heroGrid = HeroLogic.getHeroGrid(human,heroId,heroInd)
    if not heroGrid then 
        return
    end
	local skinId = heroGrid.skinOn
	if not skinId then 
		return
	end
    if SkinExcel[skinId].heroId == heroId then
        return SkinExcel[skinId].body,SkinExcel[skinId].head
    else
        print("[getBody] 英雄装备的身体ID不正确 heroId = "..heroId)
        local tHeroCof = HeroExcel[heroId]
        if tHeroCof then
            print("[getBody] 英雄装备的身体ID不正确,返回基础配置 heroId = "..heroId.." body = "..tHeroCof.body.." head = "..tHeroCof.head)
            return tHeroCof.body, tHeroCof.head
        end
    end
	--[[if not human.db.skinBag then
		return
	end
	local bagDB = getBag(human)
	if human.heroSkin[heroInd] then
		local skinInd = human.heroSkin[heroInd][1]
		local skinID = bagDB[skinInd].id
		return SkinExcel[skinID].body,SkinExcel[skinID].head
	end]]
end

function getHeroSkin(human,heroInd)
	local heroId = HeroLogic.getHeroIdByIndex(human,heroInd)
    if not heroId then
        return
    end
    local heroGrid = HeroLogic.getHeroGrid(human,heroId,heroInd)
	local skinId = heroGrid.skinOn
	if not skinId then
		return
	end
	return SkillExcel[skinId]
	--[=[if not human or not human.db.skinBag then
		return
	end
	local bagDB = getBag(human)
	if human.heroSkin[heroInd] then
		local skinInd = human.heroSkin[heroInd][1]
		local skinID = bagDB[skinInd].id
		local skinConf = SkinExcel[skinID]
		local skillConf = SkillExcel[human.heroSkin[heroInd][2]]
		return skinConf,skillConf
	end]=]
end

function getBodyByHeroId(human, heroid)
    if not human then return end
    local list = HeroLogic.getHeroListById(human, heroid)
    if #list > 0 then
        local heroIdx = list[1]
        return getBody(human, heroIdx)
    end
end

local function calcSkinAttr(human)
    local skinBag = human.db.skinBag
    if not skinBag then 
        return
    end
    local attrMap = {}
    for i = 1,#skinBag do 
        local data = skinBag[i]
        local skinCfg = SkinExcel[data.id]
        for _,attr in pairs(skinCfg.attrs) do 
            attrMap[attr[1]] = attrMap[attr[1]] or 0
            attrMap[attr[1]] = attrMap[attr[1]] + attr[2]
        end
    end
    return attrMap
end

-------------------------- protocol --------------------------
-- 皮肤信息查询
function skinQuery(human)
    local msgRet = Msg.gc.GC_SKIN_BAG
    local data = skinListQuery(human)
    local cnt = 0
    for _,info in pairs(data) do
        cnt = cnt + 1   
        msgRet.data[cnt].ind = info.idx
        msgRet.data[cnt].id = info.id
        msgRet.data[cnt].isOn = info.state
       
    end
    msgRet.data[0] = cnt
    msgRet.isEnd = 1
    local bSend = false
    local maxLen = #msgRet.list -- 每次最多只能传30个
    cnt = 0
    for id in pairs(SkinExcel) do
        cnt = cnt + 1
        skinNetGen(human,msgRet.list[cnt],id)
        if cnt >= maxLen then
            msgRet.list[0] = maxLen
            cnt = 0
            Msg.send(msgRet,human.fd)
            msgRet.isEnd = 2
            bSend = true
        end
    end
    msgRet.list[0] = cnt
    if bSend then
        msgRet.isEnd = 3
    end
    Msg.send(msgRet,human.fd)
end

-- 皮肤穿戴功能
function skinOp(human,heroIdx,skinIdx)
    if skinIdx == 0 then 
        skinOff(human,heroIdx)
    else
        skinOn(human,skinIdx,heroIdx)
    end
    local retMsg = Msg.gc.GC_SKIN_ON
    retMsg.heroId = heroIdx
    retMsg.skinInd = skinIdx
    Msg.send(retMsg,human.fd)
end

-- 皮肤解锁
function skinUnlock(human,id)
    local skinCfg = assert(SkinExcel[id],"invalid skinId is ",id)
    local isUnlock = false
    for i = 1,#human.db.skinBag do 
        local skin = human.db.skinBag[i]
        if skin.id == id then 
            isUnlock =true
            break
        end 
    end
    --[[for _,skin in pairs(human.db.skinBag) do 
        if skin.id == id then 
            isUnlock =true
            break
        end
    end]]
    -- 皮肤已经解锁
    if isUnlock then
        -- 发放皮肤重复物品
        local itemList = {}
        for _,item in pairs(skinCfg.repeated) do 
            itemList[#itemList+1] =  {
                item[1],item[2]
            }
        end
        return BagLogic.addItemList(human,itemList,"skin")
        --Broadcast.sendErr(human, ":skin repeat:"..Lang.SKIN_REPEAT)
        --return
    end
    local now = os.time()
    human.db.skinBag[#human.db.skinBag + 1] = {
        id = id,
        ttl = -1,
        state = 0,
        getTime = now,
    }
    -- 解锁头像
	RoleHeadLogic.active(human, RoleHeadLogic.HEAD_TYPE_1, skinCfg.head)
    -- 解锁身体
    if skinCfg.body ~= 0 then 
        RoleHeadLogic.active(human, RoleHeadLogic.HEAD_TYPE_3, skinCfg.body)
        RoleHeadLogic.active(human, RoleHeadLogic.HEAD_TYPE_5, skinCfg.body)
    end

    -- 所有角色属性提升
    -- 回复给客户端
    local msgRet = Msg.gc.GC_SKIN_UPDATE
    local data = msgRet.list[1].data
    data.ind = #human.db.skinBag
    data.isOn = 0
    skinNetGen(human,data.data,id)
    msgRet.list[1].op = 1
    msgRet.list[0] = 1
	Msg.send(msgRet,human.fd)

    --更新数据
    RoleAttr.cleanHeroAttrCache(human)
    -- RoleAttr.doCalc(human)
    ObjHuman.doCalcHero(human)
    ObjHuman.sendAttr(human, RoleDefine.ZHANDOULI)

    skinQuery(human)
end

-- 计算皮肤属性
function doCalcSkinHero(human,attrs)
    local skinBag = human.db.skinBag
    local attrMap = {}
    for i = 1,#skinBag do 
        local data = skinBag[i]
        local skinCfg = SkinExcel[data.id]
        for _,attr in pairs(skinCfg.attrs) do 
            attrMap[attr[1]] = attrMap[attr[1]] or 0
            attrMap[attr[1]] = attrMap[attr[1]] + attr[2]
        end
    end
    --[=[for id in pairs(skinBag) do
        local skinCfg = SkinExcel[id]
        for _,attr in pairs(skinCfg.attrs) do 
            attrMap[attr[1]] = attrMap[attr[1]] or 0
            attrMap[attr[1]] = attrMap[attr[1]] + attr[2]
        end
    end]=]
    for attr,cnt in pairs(attrMap) do 
        RoleAttr.updateValue(attr,cnt, attrs)
    end
end

function onFightBegin(human)
    local skinAttrMap = calcSkinAttr(human)
    if not skinAttrMap or not next(skinAttrMap) then 
        return
    end
    for pos = 1,CombatDefine.COMBAT_HERO_ALL_CNT do
        local obj = CombatImpl.objList[pos]
		if obj then
            for attr,cnt in ipairs(skinAttrMap) do
                obj.sysAttr[attr] = obj.sysAttr[attr] or 0
                obj.sysAttr[attr] = obj.sysAttr[attr] +cnt
            end
            obj.isSysAttrChange = true
        end
    end
end

-- 登录检测英雄皮肤装备数据
function OnLoginCheckEquipSkin(human, bSyncClient)
    if not human then
        return
    end

    local skinBag = human.db.skinBag
    if not skinBag then
        return
    end

    -- 检测的英雄
    local tCheckHero = {}
    for i = 1,#skinBag do 
        local data = skinBag[i]
        local nSkinID = data.id

        local tConfig = SkinExcel[nSkinID]
        if not tConfig then
            print("[OnLoginCheckEquipSkin] 严重问题, 找不到对应皮肤的配置 nSkinID = "..nSkinID)
            break
        end

        local nHeroID = tConfig.heroId
        tCheckHero[nHeroID] = tCheckHero[nHeroID] or {}

        -- 找所有皮肤中是否有装备着的
        local bEquip, nNowSkinID = false, 0
        for nHaveSkinID, v in pairs(tCheckHero[nHeroID]) do
            if v == 1 then
                bEquip = true
                nNowSkinID = nHaveSkinID
                break
            end
        end

        if data.state == 1 then
            if false == bEquip then
                tCheckHero[nHeroID][nSkinID] = 1            -- 装备标识

                -- 所有英雄进行装备皮肤
                local heroIdxList = HeroLogic.getHeroListById(human, nHeroID)

                local headID = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_1)
                local bodyID = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_3)

                for _,idx in ipairs(heroIdxList) do
                    human.db.heroBag[idx].skinOn = nSkinID
                    -- RoleHeadLogic.setHead(human,tConfig.head,RoleHeadLogic.HEAD_TYPE_1)
                    -- if tConfig.body ~= 0 then
                    --     RoleHeadLogic.setHead(human,tConfig.body,RoleHeadLogic.HEAD_TYPE_3)
                    -- end
                end

                if headID <= 0 then
                    RoleHeadLogic.setHead(human,tConfig.head,RoleHeadLogic.HEAD_TYPE_1)
                end

                if bodyID <= 0 and tConfig.body ~= 0 then
                    RoleHeadLogic.setHead(human,tConfig.body,RoleHeadLogic.HEAD_TYPE_3)
                end

                print("[OnLoginCheckEquipSkin] 对玩家英雄设置了皮肤 nSkinID = "..nSkinID.." nHeroID = "..nHeroID)
            else
                tCheckHero[nHeroID][nSkinID] = 0            -- 未装备标识
                data.state = 0
                print("[OnLoginCheckEquipSkin] 同一个英雄穿上了两个皮肤!! 进行修正 nHeroID = "
                .. nHeroID.." nNowSkinID = "..nNowSkinID .. " nSkinID = "..nSkinID)
            end
        else
            tCheckHero[nHeroID][nSkinID] = 0            -- 未装备标识
            if false == bEquip then
                local heroIdxList = HeroLogic.getHeroListById(human, nHeroID)
                local heroCfg = HeroExcel[nHeroID]
    
                for _,idx in ipairs(heroIdxList) do
                    -- 脱下皮肤 并且还原默认身体 icon和head
                    human.db.heroBag[idx].skinOn = nil
                    --local defaultHead = RoleHeadLogic.getDefaultHead(human)
                    -- RoleHeadLogic.setHead(human,heroCfg.head,RoleHeadLogic.HEAD_TYPE_1)
    
                    -- RoleHeadLogic.setHead(human,heroCfg.body,RoleHeadLogic.HEAD_TYPE_3)
                end

                local headID = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_1)
                local bodyID = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_3)
                if headID <= 0 then
                    RoleHeadLogic.setHead(human,tConfig.head,RoleHeadLogic.HEAD_TYPE_1)
                end

                if bodyID <= 0 then
                    RoleHeadLogic.setHead(human,tConfig.body,RoleHeadLogic.HEAD_TYPE_3)
                end

                print("[OnLoginCheckEquipSkin] 对玩家英雄设置取消了皮肤 nHeroID = "..nHeroID.." nSkinID = "..nSkinID)
            end
        end
    end

    if bSyncClient then
        skinQuery(human)
        print("[OnLoginCheckEquipSkin] 同步数据结束")
    end
end