local _, namespace = ...
local GuildPing = namespace.GuildPing
local UI = GuildPing.UIFactory

if not UI then
	return
end

local CreateWindow = UI.CreateWindow
local MakeDraggable = UI.MakeDraggable
local SetTitle = UI.SetTitle
local CreateButton = UI.CreateButton
local CreateLabel = UI.CreateLabel
local ROW_BACKDROP = UI.RowBackdrop
local DISCORD_BLUE = UI.DiscordBlue
local GUILD_GREEN = UI.GuildGreen
local MUTED_COLOR = UI.MutedColor
local WARNING_GOLD = UI.WarningGold
local POKER_RED = CreateColor(0.478, 0.149, 0.212, 1)
local CONNECT_BLUE = CreateColor(0.18, 0.42, 0.92, 1)
local DICE_AMBER = CreateColor(0.96, 0.57, 0.16, 1)
local RUNE_VIOLET = CreateColor(0.67, 0.43, 0.88, 1)

local function FormatNumber(value)
	local formatted = tostring(math.floor(tonumber(value) or 0))
	while true do
		local changed
		formatted, changed = formatted:gsub("^(-?%d+)(%d%d%d)", "%1,%2")
		if changed == 0 then
			return formatted
		end
	end
end

local function CreateGameCard(parent, title, eyebrow, description, accent)
	local card = CreateFrame("Frame", nil, parent, "BackdropTemplate")
	card:SetSize(270, 170)
	card:SetBackdrop(ROW_BACKDROP)
	card:SetBackdropColor(0.047, 0.055, 0.078, 0.96)
	card:SetBackdropBorderColor(accent:GetRGB())

	card.eyebrow = CreateLabel(card, eyebrow, "GameFontNormalSmall")
	card.eyebrow:SetPoint("TOPLEFT", 16, -16)
	card.eyebrow:SetTextColor(accent:GetRGB())
	card.title = CreateLabel(card, title, "GameFontNormalLarge")
	card.title:SetPoint("TOPLEFT", 16, -40)
	card.description = CreateLabel(card, description, "GameFontHighlight")
	card.description:SetPoint("TOPLEFT", 16, -73)
	card.description:SetPoint("TOPRIGHT", -16, -73)
	card.description:SetWordWrap(true)

	card.status = CreateLabel(card, "", "GameFontHighlightSmall")
	card.status:SetPoint("BOTTOMLEFT", 16, 50)
	card.status:SetPoint("BOTTOMRIGHT", -16, 50)
	card.status:SetWordWrap(false)
	card.status:SetTextColor(MUTED_COLOR:GetRGB())
	card.openButton = CreateButton(card, "Open", 122, 27, "primary")
	card.openButton:SetPoint("BOTTOMLEFT", 16, 12)
	card.inviteText = CreateLabel(card, "", "GameFontNormal")
	card.inviteText:SetPoint("LEFT", card.openButton, "RIGHT", 12, 0)
	card.inviteText:SetTextColor(accent:GetRGB())
	return card
end

local function CreateStatisticsCard(parent, title, accent)
	local card = CreateFrame("Frame", nil, parent, "BackdropTemplate")
	card:SetSize(270, 135)
	card:SetBackdrop(ROW_BACKDROP)
	card:SetBackdropColor(0.047, 0.055, 0.078, 0.96)
	card:SetBackdropBorderColor(accent:GetRGB())
	card.title = CreateLabel(card, title, "GameFontNormalLarge")
	card.title:SetPoint("TOPLEFT", 14, -14)
	card.title:SetTextColor(accent:GetRGB())
	card.summary = CreateLabel(card, "", "GameFontHighlight")
	card.summary:SetPoint("TOPLEFT", 14, -48)
	card.summary:SetPoint("BOTTOMRIGHT", -14, 12)
	card.summary:SetJustifyH("LEFT")
	card.summary:SetJustifyV("TOP")
	return card
end

local function FormatMatchTime(timestamp)
	if date and tonumber(timestamp) and tonumber(timestamp) > 0 then
		return date("%b %d %H:%M", timestamp)
	end
	return "Recently"
end

