------------------------------------------------------
-- 兵书逻辑
------------------------------------------------------

local FuwenExcel = require("excel.fuwen")
local HeroExcel = require("excel.hero")
local Lang = require("common.Lang")
local Util = require("common.Util")
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 BingshuGrid = require("fuwen.BingshuGrid")
local HeroLogic = require("hero.HeroLogic")
local LiLianLogic = require("dailyTask.LiLianLogic")
local Log = require("common.Log")

BINGSHU_MAXCNT = 3 			-- 最多x个兵书
BINGSHU_OPEN_LIST = {6, 11, 13}

------------------------------------- config ------------------------------------------
-- 获取可以激活的技能列表
local CAN_LEARN_LIST = nil
function getCanLearnList()
	if not CAN_LEARN_LIST then
		CAN_LEARN_LIST = {}
		for id, config in Util.pairsByKeys(FuwenExcel.skill) do
			if config.isBingshuSkill == 1 and config.lv == 1 then
				CAN_LEARN_LIST[#CAN_LEARN_LIST + 1] = id
			end
		end
	end
	return CAN_LEARN_LIST
end

-- 获取下一级技能
function getNextSkillID(skillID)
	local tconfig = FuwenExcel.skill[skillID]
	if not tconfig then return end
	for id, config in pairs(FuwenExcel.skill) do
		if (config.isBingshuSkill == 1) and
			(config.groupID == tconfig.groupID) and 
			(config.lv == tconfig.lv + 1) and
			(#config.bingshuUpNeed > 0) then
			return id
		end
	end
end

----------------------------------------- db -------------------------------------------------

-- 获取兵书grid
function getBingshuGrid(heroGrid, index)
	if not heroGrid then return end
	if not heroGrid.bingshu then return end
	return index and heroGrid.bingshu[index]
end

-- 是否已经学过某个技能
function isLearnSkill(heroGrid, skillID)
	if not heroGrid then return end
	if not heroGrid.bingshu then return end

	local skillConfig = FuwenExcel.skill[skillID]
	for _, grid in pairs(heroGrid.bingshu) do
		local tconfig = FuwenExcel.skill[grid.skillID]
		if tconfig.groupID == skillConfig.groupID then
			return true
		end
	end
end

----------------------------------------- msg -------------------------------------------------

-- 查询
function sendQuery(human, heroID, heroIndex)
	local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
	if not heroGrid then return end

	local msgRet = Msg.gc.GC_BINGSHU_QUERY
	msgRet.heroID = heroID
	msgRet.heroIndex = heroIndex
	msgRet.skills[0] = 0
	for i = 1, BINGSHU_MAXCNT do
		local grid = getBingshuGrid(heroGrid, i)
		if grid then
			msgRet.skills[0] = msgRet.skills[0] + 1
			BingshuGrid.makeBingshuNet(msgRet.skills[msgRet.skills[0]], grid, i)
		end
	end
	msgRet.openList[0] = BINGSHU_MAXCNT
	for i = 1, msgRet.openList[0] do
		msgRet.openList[i] = BINGSHU_OPEN_LIST[i] or 0
	end

	for i = 1, BINGSHU_MAXCNT do
		msgRet.red[i] = isBingShuDotByIndex(human, heroGrid, i) and 1 or 0
	end
	msgRet.red[0] = BINGSHU_MAXCNT
--	Msg.trace(msgRet) 
	Msg.send(msgRet, human.fd)
end

-- 可激活列表
function sendLearnList(human, heroID, heroIndex, index)
	local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
	if not heroGrid then return end

	local learnList = getCanLearnList()
	local msgRet = Msg.gc.GC_BINGSHU_LEARN_LIST
	msgRet.list[0] = 0
	for _, skillID in ipairs(learnList) do
		if msgRet.list[0] >= #msgRet.list then
			break
		end
		if not isLearnSkill(heroGrid, skillID) then
			msgRet.list[0] = msgRet.list[0] + 1
			BingshuGrid.makeBingshuLearnNet(msgRet.list[msgRet.list[0]], skillID)
		end
	end
	msgRet.index = index
--	Msg.trace(msgRet)
	Msg.send(msgRet, human.fd)
end


-- 学习技能
function learnSkill(human, heroID, heroIndex, index, skillID)
	local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
	if not heroGrid then
		return Broadcast.sendErr(human, Lang.DRILL_CHOOSE_FRIEND_ERR_INFO)
	end

	if index < 1 or index > BINGSHU_MAXCNT then
		return Broadcast.sendErr(human, Lang.DRILL_CHOOSE_FRIEND_ERR_INFO)
	end
	local heroConfig = HeroExcel.hero[heroGrid.id]
	if heroGrid.star < BINGSHU_OPEN_LIST[index] then
		return
	end

	if getBingshuGrid(heroGrid, index) then
		return Broadcast.sendErr(human, Lang.SKIN_PARAM_ERR)
	end

	local config = FuwenExcel.skill[skillID]
	if not config then return end
	if config.isBingshuSkill ~= 1 then return end
	if config.lv ~= 1 then return end

	for _, item in ipairs(config.bingshuUpNeed) do
		local itemID = item[1]
		local itemCnt = item[2]
		if not BagLogic.checkItemCnt(human, itemID, itemCnt) then
			return Broadcast.sendErr(human, Lang.ABS_ITEM_ERR)
		end
	end

	for _, item in ipairs(config.bingshuUpNeed) do
		local itemID = item[1]
		local itemCnt = item[2]
		BagLogic.delItem(human, itemID, itemCnt, "bingshu")
	end

	local grid = BingshuGrid.create(skillID)
	heroGrid.bingshu = heroGrid.bingshu or {}
	heroGrid.bingshu[index] = grid

	local msgRet = Msg.gc.GC_BINGSHU_LEARN
	msgRet.heroID = heroID
	msgRet.heroIndex = heroIndex
	BingshuGrid.makeBingshuNet(msgRet.data, grid, index)
--	Msg.trace(msgRet)
	Msg.send(msgRet, human.fd)

	ObjHuman.doCalcHero(human, heroIndex)

	local newcf = FuwenExcel.skill[grid.skillID]
	LiLianLogic.onCallback(human,LiLianLogic.LILIAN_OUTID28,1,newcf.lv)

	HeroLogic.sendHeroBagDynamic(human, heroID, heroIndex)
	sendQuery(human, heroID, heroIndex)
end

function getForgetCost(lv)
	local costs = FuwenExcel.define[1].bingshuForgetCosts
	return costs[lv] or costs[#costs]
end

-- 升级查询
function sendLevelUpQuery(human, heroID, heroIndex, index)
	--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] 收到查询请求: heroID="..(heroID or "nil")..", heroIndex="..(heroIndex or "nil")..", index="..(index or "nil"))
	
	local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
	if not heroGrid then 
		--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] 英雄不存在: heroID="..(heroID or "nil")..", heroIndex="..(heroIndex or "nil"))
		return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
	end
	
	local grid = getBingshuGrid(heroGrid, index)
	if not grid then 
		--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] 兵书格子不存在: heroID="..(heroID or "nil")..", heroIndex="..(heroIndex or "nil")..", index="..(index or "nil"))
		return Broadcast.sendErr(human, "兵书格子不存在")
	end

	local config = FuwenExcel.skill[grid.skillID]
	local nextSkillID = getNextSkillID(grid.skillID)
	local nextConfig = nextSkillID and FuwenExcel.skill[nextSkillID]
	local msgRet = Msg.gc.GC_BINGSHU_LEVELUP_QUERY
	msgRet.heroID = heroID
	msgRet.heroIndex = heroIndex
	
	-- 检查grid和skillID
	if not grid or not grid.skillID then
		--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] ERROR: grid或grid.skillID不存在, grid="..tostring(grid)..", skillID="..(grid and grid.skillID or "nil"))
		return Broadcast.sendErr(human, "兵书数据错误")
	end
	
	-- 检查技能配置
	if not config then
		--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] ERROR: 技能配置不存在, skillID="..grid.skillID)
		return Broadcast.sendErr(human, "技能配置不存在")
	end
	
	BingshuGrid.makeBingshuNet(msgRet.bingshu, grid, index)
	msgRet.upData[0] = 0
	if nextConfig then
		msgRet.upData[0] = 1
		BingshuGrid.makeBingshuLearnNet(msgRet.upData[1], nextSkillID)
	end
	msgRet.forgetCost = getForgetCost(config.lv)
	msgRet.returnItems[0] = config and #config.bingshuForgetReturn or 0
	for i = 1, msgRet.returnItems[0] do
		local itemID = config.bingshuForgetReturn[i][1]
		local itemCnt = config.bingshuForgetReturn[i][2]
		Grid.makeItem(msgRet.returnItems[i], itemID, itemCnt)
	end
	
	-- 检查消息格式
	local protoID = msgRet[1]
	--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] 准备发送消息: protoID="..(protoID or "nil")..", heroID="..heroID..", heroIndex="..heroIndex..", index="..index..", skillID="..(grid.skillID or "nil")..", forgetCost="..msgRet.forgetCost)
	--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] human.fd="..(human.fd or "nil")..", upData[0]="..(msgRet.upData[0] or "nil")..", returnItems[0]="..(msgRet.returnItems[0] or "nil"))
	
	-- 检查bingshu数据
	if msgRet.bingshu then
		--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] msgRet.bingshu存在, index="..(msgRet.bingshu.index or "nil")..", skillID="..(msgRet.bingshu.skill and msgRet.bingshu.skill.skillID or "nil"))
		if msgRet.bingshu.skill then
			--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] msgRet.bingshu.skill.skillID="..(msgRet.bingshu.skill.skillID or "nil")..", skillName="..(msgRet.bingshu.skill.skillName or "nil"))
		else
			--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] WARNING: msgRet.bingshu.skill为nil")
		end
	else
		--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] WARNING: msgRet.bingshu为nil")
	end
	
	-- 检查upData数据
	if msgRet.upData[0] > 0 and msgRet.upData[1] then
		--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] msgRet.upData[1]存在, skillID="..(msgRet.upData[1].skill and msgRet.upData[1].skill.skillID or "nil"))
	end
	
	-- 检查returnItems数据
	if msgRet.returnItems[0] > 0 then
		--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] msgRet.returnItems[0]="..msgRet.returnItems[0])
		for i = 1, msgRet.returnItems[0] do
			if msgRet.returnItems[i] then
				--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] msgRet.returnItems["..i.."]: id="..(msgRet.returnItems[i].id or "nil")..", cnt="..(msgRet.returnItems[i].cnt or "nil"))
			end
		end
	end
	
	if not human.fd then
		--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] ERROR: human.fd为nil，无法发送消息")
		return Broadcast.sendErr(human, "连接已断开")
	end
	
	-- 使用Msg.trace检查消息格式（如果可用）
	-- Msg.trace(msgRet)
	
	Msg.send(msgRet, human.fd)
	--Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] 消息已发送: protoID="..(protoID or "nil")..", heroID="..heroID..", heroIndex="..heroIndex..", index="..index)
