
local GetOrCreateSquare = VLF.GetOrCreateSquare
local SpawnZombiesAroundXY = VLZB.SpawnZombiesAroundXY
local RemoveItemInContainer = VLIT.RemoveItemInContainer
local VLF_var_itemList = VLF.var.itemList

local GetModDataReliefSupplyEvent = VLERS.GetModDataReliefSupplyEvent
local HasTimePassedInHours = VLF.HasTimePassedInHours
local PlaySound_Helicopter = VLERS.PlaySound_Helicopter
local RemoveSupplysQuestList = VLERS.RemoveSupplysQuestList
local BroadCastAboutSupplyDropped = VLERS.BroadCastAboutSupplyDropped
local RegisterReliefCrateSpawn = VLERS.RegisterReliefCrateSpawn
local UpdateSupplyLootedData = VLERS.UpdateSupplyLootedData
local RemoveCrateModData = VLERS.RemoveCrateModData
local UpdatePlayerGMDKnewReliefSupply = VLERS.UpdatePlayerGMDKnewReliefSupply
local RemoveGMDSupplyID = VLERS.RemoveGMDSupplyID
local UpdateSpawnedData = VLERS.UpdateSpawnedData

local cSprite = VLERS.cSprite
local requiredHoursToStartEvent = VLERS.requiredHoursToStartEvent

local reliefSupplyRules = {
	{
		minDay = 0,        	-- từ ngày 0	--FIXME: 0
		cooldownDays = 0.5,	--FIXME: 0.5
		chance = 1 / 12	--FIXME: 1 / 12		-- ~8% mỗi tiếng	~trung bình 0.5 + 0.5 ngày 1 lần
	},
	{
		minDay = 30,      	-- sau 1 tháng	--FIXME: 30
		cooldownDays = 0.5,	--FIXME: 0.5
		chance = 1 / 36		--FIXME: 1 / 36		-- ~2.78% mỗi tiếng	~trung bình 1.5 + 0.5 ngày 1 lần
	},
	{
		minDay = 90,       -- sau 3 tháng
		cooldownDays = 1,
		chance = 1 / 48	-- ~2% mỗi tiếng	~trung bình 2 + 1 ngày 1 lần
	},
	{
		minDay = 365,      -- sau 1 năm
		cooldownDays = 1.5,
		chance = 1 / 60	-- ~1.66% mỗi tiếng	~trung bình 2.5 + 1.5 ngày 1 lần
	}
}

--Chọn tỉ lệ và cooldown theo thời gian tồn tại của World
local function GetReliefSupplyRule(worldAgeDays)
	local selected = reliefSupplyRules[1]

	for _, rule in ipairs(reliefSupplyRules) do
		if worldAgeDays >= rule.minDay then
			selected = rule
		else
			break
		end
	end

	return selected
end

--Danh sách các khu vực thả hòm cứu trợ
local reliefAreas = {
	{ x = 12011, y = 1208, x2 = 13994, y2 = 3467, weight = 400 },		--Louisville	--400
	{ x = 11188, y = 6607, x2 = 12116, y2 = 7095, weight = 100 },		--West Point	--100
	{ x = 10582, y = 9418, x2 = 10935, y2 = 10649, weight = 100 },	--Muldraugh		--100	
	{ x = 9789, y = 12601, x2 = 10385, y2 = 13148, weight = 100 },	--March Ridge	--100	
	{ x = 7979, y = 11439, x2 = 8413, y2 = 11806, weight = 100 },		--Rosewood		--100	
	{ x = 7084, y = 8186, x2 = 7368, y2 = 8434, weight = 100 },		--Fallas Lake	--100	
	{ x = 5911, y = 5198, x2 = 6839, y2 = 5570, weight = 100 },		--Riverside		--100	
	{ x = 1480, y = 5702, x2 = 2473, y2 = 6515, weight = 100 },		--Brandenburg	--100	
	{ x = 293, y = 9540, x2 = 960, y2 = 9940, weight = 100 },			--Ekron			--100	
	{ x = 3389, y = 10862, x2 = 3788, y2 = 11262, weight = 100 },		--Echo Creek	--100	
	{ x = 1724, y = 13816, x2 = 3130, y2 = 14966, weight = 100 },		--Irvington		--100
}