local function ResultLabel(result)
	if result == "WIN" then return "Won", GUILD_GREEN end
	if result == "LOSS" then return "Lost", POKER_RED end
	if result == "PRACTICE" then return "Practice", MUTED_COLOR end
	if result == "SOLO_WIN" then return "Completed", GUILD_GREEN end
	if result == "SOLO_LOSS" then return "Unsolved", POKER_RED end
	return "Draw", WARNING_GOLD
end

function GuildPing:CreateGamesHub()
	if self.gamesHub then
		return self.gamesHub
	end

	local hub = CreateWindow("GuildPingGamesHubFrame")
	hub:SetSize(900, 650)
	hub:SetPoint("CENTER")
	hub:SetFrameStrata("DIALOG")
	MakeDraggable(hub, hub.header)
	SetTitle(hub, "Guild Ping — Games")

	hub.heading = CreateLabel(hub, "Choose a game", "GameFontNormalLarge")
	hub.heading:SetPoint("TOPLEFT", 24, -50)
	hub.description = CreateLabel(
		hub,
		"Challenge guild members from anywhere in Azeroth, or settle in with a saved solo game.",
		"GameFontHighlight"
	)
	hub.description:SetPoint("TOPLEFT", 24, -80)
	hub.description:SetPoint("TOPRIGHT", -24, -80)
	hub.description:SetWordWrap(true)

	hub.checkersCard = CreateGameCard(
		hub,
		"Checkers",
		"TACTICS",
		"Plan captures, chain multi-jumps, crown kings, and outmaneuver another guild member.",
		GUILD_GREEN
	)
	hub.checkersCard:SetPoint("TOPLEFT", 24, -124)
	hub.checkersCard.openButton:SetScript("OnClick", function()
		GuildPing:ShowCheckers()
	end)

	hub.deathRollCard = CreateGameCard(
		hub,
		"Death Roll",
		"PRESS YOUR LUCK",
		"Shrink the range with every roll. The first player unlucky enough to land on 1 loses.",
		WARNING_GOLD
	)
	hub.deathRollCard:SetPoint("TOPLEFT", 312, -124)
	hub.deathRollCard.openButton:SetScript("OnClick", function()
		GuildPing:ShowDeathRoll()
	end)

	hub.pokerCard = CreateGameCard(
		hub,
		"Texas Hold 'Em",
		"HEADS-UP TABLE",
		"Read the board, size your bets, and play a full no-wager match from the deal to showdown.",
		POKER_RED
	)
	hub.pokerCard:SetPoint("TOPLEFT", 600, -124)
	hub.pokerCard.openButton:SetScript("OnClick", function()
		GuildPing:ShowPoker()
	end)

	hub.connectFourCard = CreateGameCard(
		hub,
		"Connect Four",
		"DROP & CONNECT",
		"Stack bright discs and connect four across, upward, or diagonally before your opponent.",
		CONNECT_BLUE
	)
	hub.connectFourCard:SetPoint("TOPLEFT", 24, -310)
	hub.connectFourCard.openButton:SetScript("OnClick", function()
		GuildPing:ShowConnectFour()
	end)

	hub.fiveDiceCard = CreateGameCard(
		hub,
		"Five Dice",
		"SOLO SCORECARD",
		"Hold your best dice, spend three rolls wisely, and fill thirteen scoring categories.",
		DICE_AMBER
	)
	hub.fiveDiceCard:SetPoint("TOPLEFT", 312, -310)
	hub.fiveDiceCard.openButton:SetScript("OnClick", function()
		GuildPing:ShowFiveDice()
	end)

	hub.runeMastermindCard = CreateGameCard(
		hub,
		"Rune Mastermind",
		"SOLO CODEBREAKER",
		"Crack a four-rune lock using exact and misplaced clues before eight guesses run out.",
		RUNE_VIOLET
	)
	hub.runeMastermindCard:SetPoint("TOPLEFT", 600, -310)
	hub.runeMastermindCard.openButton:SetScript("OnClick", function()
		GuildPing:ShowRuneMastermind()
	end)

	hub.alertsLabel = CreateLabel(hub, "TURN ALERTS", "GameFontNormalSmall")
	hub.alertsLabel:SetPoint("TOPLEFT", 24, -492)
	hub.alertsLabel:SetTextColor(DISCORD_BLUE:GetRGB())
	hub.soundAlertButton = CreateButton(hub, "Sound", 110, 25)
	hub.soundAlertButton:SetPoint("TOPLEFT", 24, -513)
	hub.screenAlertButton = CreateButton(hub, "Screen alert", 130, 25)
	hub.screenAlertButton:SetPoint("LEFT", hub.soundAlertButton, "RIGHT", 8, 0)
	hub.badgeAlertButton = CreateButton(hub, "Minimap badge", 142, 25)
	hub.badgeAlertButton:SetPoint("LEFT", hub.screenAlertButton, "RIGHT", 8, 0)
	hub.statisticsButton = CreateButton(hub, "Statistics", 104, 25)
	hub.statisticsButton:SetPoint("LEFT", hub.badgeAlertButton, "RIGHT", 14, 0)
	hub.statisticsButton:SetScript("OnClick", function()
		GuildPing:ShowGameStatistics()
	end)
	hub.lookingButton = CreateButton(hub, "Looking to Play", 142, 25)
	hub.lookingButton:SetPoint("LEFT", hub.statisticsButton, "RIGHT", 8, 0)
	hub.lookingButton:SetScript("OnClick", function()
		local changed, errorMessage = GuildPing:ToggleLookingToPlay()
		if not changed then GuildPing:Print(errorMessage) end
	end)
	hub.lookingButton:HookScript("OnEnter", function(self)
		if not GameTooltip then return end
		GameTooltip:SetOwner(self, "ANCHOR_TOP")
		GameTooltip:SetText("Looking to Play")
		GameTooltip:AddLine("Turning this on sends guild members using Guild Ping a one-time chat notice. Status refreshes quietly after that.", 0.78, 0.82, 0.92, true)
		GameTooltip:Show()
	end)
	hub.lookingButton:HookScript("OnLeave", function() if GameTooltip then GameTooltip:Hide() end end)
	hub.findPlayersButton = CreateButton(hub, "Find Players", 126, 25)
	hub.findPlayersButton:SetPoint("LEFT", hub.lookingButton, "RIGHT", 8, 0)
	hub.findPlayersButton:SetScript("OnClick", function() GuildPing:ShowLookingToPlay() end)
	local alertButtons = {
		{ button = hub.soundAlertButton, key = "gameTurnSound", label = "Sound" },
		{ button = hub.screenAlertButton, key = "gameTurnScreenAlert", label = "Screen alert" },
		{ button = hub.badgeAlertButton, key = "gameTurnMinimapBadge", label = "Minimap badge" },
	}
	for _, definition in ipairs(alertButtons) do
		definition.button.settingKey = definition.key
		definition.button:SetScript("OnClick", function(self)
			GuildPing:ToggleGameTurnAlertSetting(self.settingKey)
			GuildPing:RefreshGamesHub()
		end)
	end
	hub.alertButtons = alertButtons

	hub.footerText = CreateLabel(hub, "Multiplayer uses addon messages; solo games stay entirely on this client.", "GameFontDisableSmall")
	hub.footerText:SetPoint("BOTTOMLEFT", 24, 17)
	hub.closeButton = CreateButton(hub, "Close", 90, 25)
	hub.closeButton:SetPoint("BOTTOMRIGHT", -24, 12)
	hub.closeButton:SetScript("OnClick", function() hub:Hide() end)
	hub.watchButton = CreateButton(hub, "Watch Games", 118, 25)
	hub.watchButton:SetPoint("RIGHT", hub.closeButton, "LEFT", -8, 0)
	hub.watchButton:SetScript("OnClick", function() GuildPing:ShowSpectatorLobby() end)
	hub.footerText:SetPoint("RIGHT", hub.watchButton, "LEFT", -12, 0)
	hub.footerText:SetWordWrap(false)
	hub:SetScript("OnShow", function() GuildPing:RefreshGamesHub() end)
	hub:Hide()
	self.gamesHub = hub
	return hub
