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 GUILD_GREEN = UI.GuildGreen
local MUTED_COLOR = UI.MutedColor
local WARNING_GOLD = UI.WarningGold
local UPDATE_RED = UI.UpdateRed
local Unpack = unpack or table.unpack

local LIGHT_SQUARE = { 0.69, 0.59, 0.45, 1 }
local DARK_SQUARE = { 0.23, 0.16, 0.12, 1 }
local BLACK_PIECE = { 0.08, 0.10, 0.15, 1 }
local RED_PIECE = { 0.78, 0.12, 0.15, 1 }
local FELT_GREEN = { 0.071, 0.239, 0.192, 0.98 }
local OLD_BRASS = { 0.843, 0.659, 0.294, 1 }
local CARD_IVORY = { 0.957, 0.906, 0.773, 1 }
local CARD_INK = { 0.090, 0.105, 0.125, 1 }
local SUIT_RED = { 0.67, 0.10, 0.14, 1 }
local SUITS = { c = "♣", d = "♦", h = "♥", s = "♠" }
local RANKS = { T = "10" }

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 CreateListingRow(parent, width)
	local row = CreateFrame("Frame", nil, parent, "BackdropTemplate")
	row:SetSize(width, 54)
	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.gameText = CreateLabel(row, "", "GameFontNormal")
	row.gameText:SetPoint("TOPLEFT", 12, -9)
	row.playersText = CreateLabel(row, "", "GameFontHighlightSmall")
	row.playersText:SetPoint("BOTTOMLEFT", 12, 9)
	row.playersText:SetTextColor(MUTED_COLOR:GetRGB())
	row.watchButton = CreateButton(row, "Watch", 94, 25, "primary")
	row.watchButton:SetPoint("RIGHT", -10, 0)
	row.watchButton:SetScript("OnClick", function()
		local session, errorMessage = GuildPing:WatchSpectatorGame(row.listingKey)
		if not session then GuildPing:Print(errorMessage) end
	end)
	row:Hide()
	return row
end

function GuildPing:CreateSpectatorLobby()
	if self.spectatorLobby then return self.spectatorLobby end
	local frame = CreateWindow("GuildPingSpectatorLobbyFrame")
	frame:SetSize(700, 540)
	frame:SetPoint("CENTER")
	frame:SetFrameStrata("DIALOG")
	MakeDraggable(frame, frame.header)
	SetTitle(frame, "Guild Ping — Watch Games")
	frame.heading = CreateLabel(frame, "Live guild games", "GameFontNormalLarge")
	frame.heading:SetPoint("TOPLEFT", 24, -49)
	frame.description = CreateLabel(frame, "Watch active Checkers and Hold 'Em games. Poker spectators receive public table state only; hole cards are never transmitted.", "GameFontHighlight")
	frame.description:SetPoint("TOPLEFT", 24, -79)
	frame.description:SetPoint("TOPRIGHT", -24, -79)
	frame.description:SetWordWrap(true)
	frame.rows = {}
	for index = 1, 6 do
		local row = CreateListingRow(frame, 652)
		row:SetPoint("TOPLEFT", 24, -132 - ((index - 1) * 58))
		frame.rows[index] = row
	end
	frame.emptyText = CreateLabel(frame, "No spectatable guild games are being advertised right now.", "GameFontDisable")
	frame.emptyText:SetPoint("TOPLEFT", 30, -142)
	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:RefreshSpectatorLobby() end)
	frame:Hide()
	self.spectatorLobby = frame
	return frame
end