end

-- 升级
function levelUp(human, heroID, heroIndex, index)
	local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
	if not heroGrid then return end
	local grid = getBingshuGrid(heroGrid, index)
	if not grid then return end

	local nextSkillID = getNextSkillID(grid.skillID)
	local nextConfig = nextSkillID and FuwenExcel.skill[nextSkillID]
	if not nextConfig then
		return Broadcast.sendErr(human, Lang.BINGSHU_LEVELUP_ERR_FULL)
	end

	for _, item in ipairs(nextConfig.bingshuUpNeed) do
		local itemID = item[1]
		local itemCnt = item[2]
		if not BagLogic.checkItemCnt(human, itemID, itemCnt) then
			return
		end
	end

	for _, item in ipairs(nextConfig.bingshuUpNeed) do
		local itemID = item[1]
		local itemCnt = item[2]
		BagLogic.delItem(human, itemID, itemCnt, "bingshu")
	end

	grid.skillID = nextSkillID
	local msgRet = Msg.gc.GC_BINGSHU_LEVELUP
	msgRet.heroID = heroID
	msgRet.heroIndex = heroIndex
	BingshuGrid.makeBingshuNet(msgRet.bingshu, grid, index)
--	Msg.trace(msgRet)
	Msg.send(msgRet, human.fd)

	ObjHuman.doCalcHero(human, heroIndex)
	sendLevelUpQuery(human, heroID, heroIndex, index)
	sendQuery(human, heroID, heroIndex)
	
	HeroLogic.sendHeroBagDynamic(human, heroID, heroIndex)