local function GetRandomReliefAreaByWeight()
	local totalWeight = 0

	for _, area in ipairs(reliefAreas) do
		totalWeight = totalWeight + (area.weight or 0)
	end

	if totalWeight <= 0 then return nil end

	local roll = ZombRand(totalWeight)
	local current = 0

	for _, area in ipairs(reliefAreas) do
		current = current + (area.weight or 0)
		if roll < current then
			return area
		end
	end

	return nil
end

--Chọn tọa độ XY thả Hòm Cứu Trợ
local function GetRandomXYInReliefAreas()	--local x, y = GetRandomXYInReliefAreas()
	--chọn khu vực theo weight
	local area = GetRandomReliefAreaByWeight()
	if not area then return nil, nil end
	
	local rx, ry
	local questMD_Events_ReliefSupply = GetModDataReliefSupplyEvent()
	
	for i = 1, 50 do
		--chọn ngẫu nhiên tọa độ
		rx = ZombRand(area.x, area.x2 + 1)
		ry = ZombRand(area.y, area.y2 + 1)
		
		--nếu không trùng với tọa độ XY các supply khác thì break
		local sameXY = false
		
		for _, data in pairs(questMD_Events_ReliefSupply) do
			if type(data) == "table" and data.x and data.y then
				if rx == data.x and ry == data.y then
					sameXY = true
					break
				end
			end
		end
		
		if sameXY == false then
			return rx, ry
		end
	end
	
	return nil, nil
end

--Chọn loại supply. 1 trong 3 loại: 1 - Thực phẩm, 2 - dược phẩm, 3 - vũ khí
local function GetSupplyTypeID()	--local supplyTypeID = GetSupplyTypeID()
	local r = ZombRand(3) + 1
	return r	
end

