local _, namespace = ...
local GuildPing = namespace.GuildPing

local MESSAGE_PREFIX = "GuildPingPlay"
local PROTOCOL_VERSION = "1"
local PRESENCE_TIMEOUT = 150
local HEARTBEAT_INTERVAL = 60

local function NormalizePlayerName(name)
	return tostring(name or ""):lower():gsub("%s+", "")
end

local function GetLocalPlayerName()
	if GetUnitName then
		local name = GetUnitName("player", true)
		if name and name ~= "" then return name end
	end
	if UnitFullName then
		local name, realm = UnitFullName("player")
		if name and realm and realm ~= "" then return name .. "-" .. realm end
		if name then return name end
	end
	return UnitName and UnitName("player") or "player"
end

function GuildPing:IsLookingToPlay()
	local profile = self:GetProfile()
	return profile.settings.lookingToPlay == true
end

function GuildPing:SendLookingToPlayPresence(enabled)
	if not self.gameSocialInitialized or not IsInGuild or not IsInGuild() then
		return nil, "You must be in a guild to advertise game availability."
	end
	local message = enabled and ("L|" .. PROTOCOL_VERSION .. "|C,D,P,F") or ("O|" .. PROTOCOL_VERSION)
	local succeeded, result = pcall(C_ChatInfo.SendAddonMessage, MESSAGE_PREFIX, message, "GUILD")
	if not succeeded or result == false then
		return nil, "WoW could not update your Looking to Play status."
	end
	return true
end

function GuildPing:SetLookingToPlay(enabled)
	local profile = self:GetProfile()
	local wasLooking = profile.settings.lookingToPlay == true
	profile.settings.lookingToPlay = not not enabled
	local sent, errorMessage = self:SendLookingToPlayPresence(profile.settings.lookingToPlay)
	if not sent then
		profile.settings.lookingToPlay = false
		return nil, errorMessage
	end
	if profile.settings.lookingToPlay and not wasLooking then
		self:Print("Looking to Play is on. Guild members with Guild Ping have been notified.")
	elseif not profile.settings.lookingToPlay and wasLooking then
		self:Print("Looking to Play is off.")
	end
	if self.RefreshLookingToPlayUI then self:RefreshLookingToPlayUI() end
	if self.RefreshGamesHub then self:RefreshGamesHub() end
	return true
end

function GuildPing:ToggleLookingToPlay()
	return self:SetLookingToPlay(not self:IsLookingToPlay())
end

function GuildPing:CleanupLookingToPlayPlayers()
	local currentTime = GetTime and GetTime() or 0
	self.lookingToPlayPlayers = self.lookingToPlayPlayers or {}
	for key, player in pairs(self.lookingToPlayPlayers) do
		if currentTime - (tonumber(player.lastSeen) or 0) > PRESENCE_TIMEOUT then
			self.lookingToPlayPlayers[key] = nil
		end
	end
end

function GuildPing:GetLookingToPlayPlayers()
	self:CleanupLookingToPlayPlayers()
	local players = {}
	for _, player in pairs(self.lookingToPlayPlayers or {}) do
		table.insert(players, player)
	end
	table.sort(players, function(left, right)
		return NormalizePlayerName(left.name) < NormalizePlayerName(right.name)
	end)
	return players
end

function GuildPing:HandleGameSocialMessage(prefix, message, channel, sender)
	if not self.gameSocialInitialized or prefix ~= MESSAGE_PREFIX or channel ~= "GUILD"
		or type(message) ~= "string" or type(sender) ~= "string"
		or NormalizePlayerName(sender) == NormalizePlayerName(GetLocalPlayerName()) then
		return
	end
	local messageType, protocol, games = message:match("^([^|]+)|([^|]+)|?(.*)$")
	if protocol ~= PROTOCOL_VERSION then return end
	self.lookingToPlayPlayers = self.lookingToPlayPlayers or {}
	local senderKey = NormalizePlayerName(sender)
	local currentTime = GetTime and GetTime() or 0
	local existingPlayer = self.lookingToPlayPlayers[senderKey]
	local wasRecentlyLooking = existingPlayer
		and currentTime - (tonumber(existingPlayer.lastSeen) or 0) <= PRESENCE_TIMEOUT
	if messageType == "O" then
		self.lookingToPlayPlayers[senderKey] = nil
	elseif messageType == "L" and games == "C,D,P,F" then
		self.lookingToPlayPlayers[senderKey] = {
			name = sender,
			games = games,
			lastSeen = currentTime,
		}
		if not wasRecentlyLooking then
			self:Print(sender .. " is looking for a game. Open /gp games and choose Find Players to send a challenge.")
		end
	else
		return
	end
	if self.RefreshLookingToPlayUI then self:RefreshLookingToPlayUI() end
	if self.RefreshGamesHub then self:RefreshGamesHub() end
end

function GuildPing:InitializeGameSocial()
	if self.gameSocialInitialized or not C_ChatInfo or not C_ChatInfo.RegisterAddonMessagePrefix
		or not C_ChatInfo.SendAddonMessage then return end
	if not C_ChatInfo.RegisterAddonMessagePrefix(MESSAGE_PREFIX) then return end
	self.gameSocialInitialized = true
	self.lookingToPlayPlayers = self.lookingToPlayPlayers or {}
	local function heartbeat()
		if self:IsLookingToPlay() then self:SendLookingToPlayPresence(true) end
	end
	if C_Timer and C_Timer.After then C_Timer.After(4, heartbeat) end
	if C_Timer and C_Timer.NewTicker then
		self.gameSocialTicker = C_Timer.NewTicker(HEARTBEAT_INTERVAL, heartbeat)
	end
end