end

function GuildPing:CreateGameStatisticsWindow()
	if self.gameStatisticsWindow then return self.gameStatisticsWindow end
	local frame = CreateWindow("GuildPingGameStatisticsFrame")
	frame:SetSize(900, 700)
	frame:SetPoint("CENTER")
	frame:SetFrameStrata("DIALOG")
	MakeDraggable(frame, frame.header)
	SetTitle(frame, "Guild Ping — Game Statistics")

	frame.heading = CreateLabel(frame, "Your game ledger", "GameFontNormalLarge")
	frame.heading:SetPoint("TOPLEFT", 24, -50)
	frame.description = CreateLabel(frame, "Competitive, practice, and solo results are stored separately for this guild profile.", "GameFontHighlight")
	frame.description:SetPoint("TOPLEFT", 24, -79)
	frame.description:SetTextColor(MUTED_COLOR:GetRGB())

	frame.checkersCard = CreateStatisticsCard(frame, "Checkers", GUILD_GREEN)
	frame.checkersCard:SetPoint("TOPLEFT", 24, -112)
	frame.deathRollCard = CreateStatisticsCard(frame, "Death Roll", WARNING_GOLD)
	frame.deathRollCard:SetPoint("TOPLEFT", 315, -112)
	frame.pokerCard = CreateStatisticsCard(frame, "Hold 'Em", POKER_RED)
	frame.pokerCard:SetPoint("TOPLEFT", 606, -112)
	frame.connectFourCard = CreateStatisticsCard(frame, "Connect Four", CONNECT_BLUE)
	frame.connectFourCard:SetPoint("TOPLEFT", 24, -263)
	frame.fiveDiceCard = CreateStatisticsCard(frame, "Five Dice", DICE_AMBER)
	frame.fiveDiceCard:SetPoint("TOPLEFT", 315, -263)
	frame.runeMastermindCard = CreateStatisticsCard(frame, "Rune Mastermind", RUNE_VIOLET)
	frame.runeMastermindCard:SetPoint("TOPLEFT", 606, -263)

	frame.recentHeading = CreateLabel(frame, "Recent matches", "GameFontNormalLarge")
	frame.recentHeading:SetPoint("TOPLEFT", 24, -414)
	frame.recentLines = {}
	for index = 1, 7 do
		local line = CreateLabel(frame, "", "GameFontHighlight")
		line:SetPoint("TOPLEFT", 30, -448 - ((index - 1) * 27))
		line:SetPoint("RIGHT", -30, 0)
		line:SetWordWrap(false)
		frame.recentLines[index] = line
	end
	frame.emptyText = CreateLabel(frame, "Finish a multiplayer match or practice game to begin your history.", "GameFontDisable")
	frame.emptyText:SetPoint("TOPLEFT", 30, -451)

	frame.backButton = CreateButton(frame, "Back to Games", 126, 25, "primary")
	frame.backButton:SetPoint("BOTTOMLEFT", 24, 16)
	frame.backButton:SetScript("OnClick", function()
		frame:Hide()
		GuildPing:ShowGames()
	end)
	frame.closeButton = CreateButton(frame, "Close", 90, 25)
	frame.closeButton:SetPoint("BOTTOMRIGHT", -24, 16)
	frame.closeButton:SetScript("OnClick", function() frame:Hide() end)
	frame:SetScript("OnShow", function() GuildPing:RefreshGameStatisticsWindow() end)
	frame:Hide()
	self.gameStatisticsWindow = frame
	return frame