--Lấy FullName các item sẽ thêm vào Supply
local function GetRandomItemsInSupply(supplyTypeID)	--local itemFNameList = GetRandomItemsInSupply(supplyTypeID)
	supplyTypeID = supplyTypeID or 1
	local itemList = {}
	if supplyTypeID == 1 then 	--supply thực phẩm
		--lấy 3 loại đồ hộp thức ăn
		for i = 1, 3 do
			local itemFName = VLF_var_itemList["foodItems"][ZombRand(#VLF_var_itemList["foodItems"]) + 1]
			local quantity = ZombRand(5,17)
			table.insert(itemList, {itemFName = itemFName, quantity = quantity})
		end
		
	elseif supplyTypeID == 2 then 	--supply dược phẩm
		--5 loại thuốc
		for i = 1, 5 do
			local itemFName = VLF_var_itemList["medicalItems"][ZombRand(#VLF_var_itemList["medicalItems"]) + 1]
			local quantity = ZombRand(5,11)
			if string.find(itemFName, "Box") then
				quantity = ZombRand(3) + 1
			end
				
			table.insert(itemList, {itemFName = itemFName, quantity = quantity})
		end
	
	else		--supply vũ khí
		--2 đến 4 loại súng
		--1 đến 3 phụ kiện
		--3 loại đạn, số lượng

		--Súng --cân nặng 4.0/1
		for i = 1, ZombRand(2, 5) do
			local itemFName = VLF_var_itemList["rangedWpnItems"][ZombRand(#VLF_var_itemList["rangedWpnItems"]) + 1]
			local quantity = 1
			table.insert(itemList, {itemFName = itemFName, quantity = quantity})
		end
		
		--Phụ kiện súng --cân nặng 0.5/1
		for i = 1, ZombRand(1, 4) do
			local itemFName = VLF_var_itemList["weaponPartItems"][ZombRand(#VLF_var_itemList["weaponPartItems"]) + 1]
			local quantity = 1
			table.insert(itemList, {itemFName = itemFName, quantity = quantity})
		end
		
		--Hộp đạn --cân nặng 1.2/1
		for i = 1, 3 do
			local itemFName = VLF_var_itemList["ammoItems"][ZombRand(#VLF_var_itemList["ammoItems"]) + 1]
			local quantity = ZombRand(3, 11)
			table.insert(itemList, {itemFName = itemFName, quantity = quantity})
		end
		
	end
	
	--Debug print item list thêm vào crate
	--for _, data in pairs(itemList) do
		--print("Server---GetRandomItemsInSupply---supplyTypeID, itemFName, quantity= ", supplyTypeID, data.itemFName, data.quantity)
	--end
	return itemList
end

--Lấy SupplyID không bị trùng
local function GetSupplyID()	
	local questMD_Events_ReliefSupply = GetModDataReliefSupplyEvent()
	local gameTime = getGameTime()
    local supplyID
    local isExisting = true
	local rNumber = 0
	local tries = 0
    local maxTries = 100
	
	while isExisting do
        supplyID = math.floor(gameTime:getMinutesStamp()) + rNumber 
        isExisting = false
		
		if questMD_Events_ReliefSupply[supplyID] then
			rNumber = ZombRand(10000, 20000)
			tries = tries + 1
			isExisting = true
		end
		
		if tries >= maxTries then
			return nil
		end
    end
	
	return supplyID
end

--Tính tỉ lệ và kiểm tra cooldown để Kích hoạt Event Relief Supply
--Nếu kích hoạt thì lưu ModData và gửi cho các client
function VLERS.TryTriggerReliefSupply(alwaysTrigger)	--local isTrigger, supplyID = TryTriggerReliefSupply()
	alwaysTrigger = alwaysTrigger or false
	local world = getGameTime()
	local currentHour = world:getWorldAgeHours()
	
	--Sau 7 ngày mới xuất hiện sự kiện này
	--if currentHour < 168 then return false, nil end
	
	local worldAgeDays = world:getWorldAgeDaysSinceBegin()

	local rule = GetReliefSupplyRule(worldAgeDays)

	--ModData để lưu cooldown
	local questMD_Events_ReliefSupply = GetModDataReliefSupplyEvent()
	
	local lastTriggerHour = questMD_Events_ReliefSupply["lastTriggerHour"] or -999999
	local cooldownHours = rule.cooldownDays * 24

	--đang cooldown
	if not alwaysTrigger then
		if currentHour - lastTriggerHour < cooldownHours then
			return false, nil
		end
	end

	--random theo tỉ lệ. --nếu kích hoạt thì lưu ModData
	local r = ZombRandFloat(0, 1)
	--print("--------RANDOM NUMBER, rule.chance: ", r, rule.chance)
	if r <= rule.chance or alwaysTrigger == true then
		questMD_Events_ReliefSupply["lastTriggerHour"] = currentHour
		
		local x, y = GetRandomXYInReliefAreas()
		if not x or not y then 
			--print("------KHONG CO TOA DO X Y HOP LE DE SPAWN")
			return false, nil 
		end
		
		local gameTime = getGameTime()
		local supplyID = GetSupplyID()
		if not supplyID then return false, nil end
		
		questMD_Events_ReliefSupply[supplyID] = questMD_Events_ReliefSupply[supplyID] or {}

		local supplyTypeID = GetSupplyTypeID()
		local itemFNameList = GetRandomItemsInSupply(supplyTypeID)
		
		local activateStartHour = gameTime:getWorldAgeHours()
		
		local instantSpawn = false
		local sq = getCell():getGridSquare(x, y, 0)
		if sq then instantSpawn = true end
		
		--print("Server---TryTriggerReliefSupply---Triggered!---supplyID, x, y, supplyTypeID, activateStartHour= ", supplyID, x, y, supplyTypeID, activateStartHour, instantSpawn)
		--print("------- getPlayer():teleportTo("..tostring(x)..","..tostring(y+3)..",0)")
		
		RegisterReliefCrateSpawn(x, y, supplyID, supplyTypeID, cSprite, activateStartHour, itemFNameList, instantSpawn)
		
		--gửi tín hiệu qua radio thông báo đã thả Relief Supply. 
		if not isServer() then	--SP
			BroadCastAboutSupplyDropped(getPlayer(), supplyID)
		end
			
		if isServer() then
			sendServerCommand("Event_ReliefSupply_C", "BroadCastSupplyDropped_C", {supplyID = supplyID})
		end
		
		return true, supplyID
	end

	return false, nil
end
local TryTriggerReliefSupply = VLERS.TryTriggerReliefSupply

local _hour = 1
 
local function EveryHours_TriggerAndSendBroadCast()
	--Kiểm tra world đã tồn tại ít nhất 7 ngày
	if HasTimePassedInHours(requiredHoursToStartEvent) ~= true then return end
	 
	if _hour % 3 == 0 then	
		local questMD_Events_ReliefSupply = GetModDataReliefSupplyEvent()
		
		--Gửi Broadcast thông báo Tất cả Supply Dropped mỗi 3 tiếng
		for supplyID, data in pairs(questMD_Events_ReliefSupply) do
			if type(data) == "table" then
				--nếu supply chưa bị lấy
				if not data.looted then
					--print("Server---EveryHours_TriggerAndSendBroadCast---supplyID DROPPED= ", supplyID)
					if not isServer() then	--SP
						BroadCastAboutSupplyDropped(getPlayer(), supplyID)
					end
						
					if isServer() then
						sendServerCommand("Event_ReliefSupply_C", "BroadCastSupplyDropped_C", {supplyID = supplyID})
					end
					
					--Supply sau 96 tiếng chưa bị loot (không rõ lý do) thì set looted
					local currentHour = getGameTime():getWorldAgeHours()
					local elapsedHours = currentHour - (data.activateStartHour or currentHour)
					if elapsedHours > 96 then	--FIXME: 96
						print("Server---EveryHours_TriggerAndSendBroadCast---Set LOOTED Supply Exist Over 96h= ", supplyID)
						UpdateSupplyLootedData(supplyID, true, false)
					end
				end
			end
		end
		
		--Xóa supplyID đang show trên Quest List nếu không còn data
		if not isServer() then
			RemoveSupplysQuestList()
		end	
		
		--Không có supply nào đã drop thì báo cho các client để xóa hết quest list supplyID nếu có
		if isServer() then
			sendServerCommand("Event_ReliefSupply_C", "RemoveSupplysQuestList_C", {})
		end
	end
	
	--Kích Hoạt Event mỗi tiếng --Thả Crate nếu kích hoạt
	TryTriggerReliefSupply()
	
	--[[
	--Kích Hoạt Event mỗi tiếng --Thả Crate nếu kích hoạt
	local isTrigger, supplyID = TryTriggerReliefSupply()
	
	if isTrigger == true and supplyID then
		--gửi tín hiệu qua radio thông báo đã thả Relief Supply. 
		if not isServer() then	--SP
			BroadCastAboutSupplyDropped(getPlayer(), supplyID)
		end
			
		if isServer() then
			sendServerCommand("Event_ReliefSupply_C", "BroadCastSupplyDropped_C", {supplyID = supplyID})
		end
	end
	]]

	_hour = _hour + 1	
end
Events.EveryHours.Remove(EveryHours_TriggerAndSendBroadCast)
Events.EveryHours.Add(EveryHours_TriggerAndSendBroadCast)
 
--Crate có tỉ lệ bị NPC loot nếu đang không được load. --Check mỗi 10 phút: Crate có bị NPC lấy mất
local function EveryTenMinutes_CheckReliefSupplyLooted()
	if HasTimePassedInHours(requiredHoursToStartEvent) ~= true then return end
	
    local questMD_Events_ReliefSupply = GetModDataReliefSupplyEvent()
    if not questMD_Events_ReliefSupply then return end

	local gameTime = getGameTime()
	local worldAgeDays = gameTime:getWorldAgeDaysSinceBegin()
	local currentHour = gameTime:getWorldAgeHours()
	 
    for supplyID, data in pairs(questMD_Events_ReliefSupply) do
		--Chỉ check supply chưa bị loot
        if type(data) == "table" and data.x and not data.looted then
			local skip = false
            local elapsedHours = currentHour - (data.activateStartHour or currentHour)

            --BỎ QUA nếu square để add Crate đang được load. --Tránh trường hợp player đang load thì bị xóa item trong Crate
            local square = getCell():getGridSquare(data.x, data.y, 0)
            if square and square:getChunk() then
				skip = true
            end
			
			if skip == false then
				--Xác định tỉ lệ theo tuổi world. Tỉ lệ áp dụng cho tính theo tiếng: 3 -> 3% mỗi tiếng -> 3%/6 mỗi 10 phút
				local chancePercent = 0

				if worldAgeDays <= 30 then								--FIXME: 30
					if elapsedHours < 3 then chancePercent = 3		--FIXME: 3
					elseif elapsedHours < 6 then chancePercent = 5		--FIXME: 5
					elseif elapsedHours < 12 then chancePercent = 10	--FIXME: 10
					elseif elapsedHours < 24 then chancePercent = 20	--FIXME: 20
					else chancePercent = 30 end							--FIXME: 30
					--print("Server---EveryTenMinutes_CheckReliefSupplyLooted---worldAgeDays, elapsedHours, chancePercent= ", worldAgeDays, elapsedHours, chancePercent)
				elseif worldAgeDays <= 180 then
					if elapsedHours < 3 then chancePercent = 2
					elseif elapsedHours < 6 then chancePercent = 4
					elseif elapsedHours < 12 then chancePercent = 8
					elseif elapsedHours < 24 then chancePercent = 16
					else chancePercent = 24 end
				else
					if elapsedHours < 3 then chancePercent = 1
					elseif elapsedHours < 6 then chancePercent = 3
					elseif elapsedHours < 12 then chancePercent = 6
					elseif elapsedHours < 24 then chancePercent = 12
					else chancePercent = 18 end
				end

				--Vì check mỗi 10 phút → chia 6
				local finalChance = chancePercent / 100 / 6

				if ZombRandFloat(0, 1) <= finalChance then
					print("Server---EveryTenMinutes_CheckReliefSupplyLooted---Supply LOOTED by NPC---supplyID= ", supplyID)
					--update ModData khi đã bị lấy
					UpdateSupplyLootedData(supplyID, true, false)
				end
			end
        end
    end
end
Events.EveryTenMinutes.Remove(EveryTenMinutes_CheckReliefSupplyLooted)
Events.EveryTenMinutes.Add(EveryTenMinutes_CheckReliefSupplyLooted)

--Spawn Crate của Event ReliefSupply. Add Crate tại x, y, z. Add tất cả item trong itemFNameList vào Crate
local function SpawnReliefSupplyCrate(supplyID, x, y, z)
	if not supplyID then return false end
	if not x or not y or not z then return false end
	
	print("Server---SpawnReliefSupplyCrate---Crate Added---supplyID, x, y, z= ", supplyID, x, y, z)
	local questMD_Events_ReliefSupply = GetModDataReliefSupplyEvent()
	local supplyData = questMD_Events_ReliefSupply[supplyID]
	if not supplyData then return false end
	
	--Crate đã spawn thì return
	if supplyData.spawned then return false end

	local square = GetOrCreateSquare(x, y, z)
	if not square then return false end

	--Tạo crate
	local crate = IsoThumpable.new(
		getCell(),
		square,
		supplyData.crateSprite or cSprite,
		false
	)
	crate:setIsContainer(true)
	crate:setIsThumpable(false)
	square:AddSpecialObject(crate)

	--Add item vào crate
	local container = crate:getContainer()
	if container then
		for _, itemData in ipairs(supplyData.itemFNameList or {}) do
			if itemData and itemData.quantity and itemData.quantity >= 1 then
				for i = 1, itemData.quantity do
					container:AddItem(itemData.itemFName)
				end
			end
		end
	end
	
	--Add ModData cho Crate
	crate:getModData().VL_ReliefSupplyID = supplyID
	
	--sync MP
	local index = square:getObjects():size() - 1	--Vì crate vừa add thì nó luôn nằm ở cuối danh sách array
	square:transmitAddObjectToSquare(crate, index)
	--crate:transmitModData()
	
	--update spawned data
	UpdateSpawnedData(supplyID, true, x, y, z)	
	
	--add zombies quanh Crate NẾU thời điểm spawn khác thời điểm hiện tại (Giả định Crate dropped và các zombie đã bu tới theo tiếng động)
	--if currentHour ~= droppedHour then		--ERROR: nếu tua nhanh thì sẽ không đúng time
	if supplyData.instantSpawn ~= true then
		local count = ZombRand(10, 51) -- 10 -> 50
	
		SpawnZombiesAroundXY(x, y, 0, count, "Generic03", 50, 8)
		--print("----------ADD ZOMBIE= supplyData.instantSpawn, count = ", supplyData.instantSpawn, count)
	end
	
	--NẾU thời điểm spawn = thời điểm hiện tại 
	--if currentHour == droppedHour then		--ERROR: nếu tua nhanh thì sẽ không đúng time
	if supplyData.instantSpawn == true then
		--yêu cầu client nào đang load square crate thì play sound Helicopter NẾU thời điểm spawn = thời điểm hiện tại 
		if isServer() then
			sendServerCommand("Event_ReliefSupply_C", "PlaySoundHelocopter_C", {x = x, y = y})
		else --SP
			PlaySound_Helicopter(x, y)
		end
		
		--add sound thu hút zombie NẾU thời điểm spawn = thời điểm hiện tại 
		addSound(square:getFloor(), square:getX(), square:getY(), square:getZ(), 100, 1100) --thu hút zombie 100 ô
	end

	return true
end

--Xóa modData Crate --Xóa item bên trong Crate
local function RemoveItemsAndModDataOfCrate(supplyID, x, y, z)
	local sq = getCell():getGridSquare(x, y, z)
	if sq then
		local objs = sq:getObjects()
		for i = 0, objs:size() - 1 do
			local obj = objs:get(i)
			if obj and obj:getSprite() and obj:getSprite():getName() == cSprite then
				if obj:getModData() and obj:getModData().VL_ReliefSupplyID == supplyID then
					--Xóa tất cả item trong Crate
					local container = obj:getContainer()
					if container then
						--print("Server---RemoveItemsAndModDataOfCrate---REMOVE ITEMS IN CRATE= ")
						local items = container:getItems()
						for j = items:size() - 1, 0, -1 do
							local item = items:get(j)
							if item then
								--container:removeItemOnServer(items[j]) --Not Working
								RemoveItemInContainer(container, item)
							end
						end
					end
					
					--Xóa data của Crate
					print("Server---RemoveItemsAndModDataOfCrate---RemoveCrateModData---supplyID= ", supplyID)
					RemoveCrateModData(obj)
				end
			end
		end
	end
end


--================= ONCLIENTCOMMAND =================--
VLOCC["Event_ReliefSupply"] = VLOCC["Event_ReliefSupply"] or {}

VLOCC["Event_ReliefSupply"]["SpawnSupply"] = function(player, args)		--{supplyID = supplyID, x = square:getX(), y = square:getY(), z = square:getZ()}
	local questMD_Events_ReliefSupply = GetModDataReliefSupplyEvent()
	local supplyID = args.supplyID
	if questMD_Events_ReliefSupply[supplyID] and questMD_Events_ReliefSupply[supplyID].spawned == false then
		SpawnReliefSupplyCrate(supplyID, args.x, args.y, args.z)
		
		if isServer() then
			sendServerCommand("Event_ReliefSupply_C", "UpdateSpawned_C", {supplyID = supplyID, spawned = true})
		end
	end
end
	
VLOCC["Event_ReliefSupply"]["SupplyLooted"] = function(player, args)		--{supplyID = supplyID, isLootedByPlayer = isLootedByPlayer}
	if isServer() then
		UpdateSupplyLootedData(args.supplyID, true, args.isLootedByPlayer)
	end
end

VLOCC["Event_ReliefSupply"]["RemoveDataSupplyID"] = function(player, args)		--{supplyID = supplyID}
	if isServer() then
		RemoveGMDSupplyID(args.supplyID, true)
	end
end

VLOCC["Event_ReliefSupply"]["UpdatePlayerGMDRS"] = function(player, args)		--{supplyID = supplyID}
	UpdatePlayerGMDKnewReliefSupply(player, args.supplyID)
end

VLOCC["Event_ReliefSupply"]["UpdateCrateFakeLootedByNPC"] = function(player, args)		--{supplyID = supplyID, x = x, y = y, z = z}
	--VLF.DelayFunction(function()
		local supplyID = args.supplyID
		RemoveGMDSupplyID(supplyID, true)
		RemoveItemsAndModDataOfCrate(supplyID, args.x, args.y, args.z)
	--end, 5)
end