end


-- 遗忘
function forget(human, heroID, heroIndex, index)
	local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
	if not heroGrid then return end
	local grid = getBingshuGrid(heroGrid, index)
	if not grid then return end

	local config = FuwenExcel.skill[grid.skillID]
	local needZuanshi = getForgetCost(config.lv)
	if not ObjHuman.checkRMB(human, needZuanshi) then
		return
	end

	ObjHuman.decZuanshi(human, -needZuanshi, "bingshu")
	heroGrid.bingshu[index] = nil	
	BagLogic.addItemList(human, config.bingshuForgetReturn, "bingshu")
	local msgRet = Msg.gc.GC_BINGSHU_FORGET
	msgRet.heroID = heroID
	msgRet.heroIndex = heroIndex
	msgRet.index = index
	Msg.send(msgRet, human.fd)
	ObjHuman.doCalcHero(human, heroIndex)
	
	HeroLogic.sendHeroBagDynamic(human, heroID, heroIndex)
end

BINGSHU_OPEN_TIME = nil
function isBingShuDot(human, heroGrid)
	if not BINGSHU_OPEN_TIME then
--		local d = os.date("*t",time)
		local tmpDate = {}
		tmpDate.year = 2022
		tmpDate.month = 1
		tmpDate.day = 31
		tmpDate.hour = 0
		tmpDate.min = 0
		tmpDate.sec = 0
		BINGSHU_OPEN_TIME = os.time(tmpDate)
	end
	
	if os.time() <= BINGSHU_OPEN_TIME then return -1 end
	if not heroGrid then return end
	if heroGrid.star < BINGSHU_OPEN_LIST[1] then return end

	for i = 1, BINGSHU_MAXCNT do
		if  heroGrid.star < BINGSHU_OPEN_LIST[i] then return end
		local grid = getBingshuGrid(heroGrid, i)
		if grid then
			-- 检测是否能升级
			local nextSkillID = getNextSkillID(grid.skillID)
			local nextConfig = nextSkillID and FuwenExcel.skill[nextSkillID]
			if nextConfig then
				local canUp = true
				for _, item in ipairs(nextConfig.bingshuUpNeed) do
					local itemID = item[1]
					local itemCnt = item[2]
					if BagLogic.getItemCnt(human, itemID) < itemCnt then
						canUp = false
					end
				end 

				if canUp then
					return true
				end
			end					
		else
			local learnList = getCanLearnList()
			local canUp = true
			for i, skillID in ipairs(learnList) do
				canUp = true
				local config = FuwenExcel.skill[skillID]
				for k, v in ipairs(config.bingshuUpNeed) do
					local itemID = v[1]
					local itemCnt = v[2]
					if BagLogic.getItemCnt(human, itemID) < itemCnt then
						canUp = false
					end
				end				
			
				if canUp then
					return true
				end				
			end
			
		end
	end
