local ItemEntity = require "app/userdata/bag/item_entity"

local ItemConst = require "app/module/item/item_const"
local ItemData = class("ItemData", BaseData)

local RECOVERY_TYPE_TIME = 1
local RECOVERY_TYPE_DAILY = 2

local CACHE_ITEM = {
	id = 0,
	count = 0
}

function ItemData:ctor()
	self.items = {}
end

function ItemData:init(data)
	self.items = {}
	data = data or {}
	if data.items then
		for _, info in pairs(data.items) do
			if info.id == GConst.ItemConst.ITEM_ID_GEM then
				local parmas = {}
				parmas.user_gem = info.count
				CS.ThinkingAnalytics.ThinkingAnalyticsAPI.UserSet(parmas)
			elseif info.id == GConst.ItemConst.ITEM_ID_GOLD then
				local parmas = {}
				parmas.user_gold = info.count
				CS.ThinkingAnalytics.ThinkingAnalyticsAPI.UserSet(parmas)
			end
			if info.id == GConst.ItemConst.ITEM_ID_VIT then
				DataManager.PlayerData:setVit(info.count)
			end
			if info.id == GConst.ItemConst.ITEM_ID_ARENA_TICKET then
				DataManager.PlayerData:setArenaTicket(info.count)
			end
			self:_add(info.id, info.count)
		end
	end
	self.recoveryList = {}
	self.recoveryMap = {}
	if data.recoveries then
		local recoveryCfg = ConfigManager:getConfig("recovery")
		for k, v in pairs(data.recoveries) do
			local recoveryInfo = recoveryCfg[v.id]
			if recoveryInfo then
				local obj = {
					id = v.id,
					ts = v.ts // 1000,
					limit = recoveryInfo.limit,
					recoveryType = recoveryInfo.type,
					time = recoveryInfo.time
				}
				self.recoveryMap[v.id] = obj
				table.insert(self.recoveryList, obj)
			end
		end
	end
	self.initDay = Time:getBeginningOfServerToday()
	self.data.dirty = false
end

function ItemData:_add(id, num)
	self.items[id] = ItemEntity:create(id, num)
end

function ItemData:clear()
	self.items = {}
end

-- 根据id获取道具
function ItemData:getItemById(id)
	if self.items[id] then
		return self.items[id]
	end
	local item = ItemEntity:create(id, 0)
	self.items[id] = item
	return self.items[id]
end

-- 获取所有道具数据
function ItemData:getAllItems()
	return self.items
end

function ItemData:getItemNumById(id)
	local num
	if self.items[id] then
		num = self.items[id]:getNum()
	else
		num = 0
	end
	return num
end

function ItemData:getVit()
	return self:getItemNumById(GConst.ItemConst.ITEM_ID_VIT)
end

function ItemData:addItemReward(item, itemGetType)
	CACHE_ITEM.id = GFunc.getRewardId(item)
	CACHE_ITEM.count = GFunc.getRewardNum(item)
	self:addItem(CACHE_ITEM, itemGetType)
end

function ItemData:addItemCost(cost, itemGetType)
	CACHE_ITEM.id = GFunc.getRewardId(cost)
	CACHE_ITEM.count = -GFunc.getRewardNum(cost)
	self:addItem(CACHE_ITEM, itemGetType)
	self:setDirty()
end

function ItemData:addItemCosts(costs, itemGetType)
	if not costs then
		return
	end
	for _, cost in ipairs(costs) do
		self:addItemCost(cost, itemGetType)
	end
end

