-----------------------------------------------------------------------
-- AddOn namespace.
-----------------------------------------------------------------------
local ADDON_NAME, private = ...

local RSRecentlySeenTracker = private.NewLib("RareScannerRecentlySeenTracker")

-- RareScanner database libraries
local RSConfigDB = private.ImportLib("RareScannerConfigDB")
local RSGeneralDB = private.ImportLib("RareScannerGeneralDB")

-- RareScanner internal libraries
local RSConstants = private.ImportLib("RareScannerConstants")
local RSLogger = private.ImportLib("RareScannerLogger")
local RSUtils = private.ImportLib("RareScannerUtils")
local RSTimeUtils = private.ImportLib("RareScannerTimeUtils")

-- Timers
local RESET_RECENTLY_SEEN_TIMER

---============================================================================
-- Tracks notifications
---============================================================================

local recently_seen_entities = {}
local VIGNETTE_ID_SEPARATOR = "-"

local function InitResetRecentlySeenTimer()
	if (RESET_RECENTLY_SEEN_TIMER) then
		return
	end
	
	RESET_RECENTLY_SEEN_TIMER = C_Timer.NewTicker(RSConstants.CHECK_RESET_RECENTLY_SEEN_TMER, function()
		for entityID, entityInfo in pairs (recently_seen_entities) do
			local currenTime = time()
			
			-- If its an entity that spawns only in one spot
			if (type(entityInfo) == "number") then
				if (currenTime > (entityInfo + RSConstants.RECENTLY_SEEN_RESET_TIMER)) then
					--RSLogger:PrintDebugMessage(string.format("ResetRecentlySeen[%s] (mono)", entityID))
					recently_seen_entities[entityID] = nil
					RSGeneralDB.DeleteRecentlySeen(entityID)
				end			
			-- If its an entity that spawns in multiple spots at the same time
			else
				for xy, info in pairs (entityInfo) do
					if (currenTime > (entityInfo[xy].time + RSConstants.RECENTLY_SEEN_RESET_TIMER)) then
						if (RSUtils.GetTableLength(recently_seen_entities[entityID]) == 1) then
							recently_seen_entities[entityID] = nil
							--RSLogger:PrintDebugMessage(string.format("ResetRecentlySeen[%s] (multi/last)", entityID))
							RSGeneralDB.DeleteRecentlySeen(entityID)
							break;
						else
							recently_seen_entities[entityID][xy] = nil
							RSLogger:PrintDebugMessage(string.format("ResetRecentlySeen[%s] (multi)", entityID))
						end
					end
				end
			end
		end
	end)
end

function RSRecentlySeenTracker.AddRecentlySeen(entityID, atlasName, isNavigating)
	if (isNavigating) then
		return
	end
	
	-- Initializes timer
	InitResetRecentlySeenTimer()
	
	local currentTime = time()
	
	-- If not spawning in multiple places at the same time stores only the time
	if (entityID and (RSUtils.Contains(RSConstants.NPCS_WITH_MULTIPLE_SPAWNS, entityID) or RSUtils.Contains(RSConstants.CONTAINERS_WITH_MULTIPLE_SPAWNS, entityID))) then
		-- Extracts info from internal database
		local entityInfo = RSGeneralDB.GetAlreadyFoundEntity(entityID)
		if (entityInfo) then
			if (not recently_seen_entities[entityID]) then
				recently_seen_entities[entityID] = {}
			end
			
			local xy = entityInfo.coordX.."_"..entityInfo.coordY
			recently_seen_entities[entityID][xy] = {}
			recently_seen_entities[entityID][xy].x = entityInfo.coordX
			recently_seen_entities[entityID][xy].y = entityInfo.coordY
			recently_seen_entities[entityID][xy].mapID = entityInfo.mapID
			recently_seen_entities[entityID][xy].atlasName = atlasName
			recently_seen_entities[entityID][xy].time = currentTime
			
			RSGeneralDB.SetRecentlySeen(entityID)
			--RSLogger:PrintDebugMessage(string.format("AddRecentlySeen[%s] (multi) [%s]", entityID, RSTimeUtils.TimeStampToClock(currentTime)))
		end
	-- Otherwise stores also the coordinates
	else
		recently_seen_entities[entityID] = currentTime
		RSGeneralDB.SetRecentlySeen(entityID)
		--RSLogger:PrintDebugMessage(string.format("AddRecentlySeen[%s] (mono) [%s]", entityID, RSTimeUtils.TimeStampToClock(currentTime)))
	end
end

function RSRecentlySeenTracker.RemoveRecentlySeen(entityID)
	local entityInfo = recently_seen_entities[entityID]
	
	if (not entityInfo) then
		return nil
	end
	
	-- If its an entity that spawns only in one spot
	if (type(entityInfo) == "number") then
		--RSLogger:PrintDebugMessage(string.format("RemoveRecentlySeen[%s] (mono)", entityID))
		recently_seen_entities[entityID] = nil
		RSGeneralDB.DeleteRecentlySeen(entityID)
		return nil
	end
	
	-- If its an entity that spawns in multiple spots at the same time
					
	-- Calculates the distance between all of them and the player
	local xyDistances = {}
	
	for xy, info in pairs (entityInfo) do
		local playerMapPosition = C_Map.GetPlayerMapPosition(info.mapID, "player")
		if (playerMapPosition) then
			local x, y = playerMapPosition:GetXY()
			local distance = RSUtils.DistanceBetweenCoords(x, info.x, y, info.y)
			xyDistances[xy] = distance
		end
	end
	
	-- If for whatever reason it couldnt get the players coordinates it will be empty
	if (RSUtils.GetTableLength(xyDistances) == 0) then
		return nil
	end
	
	-- And removes the closest to the player
	local distances = {}
	for xy, distance in pairs (xyDistances) do
		table.insert(distances, distance)
	end
	
	local min = math.min(unpack(distances))
	for xy, distance in pairs (xyDistances) do
		if (distance == min) then
			local x, y = strsplit("_", xy)
			if (RSUtils.GetTableLength(recently_seen_entities[entityID]) == 1) then
				--RSLogger:PrintDebugMessage(string.format("RemoveRecentlySeen[%s,x=%s,y=%s] (multi/last)", entityID, x, y))
				recently_seen_entities[entityID] = nil
				RSGeneralDB.DeleteRecentlySeen(entityID)
			else
				--RSLogger:PrintDebugMessage(string.format("RemoveRecentlySeen[%s,x=%s,y=%s] (multi)", entityID, x, y))
				recently_seen_entities[entityID][xy] = nil
			end
			
			return x, y
		end
	end
end

function RSRecentlySeenTracker.IsRecentlySeen(entityID, x, y)
	if (not entityID) then
		return false
	end
	
	-- If it isnt cached in this session check database 
	local entityInfo = recently_seen_entities[entityID]
	if (not entityInfo) then
		return RSGeneralDB.IsRecentlySeen(entityID)
	end
	
	-- If its an entity that spawns only in one spot
	if (type(entityInfo) == "number") then
		return true
	end
	
	-- If its an entity that spawns in multiple spots then check all the coordinates
	for _, info in pairs (entityInfo) do
		if (info.x == x and info.y == y) then
			return true
		end
	end

	-- Otherwise it isnt recently seen
	return false
end

function RSRecentlySeenTracker.GetAllRecentlySeenSpots()
	return recently_seen_entities
end