end

function isBingShuDotByIndex(human, heroGrid, index)
	if not BINGSHU_OPEN_TIME then
--		local d = os.date("*t",time)
		local tmpDate = {}
		tmpDate.year = 2022
		tmpDate.month = 1
		tmpDate.day = 31
		tmpDate.hour = 0
		tmpDate.min = 0
		tmpDate.sec = 0
		BINGSHU_OPEN_TIME = os.time(tmpDate)
	end

	if os.time() <= BINGSHU_OPEN_TIME then return end
	if not heroGrid then return end
	if heroGrid.star < BINGSHU_OPEN_LIST[index] then return end

	local grid = getBingshuGrid(heroGrid, index)
	if grid then
		-- 检测是否能升级
		local nextSkillID = getNextSkillID(grid.skillID)
		local nextConfig = nextSkillID and FuwenExcel.skill[nextSkillID]
		if nextConfig then
			local canUp = true
			for _, item in ipairs(nextConfig.bingshuUpNeed) do
				local itemID = item[1]
				local itemCnt = item[2]
				if BagLogic.getItemCnt(human, itemID) < itemCnt then
					canUp = false
				end
			end 

			if canUp then
				return true
			end
		end					
	else
		local learnList = getCanLearnList()
		local canUp = true
		for i, skillID in ipairs(learnList) do
			canUp = true
			local config = FuwenExcel.skill[skillID]
			for k, v in ipairs(config.bingshuUpNeed) do
				local itemID = v[1]
				local itemCnt = v[2]
				if BagLogic.getItemCnt(human, itemID) < itemCnt then
					canUp = false
				end
			end				
		
			if canUp then
				return true
			end				
		end
		
	end

end