function ItemData:addItem(data, itemGetType)
	if data == nil then
		return
	end

	if EDITOR_MODE then
		if not itemGetType then
			local params = {
				content = "ItemData addItem has no itemGetType",
				boxType = GConst.MESSAGE_BOX_TYPE.MB_OK,
				okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK),
			}
			GFunc.showMessageBox(params)
			Logger.log("ItemData addItem has no itemGetType")
		end
	end

	self:_addItemNumById(data.id, data.count)

	if data.id == GConst.ItemConst.ITEM_ID_GEM then
		if data.count < 0 then
			ModuleManager.TaskManager:addTaskProgress(GConst.TaskConst.TASK_TYPE.X_GEM_COST, -data.count)
			BIReport:postGemUse(data.count, itemGetType, data.id)
		else
			ModuleManager.TaskManager:addTaskProgress(GConst.TaskConst.TASK_TYPE.X_GEM_GOT, data.count)
			BIReport:postGemGet(data.count, itemGetType, data.id)
		end
		CS.ThinkingAnalytics.ThinkingAnalyticsAPI.UserAdd("user_gem", data.count)
	elseif data.id == GConst.ItemConst.ITEM_ID_GOLD then
		if data.count < 0 then
			ModuleManager.TaskManager:addTaskProgress(GConst.TaskConst.TASK_TYPE.X_GOLD_COST, -data.count)
			BIReport:postGemUse(data.count, itemGetType, data.id)
		else
			ModuleManager.TaskManager:addTaskProgress(GConst.TaskConst.TASK_TYPE.X_GOLD_GOT, data.count)
			BIReport:postGemGet(data.count, itemGetType, data.id)
		end
		CS.ThinkingAnalytics.ThinkingAnalyticsAPI.UserAdd("user_gold", data.count)
	elseif data.id == GConst.ItemConst.ITEM_ID_VIT then
		if data.count < 0 then
			ModuleManager.TaskManager:addTaskProgress(GConst.TaskConst.TASK_TYPE.X_VIT_COST, -data.count)
			BIReport:postVitUse(data.count, itemGetType)
		else
			BIReport:postVitGet(data.count, itemGetType)
		end
	elseif data.id == GConst.ItemConst.ITEM_ID_RUNES then
		if data.count > 0 then
			ModuleManager.TaskManager:addTaskProgress(GConst.TaskConst.TASK_TYPE.X_RUNES_GETED_MATERIALS, data.count)
			BIReport:postItemGet(data.count, data.id, itemGetType)
		else
			BIReport:postItemUse(data.count, data.id, itemGetType)
		end
	else
		if data.count < 0 then
			BIReport:postItemUse(data.count, data.id, itemGetType)
		else
			BIReport:postItemGet(data.count, data.id, itemGetType)
		end
	end
end

function ItemData:addItemNumById(id, num, itemGetType)
	CACHE_ITEM.id = id
	CACHE_ITEM.count = num
	self:addItem(CACHE_ITEM, itemGetType)
end

function ItemData:_addItemNumById(id, num)
	if num == nil then
		return
	end
	local isFull = false
	if id == ItemConst.ITEM_ID_VIT then
		local maxVit = DataManager.PlayerData:getMaxVit()
		local currentCount = DataManager.PlayerData:getVit()
		isFull = currentCount >= maxVit
	end
	if self.items[id] then
		self.items[id]:addNum(num)
	else
		if id == ItemConst.ITEM_ID_VIT then
			DataManager.PlayerData:setVit(num)
		end
		self:_add(id, num)
	end
	if self.items[id]:getItemType() == ItemConst.ITEM_TYPE.HERO_FRAGMENT then
		if num > 0 then
			ModuleManager.TaskManager:addTaskProgress(GConst.TaskConst.TASK_TYPE.X_HERO_FRAGMENT_GOT, num)
		end
		DataManager.HeroData:setDirty()
	end

	if id == ItemConst.ITEM_ID_VIT then
		DataManager.PlayerData:setVit(self.items[id]:getNum())
		if isFull then
			local maxVit = DataManager.PlayerData:getMaxVit()
			local currentCount = DataManager.PlayerData:getVit()
			local isNewFull = currentCount >= maxVit
			if not isNewFull then
				self:resetItemRecoveryTime(ItemConst.ITEM_ID_VIT)
			end
		end
	elseif id == ItemConst.ITEM_ID_BOUNTY_EXP then
		DataManager.BountyData:addExp(num)
	elseif id == ItemConst.ITEM_ID_ARENA_BOUNTY_EXP then
		DataManager.ArenaBountyData:addExp(num)
	elseif id == ItemConst.ITEM_ID_EXP then
		DataManager.PlayerData:addExp(num)
	end
	self:setDirty()
