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

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
end

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

local function fontSkinNet(data,id)
	if not id or id == 0 then
		data.id = 0
		data.name = ""
		data.desc = ""
		data.head = 0
		data.body = ""
		data.icon = 0
		data.camp = 0
		data.order = 0
		data.type = 0
		data.upID = 0
		data.attrs[0] = 0
		data.fenjie[0] = 0
		data.upAddExp = 0
		data.upNeedExp = 0
		data.ronghe = 0
		data.heroName = ""
		data.quality = 0
	else
		local conf = SkinExcel[id]
		data.id = id
		data.name = conf.name
		data.desc = conf.desc
		data.head = conf.head
		data.body = conf.body
		data.icon = conf.icon
		data.camp = conf.camp
		data.order = conf.order
		data.type = conf.type
		data.upID = conf.upID
		local len = 0
		for k,v in ipairs(conf.attrs) do
			len = len + 1
			data.attrs[len].key = v[1]
			data.attrs[len].value = v[2]
		end
		data.attrs[0] = len
		len = 0
		for k,v in ipairs(conf.fenjie) do
			len = len + 1
			Grid.makeItem(data.fenjie[len],v[1],v[2])
		end
		data.fenjie[0] = len
		data.upAddExp = conf.upAddExp
		data.upNeedExp = conf.upNeedExp
		data.ronghe = conf.ronghe
		data.heroName = HeroExcel[conf.id] and HeroExcel[conf.id].name or ""
		data.quality = conf.quality
	end
end

local function fontBagNet(net,human,ind)
	net.ind = ind or 0
	if human.db.skinBag[ind] then
		net.isOn = human.db.skinBag[ind].heroInd and 1 or 0
		fontSkinNet(net.data,human.db.skinBag[ind].id)
	else
		net.isOn = 0
		fontSkinNet(net.data)
	end
end

function bag(human)
	local bagDB = getBag(human)
	local msgRet = Msg.gc.GC_SKIN_BAG
	local len = 0
	msgRet.isEnd = 1
	for k in pairs(human.skinBag) do
		len = len + 1
		local net = msgRet.list[len]
		fontBagNet(net,human,k)
		if len >=30 then
			msgRet.list[0] = 30
			Msg.send(msgRet,human.fd)
			len = 0
			msgRet.isEnd = 2
		end
	end

	msgRet.isEnd = 3
	msgRet.list[0] = len
	Msg.send(msgRet,human.fd)

end

OP_ADD = 1
OP_UPDATE = 2
OP_DEL = 3
function sendChange(human,changeList)
	if #changeList == 0 then
		return
	end
	table.sort(changeList,function(a,b)
		return a[2] > b[2]
	end)
	local msgRet = Msg.gc.GC_SKIN_UPDATE
	local len = 0
	for _,v in ipairs(changeList) do
		len = len + 1
		local net = msgRet.list[len]
		net.op = v[2]
		fontBagNet(net.data,human,v[1])
		if len >= 30 then
			break
		end
	end
	msgRet.list[0] = len
	Msg.send(msgRet,human.fd)
end