function GuildPing:RefreshSpectatorLobby()
	local frame = self.spectatorLobby
	if not frame then return end
	local listings = self:GetSpectatorListings()
	frame.emptyText:SetShown(#listings == 0)
	for index, row in ipairs(frame.rows) do
		local listing = listings[index]
		if listing then
			row.listingKey = listing.key
			row.gameText:SetText(listing.gameType == self.SPECTATOR_CHECKERS and "Checkers" or "Texas Hold 'Em")
			row.playersText:SetText(listing.host .. " vs " .. listing.opponent)
			row:Show()
		else
			row.listingKey = nil
			row:Hide()
		end
	end
end

local function CreateSpectatorCheckersBoard(parent)
	local board = CreateFrame("Frame", nil, parent, "BackdropTemplate")
	board:SetSize(360, 360)
	board:SetPoint("TOP", 0, -118)
	board:SetBackdrop(ROW_BACKDROP)
	board:SetBackdropColor(0.04, 0.04, 0.05, 1)
	board:SetBackdropBorderColor(0.75, 0.64, 0.46, 1)
	board.squares = {}
	for rowIndex = 1, 8 do
		for columnIndex = 1, 8 do
			local square = CreateFrame("Frame", nil, board, "BackdropTemplate")
			square:SetSize(44, 44)
			square:SetPoint("TOPLEFT", 4 + ((columnIndex - 1) * 44), -4 - ((rowIndex - 1) * 44))
			square:SetBackdrop(ROW_BACKDROP)
			square:SetBackdropColor(Unpack((rowIndex + columnIndex) % 2 == 1 and DARK_SQUARE or LIGHT_SQUARE))
			square.piece = square:CreateTexture(nil, "ARTWORK")
			square.piece:SetTexture("Interface\\CHARACTERFRAME\\TempPortraitAlphaMask")
			square.piece:SetSize(32, 32)
			square.piece:SetPoint("CENTER")
			square.piece:Hide()
			square.king = CreateLabel(square, "K", "GameFontNormal")
			square.king:SetPoint("CENTER")
			square.king:SetTextColor(1, 0.86, 0.30, 1)
			square.king:Hide()
			board.squares[((rowIndex - 1) * 8) + columnIndex] = square
		end
	end
	return board
end

local function CreatePublicPokerCard(parent)
	local card = CreateFrame("Frame", nil, parent, "BackdropTemplate")
	card:SetSize(62, 86)
	card:SetBackdrop(ROW_BACKDROP)
	card.text = CreateLabel(card, "", "GameFontNormalLarge")
	card.text:SetPoint("CENTER")
	return card
end

local function SetPublicPokerCard(card, token)
	if type(token) == "string" and #token == 2 then
		local suit = token:sub(2, 2)
		card:SetBackdropColor(Unpack(CARD_IVORY))
		card:SetBackdropBorderColor(Unpack(OLD_BRASS))
		card.text:SetText((RANKS[token:sub(1, 1)] or token:sub(1, 1)) .. (SUITS[suit] or "?"))
		card.text:SetTextColor(Unpack((suit == "d" or suit == "h") and SUIT_RED or CARD_INK))
	else
		card:SetBackdropColor(0.035, 0.130, 0.105, 0.45)
		card:SetBackdropBorderColor(0.843, 0.659, 0.294, 0.28)
		card.text:SetText("—")
		card.text:SetTextColor(MUTED_COLOR:GetRGB())
	end
end

local function CreateSpectatorPokerTable(parent)
	local tableFrame = CreateFrame("Frame", nil, parent, "BackdropTemplate")
	tableFrame:SetPoint("TOPLEFT", 34, -118)
	tableFrame:SetPoint("TOPRIGHT", -34, -118)
	tableFrame:SetHeight(354)
	tableFrame:SetBackdrop(ROW_BACKDROP)
	tableFrame:SetBackdropColor(Unpack(FELT_GREEN))
	tableFrame:SetBackdropBorderColor(Unpack(OLD_BRASS))
	tableFrame.topPlayer = CreateLabel(tableFrame, "", "GameFontNormal")
	tableFrame.topPlayer:SetPoint("TOP", 0, -24)
	tableFrame.bottomPlayer = CreateLabel(tableFrame, "", "GameFontNormal")
	tableFrame.bottomPlayer:SetPoint("BOTTOM", 0, 24)
	tableFrame.potText = CreateLabel(tableFrame, "", "GameFontNormalLarge")
	tableFrame.potText:SetPoint("TOP", 0, -79)
	tableFrame.potText:SetTextColor(Unpack(OLD_BRASS))
	tableFrame.cards = {}
	for index = 1, 5 do
		local card = CreatePublicPokerCard(tableFrame)
		card:SetPoint("CENTER", tableFrame, "CENTER", (index - 3) * 70, -1)
		tableFrame.cards[index] = card
	end
	tableFrame.privacyText = CreateLabel(tableFrame, "Hole cards remain private", "GameFontHighlightSmall")
	tableFrame.privacyText:SetPoint("BOTTOM", 0, 72)
	tableFrame.privacyText:SetTextColor(0.78, 0.88, 0.82, 1)
	return tableFrame
end

function GuildPing:CreateSpectatorGameWindow()
	if self.spectatorGameWindow then return self.spectatorGameWindow end
	local frame = CreateWindow("GuildPingSpectatorGameFrame")
	frame:SetSize(650, 620)
	frame:SetPoint("CENTER")
	frame:SetFrameStrata("DIALOG")
	MakeDraggable(frame, frame.header)
	SetTitle(frame, "Guild Ping — Spectator")
	frame.heading = CreateLabel(frame, "Connecting…", "GameFontNormalLarge")
	frame.heading:SetPoint("TOP", 0, -50)
	frame.statusText = CreateLabel(frame, "Requesting the latest public game state.", "GameFontHighlight")
	frame.statusText:SetPoint("TOPLEFT", 24, -80)
	frame.statusText:SetPoint("TOPRIGHT", -24, -80)
	frame.statusText:SetJustifyH("CENTER")
	frame.statusText:SetTextColor(WARNING_GOLD:GetRGB())
	frame.checkersBoard = CreateSpectatorCheckersBoard(frame)
	frame.checkersBoard:Hide()
	frame.pokerTable = CreateSpectatorPokerTable(frame)
	frame.pokerTable:Hide()
	frame.backButton = CreateButton(frame, "Watch Another", 126, 25, "primary")
	frame.backButton:SetPoint("BOTTOMLEFT", 24, 16)
	frame.backButton:SetScript("OnClick", function()
		GuildPing:LeaveSpectatorGame()
		frame:Hide()
		GuildPing:ShowSpectatorLobby()
	end)
	frame.leaveButton = CreateButton(frame, "Stop Watching", 126, 25, "danger")
	frame.leaveButton:SetPoint("BOTTOMRIGHT", -24, 16)
	frame.leaveButton:SetScript("OnClick", function()
		GuildPing:LeaveSpectatorGame()
		frame:Hide()
	end)
	frame:SetScript("OnShow", function() GuildPing:RefreshSpectatorGame() end)
	frame:Hide()
	self.spectatorGameWindow = frame
	return frame
end

function GuildPing:RefreshSpectatorGame()
	local frame = self.spectatorGameWindow
	local session = self.activeSpectatorSession
	if not frame or not session then return end
	local state = session.state
	frame.checkersBoard:SetShown(session.gameType == self.SPECTATOR_CHECKERS and state ~= nil)
	frame.pokerTable:SetShown(session.gameType == self.SPECTATOR_POKER and state ~= nil)
	if not state then
		frame.heading:SetText("Connecting…")
		frame.statusText:SetText("Requesting the latest public game state from " .. session.host .. ".")
		frame.statusText:SetTextColor(WARNING_GOLD:GetRGB())
		return
	end
	if session.gameType == self.SPECTATOR_CHECKERS then
		frame.heading:SetText(state.challenger .. " vs " .. state.opponent)
		local turnPlayer = state.turn == "B" and state.challenger or state.opponent
		frame.statusText:SetText(state.status == "FINISHED" and "Game finished"
			or (turnPlayer .. " to move  •  move " .. state.moveNumber))
		frame.statusText:SetTextColor(state.status == "FINISHED" and GUILD_GREEN:GetRGB() or WARNING_GOLD:GetRGB())
		for index, square in ipairs(frame.checkersBoard.squares) do
			local piece = state.board[index]
			if piece then
				square.piece:SetVertexColor(Unpack((piece == "b" or piece == "B") and BLACK_PIECE or RED_PIECE))
				square.piece:Show()
				square.king:SetShown(piece == "B" or piece == "R")
			else
				square.piece:Hide()
				square.king:Hide()
			end
		end
	else
		local poker = frame.pokerTable
		frame.heading:SetText(state.challenger .. " vs " .. state.opponent)
		poker.topPlayer:SetText(state.challenger .. "  •  " .. FormatNumber(state.stacks[self.POKER_CHALLENGER]) .. " chips")
		poker.bottomPlayer:SetText(state.opponent .. "  •  " .. FormatNumber(state.stacks[self.POKER_OPPONENT]) .. " chips")
		poker.potText:SetText("Pot  " .. FormatNumber((state.pot or 0)
			+ (state.roundBets[self.POKER_CHALLENGER] or 0) + (state.roundBets[self.POKER_OPPONENT] or 0)))
		for index, card in ipairs(poker.cards) do SetPublicPokerCard(card, state.board[index]) end
		local action = state.lastAction and ("  •  last action: " .. state.lastAction:lower()) or ""
		if state.status == "FINISHED" then
			frame.statusText:SetText("Match finished")
		elseif state.handStatus == "COMPLETE" then
			frame.statusText:SetText(string.format("Hand %d complete%s", state.handNumber, action))
		else
			local turnPlayer = state.turn == self.POKER_CHALLENGER and state.challenger or state.opponent
			frame.statusText:SetText(string.format("Hand %d  •  %s  •  %s to act%s", state.handNumber, state.round, turnPlayer, action))
		end
		frame.statusText:SetTextColor(state.status == "FINISHED" and GUILD_GREEN:GetRGB() or WARNING_GOLD:GetRGB())
	end
end

function GuildPing:RefreshSpectatorUI()
	if self.spectatorLobby and self.spectatorLobby:IsShown() then self:RefreshSpectatorLobby() end
	if self.spectatorGameWindow and self.spectatorGameWindow:IsShown() then self:RefreshSpectatorGame() end
end

function GuildPing:ShowSpectatorLobby()
	if self.gamesHub then self.gamesHub:Hide() end
	if self.spectatorGameWindow then self.spectatorGameWindow:Hide() end
	local frame = self:CreateSpectatorLobby()
	frame:Show()
	self:RefreshSpectatorLobby()
end

function GuildPing:ShowSpectatorGame()
	if self.spectatorLobby then self.spectatorLobby:Hide() end
	local frame = self:CreateSpectatorGameWindow()
	frame:Show()
	self:RefreshSpectatorGame()
end