end

-- 清空道具，用于活动重开的时候清除对应道具
function ItemData:clearItemCount(id)
	if not self.items[id] then
		return
	end
	self.items[id]:setNum(0)
	self:setDirty()
end

function ItemData:setDirty()
	self.data.dirty = not self.data.dirty
end

-- 是否按时间恢复
function ItemData:isTimingRecovery(itemId)
	local data = self.recoveryMap[itemId]
	if not data then
		return -1
	end
	return data.type == RECOVERY_TYPE_TIME
end

function ItemData:getTimelyItemRecoveryTime(itemId)
	local data = self.recoveryMap[itemId]
	if not data then
		return -1
	end
	-- 计算当前值和最大值
	local currNum = self:getItemNumById(itemId)
	-- 如果是最大，则重置上一次时间为当前时间
	if currNum >= data.limit then
		return -1
	end
	-- 计算时间
	if self:isTimingRecovery(itemId) then
		local remainTime = data.ts + data.time  - Time:getServerTime()
		return remainTime
	else
		-- 无自动恢复时间
		return -1
	end
end

-- 按时间回复的在此回复
function ItemData:recoveryItem(data)
	-- 计算已经达到上限
	local itemId = data.id
	local currNum = self:getItemNumById(itemId)
	if currNum >= data.limit then
		return
	end
	-- 计算恢复间隔
	local nowTime = Time:getServerTime()
	local diffTime = nowTime - data.ts -- 上次回复时间，此处计算离线总共回复多少个
	if diffTime <= 0 then
		return
	end
	-- 计算增加数量
	local recoverTime = data.time
	local addCount = math.floor(diffTime / recoverTime)
	if addCount <= 0 then
		return
	end
	-- 计算此次实际增加数量
	local addAfterNum = currNum + addCount
	if addAfterNum > data.limit then
		addCount = data.limit - currNum
	end
	-- 根据实际增加的数量，计算恢复时间
	data.ts = data.ts + recoverTime * addCount
	self:addItemNumById(itemId, addCount, BIReport.ITEM_GET_TYPE.RECOVERY_TIME)
end

-- 每日回复的在此回复
function ItemData:recoveryDailyItem(data)
	if not self:isDayChange() then
		return
	end

	local itemId = data.id
	local currNum = self:getItemNumById(itemId)
	if currNum < data.limit then
		self:addItemNumById(itemId, data.limit - currNum, BIReport.ITEM_GET_TYPE.CROSS_DAY)
	end
end

function ItemData:resetItemRecoveryTime(itemId)
	local obj = self.recoveryMap[itemId]
	if obj then
		obj.ts = Time:getServerTime()
	-- else
	-- 	local obj = {
	-- 		id = v.id,
	-- 		ts = v.ts // 1000,
	-- 		limit = recoveryInfo.limit,
	-- 		recoveryType = recoveryInfo.type,
	-- 		time = recoveryInfo.time
	-- 	}
	-- 	self.recoveryMap[v.id] = obj
	-- 	table.insert(self.recoveryList, obj)
	end
end

function ItemData:updateCd()
	if not self.recoveryList then
		return
	end
	for i, v in ipairs(self.recoveryList) do
		if v.recoveryType == RECOVERY_TYPE_DAILY then
			self:recoveryDailyItem(v) -- 每日的直接加满
		else
			self:recoveryItem(v) 		-- 根据间隔时间增加
		end
	end
	self.initDay = Time:getBeginningOfServerToday()
end

function ItemData:isDayChange()
	return self.initDay ~= Time:getBeginningOfServerToday()
end

return ItemData