function onAddSkin(human,id,list)
	local ind 
	for i = 1,human.db.skinBag[0] do
		if not human.db.skinBag[i] then
			ind = i
			break
		end
	end
	local skinConf = SkinExcel[id]
	if ind and skinConf then
		human.db.skinBag[ind] = {id = id}
		human.skinBag = nil
		list[#list + 1] = {ind,OP_ADD}
		RoleHeadLogic.active(human, RoleHeadLogic.HEAD_TYPE_1, skinConf.head)
		return ind
	end
end

function onDelSkin(human,ind,list)
	if human.db.skinBag[ind] then
		human.db.skinBag[ind] = nil
		human.skinBag = nil
		list[#list + 1] = {ind,OP_DEL}
		return ind
	end
end

function checkDel(human,list)
	if #list == 0 then
		return Broadcast.sendErr(human, "empty checkDel:"..Lang.SKIN_PARAM_ERR)
	end
	local bagDB = getBag(human)
	for _,v in ipairs(list) do
		if not bagDB[v] then
			return Broadcast.sendErr(human, Lang.SKIN_NO_HAS)
		elseif bagDB[v].heroInd then
			return Broadcast.sendErr(human, Lang.SKIN_IS_ON)
		end
	end
	return true
end

function delSkin(human,delList,changeList)
	if checkDel(human,delList) then
		for _,v in ipairs(delList) do
			onDelSkin(human,v,changeList)
		end
		return true
	end
end

function addSkin(human,id,cnt)
	if not SkinExcel[id] then
		return
	end
	cnt = cnt or 1
	local changeList = {}
	for i = 1,cnt do
		onAddSkin(human,id,changeList)
	end
	sendChange(human,changeList)
	human.db.skinLog[id] = 1
end

function fenjie(human,ind)
	local bagDB = getBag(human)
	if not bagDB[ind] then
		return
	end

	local id = bagDB[ind].id
	local conf = SkinExcel[id]
	if not conf.fenjie[1] then
		return
	end
	local changeList = {}
	if not delSkin(human,{ind},changeList) then
		return
	end
	for k,v in ipairs(conf.fenjie) do
		BagLogic.addItem(human, v[1], v[2], "skin")
	end
	sendChange(human,changeList)
	local msgRet = Msg.gc.GC_SKIN_FENJIE
	msgRet.ind = ind
	Msg.send(msgRet,human.fd)
end

function upQuery(human,ind,nosend)
	local bagDB = getBag(human)
	if not bagDB[ind] then
		return
	end
	if type(bagDB[ind]) == "number" then
		if nosend then
			Broadcast.sendErr(human, ind..":upQuery:"..Lang.SKIN_PARAM_ERR)
		end
		return 
	end

	local id = bagDB[ind].id
	local conf = SkinExcel[id]
	local upConf = SkinExcel[conf.upID]
	if not (upConf and conf.upNeedExp > 0) then
		if not nosend then
			Broadcast.sendErr(human, id..":upQuery:"..Lang.SKIN_CONF_ERR)
		end
		return
	end

	local msgRet = Msg.gc.GC_SKIN_UP_QUERY
	msgRet.ind = ind
	fontSkinNet(msgRet.nowData,id)
	fontSkinNet(msgRet.upData,conf.upID)
	msgRet.maxExp = conf.upNeedExp
	msgRet.nowExp = bagDB[ind].exp or 0
	Msg.send(msgRet,human.fd)
end

function up(human,ind,list)
	local bagDB = getBag(human)
	if not bagDB[ind] then
		return
	end

	local id = bagDB[ind].id
	local conf = SkinExcel[id]
	local upConf = SkinExcel[conf.upID]
	if not (upConf and conf.upNeedExp > 0) then
		return Broadcast.sendErr(human, id..":up:"..Lang.SKIN_CONF_ERR)
	end
	local addExp = 0
	for _,v in ipairs(list) do
		if not bagDB[v] then--皮肤不存在
			return Broadcast.sendErr(human, v..":up1:"..Lang.SKIN_PARAM_ERR)
		elseif bagDB[v].heroInd then--被使用
			return Broadcast.sendErr(human, v..":up2:"..Lang.SKIN_PARAM_ERR)
		elseif v == ind then--升级目标和升级皮肤一样
			return Broadcast.sendErr(human, v..":up3:"..Lang.SKIN_PARAM_ERR)
		end
		local costID = bagDB[v].id
		local costConf = SkinExcel[costID]
		if not (costConf and costConf.upAddExp > 0) then
			return Broadcast.sendErr(human, costID..":up3:"..Lang.SKIN_PARAM_ERR)
		else
			addExp = addExp + costConf.upAddExp
		end
	end

	if addExp == 0 then
		return Broadcast.sendErr(human, #list..":up3:"..Lang.SKIN_PARAM_ERR)
	end

	local nowExp = bagDB[ind].exp or 0
	nowExp = nowExp + addExp
	if nowExp >  conf.upNeedExp then
		return
	end
	local heroInd =  bagDB[ind].heroInd
	local isUp = false
	local changeList = {}
	for _,v in ipairs(list) do
		onDelSkin(human,v,changeList)
	end

	if nowExp == conf.upNeedExp then
		onDelSkin(human,ind,changeList)
		ind = onAddSkin(human,conf.upID,changeList)
		bagDB[ind].exp = nowExp - conf.upNeedExp
		id = conf.upID
		conf = SkinExcel[id]
		upConf = conf.upID and SkinExcel[conf.upID]
		isUp = true
	else
		bagDB[ind].exp = nowExp
	end

	sendChange(human,changeList)

	local msgRet = Msg.gc.GC_SKIN_UP
	msgRet.ind = ind
	fontSkinNet(msgRet.nowData,id)
	fontSkinNet(msgRet.upData,conf.upID)
	msgRet.maxExp = conf.upNeedExp
	msgRet.nowExp = bagDB[ind].exp or 0
	Msg.send(msgRet,human.fd)
	
	upQuery(human,ind,true)

	if isUp and heroInd then
		skinOn(human,heroInd,ind)
	end
end

function fontPreviewNet(net,id,weight)
	net.weight = weight
	fontSkinNet(net.data,id)
end

function suipianPreview(human,id)
	local itemConf = ItemExcel[id]
	if not (itemConf and itemConf.type == ItemDefine.ITEM_SUBTYPE_SUIPIAN_SKIN) then
		return Broadcast.sendErr(human, id..":suipianPreview:"..Lang.SKIN_PARAM_ERR)
	end
	local msgRet = Msg.gc.GC_SKIN_SUIPIAN_PREVIEW
	msgRet.id = id
	local len = 0
	if itemConf.get[1] == 1 then
		len = len + 1
		fontPreviewNet(msgRet.list[len],itemConf.get[3],10000)
	else
		for _,v in ipairs(OutExcel[itemConf.get[3]].out) do
			len = len + 1
			local weight = math.floor(10000*v[2]/OutExcel[itemConf.get[3]].totalWeight)
			fontPreviewNet(msgRet.list[len],v[1],v[2])
		end 
	end
	msgRet.list[0] = len
	Msg.send(msgRet,human.fd)
end
SUIPIAN_CNT = 10
function suipian(human,id,cnt)
	local itemConf = ItemExcel[id]
	
	if cnt > SUIPIAN_CNT then
		return Broadcast.sendErr(human, Util.format(Lang.SKIN_SUIPIAN_LIMIT,SUIPIAN_CNT))
	end

	if not (itemConf and itemConf.type == ItemDefine.ITEM_SUBTYPE_SUIPIAN_SKIN) then
		return Broadcast.sendErr(human, id..":suipian:"..Lang.SKIN_PARAM_ERR)
	end
	if BagLogic.getItemCnt(human,id) < itemConf.fullCnt * cnt then
		return Broadcast.sendErr(human, Util.format(Lang.COMMON_NO_ITEM,itemConf.name))
	end
	local skinIDList = {}
	for i = 1,cnt do
		if itemConf.get[1] == 1 then
			skinIDList[#skinIDList + 1] = itemConf.get[3]
		else
			local outConf = OutExcel[itemConf.get[3]]
			local r = math.random(1,outConf.totalWeight)
			for _,v in ipairs(outConf.out) do
				if r <= v[2] then
					skinIDList[#skinIDList + 1] = v[1]
					break
				else
					r = r - v[2]
				end
			end 
		end
	end

	if #skinIDList == 0 then
		return Broadcast.sendErr(human, id..":suipian:"..Lang.SKIN_CONF_ERR)
	end

	BagLogic.delItem(human, id, itemConf.fullCnt * cnt, "skin")
	local msgRet = Msg.gc.GC_SKIN_SUIPIAN
	msgRet.id = id
	local len = 0
	local changeList = {}
	for _,skinID in ipairs(skinIDList) do
		len = len + 1
		onAddSkin(human,skinID,changeList)
		fontSkinNet(msgRet.out[len],skinID)
	end
	msgRet.out[0] = len
	sendChange(human,changeList)
	Msg.send(msgRet,human.fd)
end

RONGHE_ID = 1
RONGHE_CNT = 5
function ronghePreview(human)
	local outConf = OutExcel[RONGHE_ID]
	local msgRet = Msg.gc.GC_SKIN_RONGHE_PREVIEW
	local len = 0
	for _,v in ipairs(outConf.out) do
		len = len + 1
		local weight = math.floor(10000*v[2]/outConf.totalWeight)
		fontPreviewNet(msgRet.list[len],v[1],weight)
	end 
	msgRet.list[0] = len
	Msg.send(msgRet,human.fd)
end

function ronghe(human,list)
	if #list ~= RONGHE_CNT then
		return Broadcast.sendErr(human, #list..":ronghe1:"..Lang.SKIN_PARAM_ERR)
	end
	local bagDB = getBag(human)
	for k,v in ipairs(list) do
		local costID = bagDB[v] and bagDB[v].id or 0
		local costConf = SkinExcel[costID]
		if not (costConf and costConf.ronghe == 1) then
			return  Broadcast.sendErr(human, v..":"..costID..":ronghe2:"..Lang.SKIN_PARAM_ERR)
		end
	end

	local outConf = OutExcel[RONGHE_ID]
	local r = math.random(1,outConf.totalWeight)
	local skinID = outConf.out[1][1]
	for _,v in ipairs(outConf.out) do
		if r <= v[2] then
			skinID = v[1]
			break
		else
			r = r - v[2]
		end
	end
	local changeList = {}
	if not delSkin(human,list,changeList) then
		return
	end 
	onAddSkin(human,skinID,changeList)

	sendChange(human,changeList)

	local msgRet = Msg.gc.GC_SKIN_RONGHE
	msgRet.id = id
	fontSkinNet(msgRet.out,skinID)
	Msg.send(msgRet,human.fd)
end

function heroSkin(human,heroInd)
	local bagDB = getBag(human)
	local heroGrid = human.db.heroBag[heroInd]
	local heroID = heroGrid.id
	local heroConf = HeroExcel[heroID]
	local heroSkinInd = human.heroSkin[heroInd] and human.heroSkin[heroInd][1]
	local heroSkinID = heroSkinInd and bagDB[heroSkinInd].id
	local msgRet = Msg.gc.GC_SKIN_HERO
	local len = 0
	for _,v in ipairs(heroConf.skin) do
		len = len + 1
		local net = msgRet.list[len]
		fontSkinNet(net.data,v[1])
		if heroSkinID == v[1] then
			net.ind = heroSkinInd
			net.isOn = 1
		elseif human.hasSkin[v[1]] then	
			net.isOn = 1
			net.ind = 0
			for v1 in pairs(human.hasSkin[v[1]]) do
				if not bagDB[v1].heroInd then
					net.ind = v1
					net.isOn = 0
					break
				end
			end
		else
			net.ind = 0
			net.isOn = 0
		end
	end
	msgRet.list[0] = len
	Msg.send(msgRet,human.fd)
end

function skinOn(human,heroInd,skinInd)
	local bagDB = getBag(human)
	if not (skinInd == 0 or bagDB[skinInd]) then
		return Broadcast.sendErr(human, skinInd..":skinOn:"..Lang.SKIN_PARAM_ERR)
	end
	local heroGrid = human.db.heroBag[heroInd]
	local heroID = heroGrid.id
	local heroConf = HeroExcel[heroID]

	if skinInd > 0 then
		local skinID = skinInd > 0 and bagDB[skinInd].id

		if bagDB[skinInd].heroInd then
			return Broadcast.sendErr(human, Lang.SKIN_DOUBLE_ON)
		end

		if bagDB[skinInd].heroInd == heroInd then
			return
		end

		isHeroSkin = false
		for k,v in ipairs(heroConf.skin) do
			if v[1] == skinID then
				isHeroSkin = true
				break
			end
		end

		if not isHeroSkin then
			return Broadcast.sendErr(human, Lang.SKIN_NO_HERO)
		end
	end
	
	local changeInd
	for k in pairs(human.skinBag) do
		if bagDB[k].heroInd == heroInd then
			bagDB[k].heroInd = nil
			changeInd = k
		end
	end
	if skinInd > 0 then
		bagDB[skinInd].heroInd = heroInd
		changeInd = skinInd
	end
	
	human.heroSkin = nil
	heroSkin(human,heroInd)
	local msgRet = Msg.gc.GC_SKIN_ON
	msgRet.heroInd = heroInd
	msgRet.skinInd = skinInd
	Msg.send(msgRet,human.fd)
	HeroLogic.sendHeroBagDynamic(human,heroID,heroInd)
	if changeInd then
		sendChange(human,{{changeInd,OP_UPDATE}})
	end
end

function book(human)
	local msgRet = Msg.gc.GC_SKIN_BOOK
	local len = 0
	msgRet.isEnd = 1
	for k,v in pairs(SkinExcel) do
		if v.tujian == 1 then
			len = len + 1
			local net = msgRet.list[len]
			net.ind = human.db.skinLog[k] and 1 or 0
			net.isOn = 0
			fontSkinNet(net.data,k)
			if len >=30 then
				msgRet.list[0] = 30
				Msg.send(msgRet,human.fd)
				len = 0
				msgRet.isEnd = 2
			end
		end
	end

	msgRet.isEnd = 3
	msgRet.list[0] = len
	Msg.send(msgRet,human.fd)

end

function setSkill(human,heroInd,heroConf,obj)
	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 checkHeroSkin(human, heroInd)
	if not heroInd then return end
	if not human or not human.db then return 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,skillID
	else
		return
	end
	
end

function getBody(human,heroInd)
	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)
	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 onDelHero(human,heroInd)
	local bagDB = getBag(human)
	if human.heroSkin[heroInd] then
		skinOn(human,heroInd,0)
	end
end