end

function GuildPing:RefreshGameStatisticsWindow()
	local frame = self.gameStatisticsWindow
	if not frame then return end
	local checkers = self:GetGameStatistics("checkers")
	local deathRoll = self:GetGameStatistics("deathRoll")
	local poker = self:GetGameStatistics("poker")
	local connectFour = self:GetGameStatistics("connectFour")
	local fiveDice = self:GetGameStatistics("fiveDice")
	local runeMastermind = self:GetGameStatistics("runeMastermind")
	frame.checkersCard.summary:SetText(string.format(
		"Matches  %d\nRecord  %d–%d–%d\nPractice  %d\nMoves  %d  •  longest %d",
		checkers.played, checkers.wins, checkers.losses, checkers.draws,
		checkers.practiceGames, checkers.totalMoves, checkers.longestGameMoves
	))
	frame.deathRollCard.summary:SetText(string.format(
		"Matches  %d\nRecord  %d–%d–%d\nPractice  %d\nRolls  %d  •  longest %d\nHighest start  %s",
		deathRoll.played, deathRoll.wins, deathRoll.losses, deathRoll.draws,
		deathRoll.practiceGames, deathRoll.totalRolls, deathRoll.longestGameRolls,
		FormatNumber(deathRoll.highestStartingMax)
	))
	frame.pokerCard.summary:SetText(string.format(
		"Matches  %d\nRecord  %d–%d–%d\nPractice  %d\nHands  %d  •  won %d\nSplit pots  %d",
		poker.played, poker.wins, poker.losses, poker.draws,
		poker.practiceGames, poker.handsPlayed, poker.handsWon, poker.handsSplit
	))
	frame.connectFourCard.summary:SetText(string.format(
		"Matches  %d\nRecord  %d–%d–%d\nPractice  %d\nMoves  %d  •  longest %d",
		connectFour.played, connectFour.wins, connectFour.losses, connectFour.draws,
		connectFour.practiceGames, connectFour.totalMoves, connectFour.longestGameMoves
	))
	local averageDiceScore = fiveDice.soloGames > 0 and math.floor((fiveDice.totalScore / fiveDice.soloGames) + 0.5) or 0
	frame.fiveDiceCard.summary:SetText(string.format(
		"Scorecards  %d\nBest score  %d\nAverage  %d\nTotal points  %s",
		fiveDice.soloGames, fiveDice.bestScore, averageDiceScore, FormatNumber(fiveDice.totalScore)
	))
	local averageAttempts = runeMastermind.soloGames > 0 and (runeMastermind.totalAttempts / runeMastermind.soloGames) or 0
	frame.runeMastermindCard.summary:SetText(string.format(
		"Puzzles  %d\nSolved  %d  •  held %d\nBest  %s\nAverage guesses  %.1f",
		runeMastermind.soloGames, runeMastermind.soloWins, runeMastermind.soloLosses,
		runeMastermind.fewestAttempts > 0 and (runeMastermind.fewestAttempts .. " attempt" .. (runeMastermind.fewestAttempts == 1 and "" or "s")) or "—",
		averageAttempts
	))

	local gameNames = {
		checkers = "Checkers", deathRoll = "Death Roll", poker = "Hold 'Em", connectFour = "Connect Four",
		fiveDice = "Five Dice", runeMastermind = "Rune Mastermind",
	}
	local matches = self:GetRecentGameMatches()
	frame.emptyText:SetShown(#matches == 0)
	for index, line in ipairs(frame.recentLines) do
		local match = matches[index]
		if match then
			local resultText, resultColor = ResultLabel(match.result)
			if match.solo then
				line:SetText(string.format("%s  •  %s  —  %s%s", FormatMatchTime(match.completedAt),
					gameNames[match.game] or match.game, resultText,
					match.reason ~= "" and " (" .. match.reason .. ")" or ""))
			else
				line:SetText(string.format("%s  •  %s vs %s  —  %s%s", FormatMatchTime(match.completedAt),
					gameNames[match.game] or match.game, match.opponent, resultText,
					match.reason ~= "" and " (" .. match.reason .. ")" or ""))
			end
			line:SetTextColor(resultColor:GetRGB())
			line:Show()
		else
			line:Hide()
		end
	end
end

function GuildPing:ShowGameStatistics()
	if self.gamesHub then self.gamesHub:Hide() end
	local frame = self:CreateGameStatisticsWindow()
	frame:Show()
	self:RefreshGameStatisticsWindow()
end

local function RefreshCard(card, game, inviteCount, detailText)
	if game then
		local stateText = game.status == "FINISHED" and "Finished" or "In progress"
		if detailText then
			card.status:SetText(string.format("%s  •  %s", stateText, detailText))
		else
			card.status:SetText(stateText)
		end
		card.openButton:SetText(game.status == "FINISHED" and "View Game" or "Resume")
	else
		card.status:SetText("Ready for a new challenge")
		card.openButton:SetText("Open Lobby")
	end
	card.inviteText:SetText(inviteCount > 0 and string.format("%d waiting", inviteCount) or "")
	card.openButton:SetVariant(inviteCount > 0 and "primary" or "secondary")
end

local function RefreshSoloCard(card, game, detailText)
	if game then
		local stateText = game.status == "FINISHED" and "Finished" or "In progress"
		card.status:SetText(detailText and string.format("%s  •  %s", stateText, detailText) or stateText)
		card.openButton:SetText(game.status == "FINISHED" and "View Result" or "Resume")
	else
		card.status:SetText("Ready for a new solo game")
		card.openButton:SetText("Play")
	end
	card.inviteText:SetText("")
	card.openButton:SetVariant("secondary")
end

function GuildPing:RefreshGamesHub()
	local hub = self.gamesHub
	if not hub then
		return
	end
	local checkersInvites = self.GetCheckersInviteCount and self:GetCheckersInviteCount() or 0
	local deathRollInvites = self.GetDeathRollInviteCount and self:GetDeathRollInviteCount() or 0
	local pokerInvites = self.GetPokerInviteCount and self:GetPokerInviteCount() or 0
	RefreshCard(hub.checkersCard, self.activeCheckersGame, checkersInvites)
	RefreshCard(
		hub.deathRollCard,
		self.activeDeathRollGame,
		deathRollInvites,
		self.activeDeathRollGame and ("Range 1–" .. FormatNumber(self.activeDeathRollGame.currentMax)) or nil
	)
	local pokerGame = self.activePokerGame
	RefreshCard(
		hub.pokerCard,
		pokerGame,
		pokerInvites,
		pokerGame and string.format(
			"Hand %d  •  %s / %s",
			pokerGame.handNumber or 0,
			FormatNumber(pokerGame.stacks and pokerGame.stacks[self.POKER_CHALLENGER] or 0),
			FormatNumber(pokerGame.stacks and pokerGame.stacks[self.POKER_OPPONENT] or 0)
		) or nil
	)
	RefreshCard(
		hub.connectFourCard,
		self.activeConnectFourGame,
		self.GetConnectFourInviteCount and self:GetConnectFourInviteCount() or 0,
		self.activeConnectFourGame and string.format("Move %d", self.activeConnectFourGame.moveNumber or 0) or nil
	)
	local fiveDiceGame = self.activeFiveDiceGame
	RefreshSoloCard(hub.fiveDiceCard, fiveDiceGame, fiveDiceGame and (fiveDiceGame.status == "FINISHED"
		and string.format("Score %d", fiveDiceGame.totalScore or 0)
		or string.format("Round %d / %d", fiveDiceGame.round or 1, self.FIVE_DICE_CATEGORY_COUNT or 13)) or nil)
	local runeGame = self.activeRuneMastermindGame
	RefreshSoloCard(hub.runeMastermindCard, runeGame, runeGame and (runeGame.status == "FINISHED"
		and (runeGame.won and "Lock opened" or "Lock held")
		or string.format("Guess %d / %d", #(runeGame.attempts or {}) + 1, runeGame.maxAttempts or 8)) or nil)
	for _, definition in ipairs(hub.alertButtons or {}) do
		local enabled = self:GetGameTurnAlertSetting(definition.key)
		definition.button:SetText(definition.label .. (enabled and " On" or " Off"))
		definition.button:SetVariant(enabled and "primary" or "secondary")
	end
	local looking = self.IsLookingToPlay and self:IsLookingToPlay() or false
	hub.lookingButton:SetText(looking and "Looking: On" or "Looking: Off")
	hub.lookingButton:SetVariant(looking and "primary" or "secondary")
	local playerCount = self.GetLookingToPlayPlayers and #self:GetLookingToPlayPlayers() or 0
	hub.findPlayersButton:SetText(playerCount > 0 and ("Find Players (" .. playerCount .. ")") or "Find Players")
end

local function CreateLookingPlayerRow(parent, width)
	local row = CreateFrame("Frame", nil, parent, "BackdropTemplate")
	row:SetSize(width, 48)
	row:SetBackdrop(ROW_BACKDROP)
	row:SetBackdropColor(0.047, 0.055, 0.078, 0.94)
	row:SetBackdropBorderColor(0.180, 0.204, 0.275, 0.95)
	row.nameText = CreateLabel(row, "", "GameFontNormal")
	row.nameText:SetPoint("LEFT", 12, 0)
	row.nameText:SetPoint("RIGHT", -398, 0)
	row.nameText:SetWordWrap(false)
	row.pokerButton = CreateButton(row, "Hold 'Em", 86, 24)
	row.pokerButton:SetPoint("RIGHT", -8, 0)
	row.deathRollButton = CreateButton(row, "Death Roll", 92, 24)
	row.deathRollButton:SetPoint("RIGHT", row.pokerButton, "LEFT", -7, 0)
	row.connectFourButton = CreateButton(row, "Connect 4", 90, 24)
	row.connectFourButton:SetPoint("RIGHT", row.deathRollButton, "LEFT", -7, 0)
	row.checkersButton = CreateButton(row, "Checkers", 86, 24)
	row.checkersButton:SetPoint("RIGHT", row.connectFourButton, "LEFT", -7, 0)
	row.checkersButton:SetScript("OnClick", function()
		local challenge, errorMessage = GuildPing:ChallengeCheckersPlayer(row.playerName)
		if challenge then GuildPing:Print("Checkers challenge sent to " .. row.playerName .. ".") else GuildPing:Print(errorMessage) end
	end)
	row.deathRollButton:SetScript("OnClick", function()
		local challenge, errorMessage = GuildPing:ChallengeDeathRollPlayer(row.playerName, 1000)
		if challenge then GuildPing:Print("Death Roll challenge sent to " .. row.playerName .. ".") else GuildPing:Print(errorMessage) end
	end)
	row.connectFourButton:SetScript("OnClick", function()
		local challenge, errorMessage = GuildPing:ChallengeConnectFourPlayer(row.playerName)
		if challenge then GuildPing:Print("Connect Four challenge sent to " .. row.playerName .. ".") else GuildPing:Print(errorMessage) end
	end)
	row.pokerButton:SetScript("OnClick", function()
		local challenge, errorMessage = GuildPing:ChallengePokerPlayer(row.playerName, GuildPing.POKER_DEFAULT_STACK)
		if challenge then GuildPing:Print("Hold 'Em challenge sent to " .. row.playerName .. ".") else GuildPing:Print(errorMessage) end
	end)
	row:Hide()
	return row
end

function GuildPing:CreateLookingToPlayWindow()
	if self.lookingToPlayWindow then return self.lookingToPlayWindow end
	local frame = CreateWindow("GuildPingLookingToPlayFrame")
	frame:SetSize(720, 560)
	frame:SetPoint("CENTER")
	frame:SetFrameStrata("DIALOG")
	MakeDraggable(frame, frame.header)
	SetTitle(frame, "Guild Ping — Looking to Play")
	frame.heading = CreateLabel(frame, "Available guild members", "GameFontNormalLarge")
	frame.heading:SetPoint("TOPLEFT", 24, -49)
	frame.description = CreateLabel(frame, "Turning Looking on sends guild members using Guild Ping a one-time chat notice. It then refreshes quietly and disappears when stale.", "GameFontHighlight")
	frame.description:SetPoint("TOPLEFT", 24, -79)
	frame.description:SetPoint("TOPRIGHT", -24, -79)
	frame.description:SetWordWrap(true)
	frame.toggleButton = CreateButton(frame, "Looking to Play", 154, 25, "primary")
	frame.toggleButton:SetPoint("TOPLEFT", 24, -119)
	frame.toggleButton:SetScript("OnClick", function()
		local changed, errorMessage = GuildPing:ToggleLookingToPlay()
		if not changed then GuildPing:Print(errorMessage) end
	end)
	frame.statusText = CreateLabel(frame, "", "GameFontHighlightSmall")
	frame.statusText:SetPoint("LEFT", frame.toggleButton, "RIGHT", 12, 0)
	frame.statusText:SetTextColor(MUTED_COLOR:GetRGB())
	frame.watchButton = CreateButton(frame, "Watch Games", 124, 25)
	frame.watchButton:SetPoint("TOPRIGHT", -24, -119)
	frame.watchButton:SetScript("OnClick", function() frame:Hide() GuildPing:ShowSpectatorLobby() end)

	frame.rows = {}
	for index = 1, 7 do
		local row = CreateLookingPlayerRow(frame, 672)
		row:SetPoint("TOPLEFT", 24, -164 - ((index - 1) * 52))
		frame.rows[index] = row
	end
	frame.emptyText = CreateLabel(frame, "No guild members are advertising availability yet.", "GameFontDisable")
	frame.emptyText:SetPoint("TOPLEFT", 30, -174)
	frame.backButton = CreateButton(frame, "Back to Games", 126, 25, "primary")
	frame.backButton:SetPoint("BOTTOMLEFT", 24, 16)
	frame.backButton:SetScript("OnClick", function() frame:Hide() GuildPing:ShowGames() end)
	frame.closeButton = CreateButton(frame, "Close", 90, 25)
	frame.closeButton:SetPoint("BOTTOMRIGHT", -24, 16)
	frame.closeButton:SetScript("OnClick", function() frame:Hide() end)
	frame:SetScript("OnShow", function() GuildPing:RefreshLookingToPlayUI() end)
	frame:Hide()
	self.lookingToPlayWindow = frame
	return frame
end

function GuildPing:RefreshLookingToPlayUI()
	local frame = self.lookingToPlayWindow
	if not frame then return end
	local looking = self:IsLookingToPlay()
	frame.toggleButton:SetText(looking and "Looking: On" or "Looking: Off")
	frame.toggleButton:SetVariant(looking and "primary" or "secondary")
	frame.statusText:SetText(looking and "Guild members running Guild Ping can see you here." or "Turn this on to advertise your availability.")
	local players = self:GetLookingToPlayPlayers()
	frame.emptyText:SetShown(#players == 0)
	for index, row in ipairs(frame.rows) do
		local player = players[index]
		if player then
			row.playerName = player.name
			row.nameText:SetText(player.name)
			row:Show()
		else
			row.playerName = nil
			row:Hide()
		end
	end
end

function GuildPing:ShowLookingToPlay()
	if self.gamesHub then self.gamesHub:Hide() end
	local frame = self:CreateLookingToPlayWindow()
	frame:Show()
	self:RefreshLookingToPlayUI()
end

function GuildPing:RefreshGamesIndicators()
	local checkersInvites = self.GetCheckersInviteCount and self:GetCheckersInviteCount() or 0
	local deathRollInvites = self.GetDeathRollInviteCount and self:GetDeathRollInviteCount() or 0
	local pokerInvites = self.GetPokerInviteCount and self:GetPokerInviteCount() or 0
	local connectFourInvites = self.GetConnectFourInviteCount and self:GetConnectFourInviteCount() or 0
	local turnAlerts = self.GetGameTurnAlertCount and self:GetGameTurnAlertCount() or 0
	local count = checkersInvites + deathRollInvites + pokerInvites + connectFourInvites + turnAlerts
	if self.picker and self.picker.gamesButton then
		self.picker.gamesButton:SetText(count > 0 and ("Games (" .. count .. ")") or "Games")
		self.picker.gamesButton:SetVariant(count > 0 and "primary" or "secondary")
	end
	if self.gamesHub and self.gamesHub:IsShown() then
		self:RefreshGamesHub()
	end
	if self.RefreshGameTurnMinimapBadge then
		self:RefreshGameTurnMinimapBadge()
	end
end

function GuildPing:ShowGames()
	if self.checkersLobby then self.checkersLobby:Hide() end
	if self.checkersBoard then self.checkersBoard:Hide() end
	if self.deathRollLobby then self.deathRollLobby:Hide() end
	if self.deathRollGameFrame then self.deathRollGameFrame:Hide() end
	if self.pokerLobby then self.pokerLobby:Hide() end
	if self.pokerTableFrame then self.pokerTableFrame:Hide() end
	if self.connectFourLobby then self.connectFourLobby:Hide() end
	if self.connectFourBoard then self.connectFourBoard:Hide() end
	if self.fiveDiceFrame then self.fiveDiceFrame:Hide() end
	if self.runeMastermindFrame then self.runeMastermindFrame:Hide() end
	if self.spectatorLobby then self.spectatorLobby:Hide() end
	if self.spectatorGameWindow then self.spectatorGameWindow:Hide() end
	local hub = self:CreateGamesHub()
	hub:Show()
	self:RefreshGamesHub()
end
