-- WoWTetris Multiplayer System
-- Leaderboards, Challenges, Split-Screen 1v1

local addonName, addon = ...

-- Addon communication prefix
local COMM_PREFIX = "WoWTetris"
local MESSAGE_TYPES = {
    SYNC_STATS = "SYNC",
    CHALLENGE = "CHAL",
    CHALLENGE_ACCEPT = "ACPT",
    CHALLENGE_DECLINE = "DECL",
    GAME_UPDATE = "GUPD",
    GAME_OVER = "GOVR",
    PVP_SABOTAGE = "SABO",
    LOBBY = "LOBY",
    ULTIMATE_CD = "ULTC",
    SABOTAGE_CD = "SABC",
    PVP_WIN = "PWIN",  -- Player reached win score
    -- Random Queue messages
    QUEUE_JOIN = "QJOIN",    -- Player joining queue
    QUEUE_LEAVE = "QLEAVE",  -- Player leaving queue
    QUEUE_MATCH = "QMATCH",  -- Match found
    QUEUE_ACCEPT = "QACC",   -- Accept match
    QUEUE_DECLINE = "QDEC",  -- Decline match
}

-- PvP Settings
local PVP_WIN_SCORE = 3500  -- First to this score wins

-- Leaderboard data
addon.leaderboard = {
    guild = {},   -- {name = {class, level, highScore, lastSeen}}
    friends = {}, -- Same structure
}

-- Multiplayer state
addon.mpState = {
    inMatch = false,
    opponent = nil,
    opponentClass = nil,
    opponentScore = 0,
    opponentLevel = 1,
    opponentLines = 0,
    opponentBoard = {},
    opponentPiece = nil,
    opponentUltimateCd = 0,
    opponentUltimateName = "",
    opponentSabotageCd = 0,
    opponentSabotageName = "",
    pendingChallenge = nil,
    challengeFrom = nil,
    selectedPvPAbility = nil,
    pvpCooldown = 0,
    -- Random Queue state
    inQueue = false,
    queueStartTime = 0,
    queuedPlayers = {},  -- {playerName = {class, race, rating, wins, losses, timestamp}}
    pendingMatch = nil,  -- Player we're waiting to accept
    matchAccepted = false,
}

-- Queue broadcast interval
local QUEUE_BROADCAST_INTERVAL = 2  -- seconds
local QUEUE_TIMEOUT = 30  -- Remove players from queue after this many seconds of no heartbeat

-- Initialize multiplayer system
function addon:InitializeMultiplayer()
    -- Register addon message prefix
    C_ChatInfo.RegisterAddonMessagePrefix(COMM_PREFIX)
    
    -- Listen for addon messages
    local frame = CreateFrame("Frame")
    frame:RegisterEvent("CHAT_MSG_ADDON")
    frame:RegisterEvent("GROUP_ROSTER_UPDATE")
    frame:RegisterEvent("GUILD_ROSTER_UPDATE")
    frame:RegisterEvent("FRIENDLIST_UPDATE")
    frame:RegisterEvent("BN_FRIEND_INFO_CHANGED")
    frame:RegisterEvent("BN_CHAT_MSG_ADDON")  -- BNet addon messages
    
    frame:SetScript("OnEvent", function(self, event, ...)
        if event == "CHAT_MSG_ADDON" then
            addon:OnAddonMessage(...)
        elseif event == "BN_CHAT_MSG_ADDON" then
            addon:OnBNetAddonMessage(...)
        elseif event == "GUILD_ROSTER_UPDATE" then
            addon:RequestGuildSync()
        elseif event == "FRIENDLIST_UPDATE" or event == "BN_FRIEND_INFO_CHANGED" then
            addon:RequestFriendsSync()
        end
    end)
    
    -- Request initial sync after a delay
    C_Timer.After(3, function()
        addon:BroadcastStats()
    end)
end

-- Send addon message
function addon:SendMessage(msgType, data, channel, target)
    local msg = msgType .. ":" .. (data or "")
    
    if channel == "WHISPER" and target then
        -- Check if target is a BNet ID (number) or character name
        if type(target) == "number" then
            -- BNet game account ID
            BNSendGameData(target, COMM_PREFIX, msg)
        else
            C_ChatInfo.SendAddonMessage(COMM_PREFIX, msg, "WHISPER", target)
        end
    elseif channel == "GUILD" then
        if IsInGuild() then
            C_ChatInfo.SendAddonMessage(COMM_PREFIX, msg, "GUILD")
        end
    elseif channel == "PARTY" then
        if IsInGroup() then
            C_ChatInfo.SendAddonMessage(COMM_PREFIX, msg, IsInRaid() and "RAID" or "PARTY")
        end
    elseif channel == "BNET" and target then
        -- Battle.net game account ID
        BNSendGameData(target, COMM_PREFIX, msg)
    end
end

-- Handle incoming BNet addon message
function addon:OnBNetAddonMessage(prefix, msg, channel, senderID)
    if prefix ~= COMM_PREFIX then return end
    
    -- Get sender info from BNet ID
    local accountInfo = C_BattleNet.GetGameAccountInfoByID(senderID)
    local senderName = "BNet"
    if accountInfo then
        senderName = accountInfo.characterName or accountInfo.battleTag or "BNet"
        if accountInfo.realmName and accountInfo.characterName then
            senderName = accountInfo.characterName .. "-" .. accountInfo.realmName
        end
    end
    
    -- Store BNet ID for replies
    addon.mpState.opponentBNetID = senderID
    
    local msgType, data = strsplit(":", msg, 2)
    
    if msgType == MESSAGE_TYPES.SYNC_STATS then
        addon:HandleStatsSync(senderName, data, "BNET")
    elseif msgType == MESSAGE_TYPES.CHALLENGE then
        addon:HandleBNetChallenge(senderID, senderName, data)
    elseif msgType == MESSAGE_TYPES.CHALLENGE_ACCEPT then
        addon:HandleBNetChallengeAccepted(senderID, senderName, data)
    elseif msgType == MESSAGE_TYPES.CHALLENGE_DECLINE then
        addon:HandleChallengeDeclined(senderName)
    elseif msgType == MESSAGE_TYPES.GAME_UPDATE then
        addon:HandleGameUpdate(senderName, data)
    elseif msgType == MESSAGE_TYPES.GAME_OVER then
        addon:HandleOpponentGameOver(senderName, data)
    elseif msgType == MESSAGE_TYPES.LOBBY then
        addon:HandleLobbyUpdate(senderName, data)
    elseif msgType == MESSAGE_TYPES.PVP_SABOTAGE then
        addon:HandlePvPSabotage(senderName, data)
    elseif msgType == MESSAGE_TYPES.ULTIMATE_CD then
        addon:HandleUltimateCooldown(senderName, data)
    elseif msgType == MESSAGE_TYPES.SABOTAGE_CD then
        addon:HandleSabotageCooldown(senderName, data)
    elseif msgType == MESSAGE_TYPES.PVP_WIN then
        addon:HandleOpponentWin(senderName, data)
    end
end

-- Handle BNet challenge (cross-faction)
function addon:HandleBNetChallenge(senderBNetID, senderName, data)
    if addon.mpState.inMatch then
        addon:SendMessage(MESSAGE_TYPES.CHALLENGE_DECLINE, "busy", "BNET", senderBNetID)
        return
    end
    
    addon.mpState.challengeFrom = senderName
    addon.mpState.challengeFromBNetID = senderBNetID
    addon.mpState.opponentClass = data
    addon.mpState.isBNetMatch = true
    
    -- Show challenge popup
    addon:ShowChallengePopup(senderName, data)
end

-- Handle BNet challenge accepted
function addon:HandleBNetChallengeAccepted(senderBNetID, senderName, data)
    if not addon.mpState.pendingBNetChallenge then return end
    
    local opponentClass = data or "WARRIOR"
    
    print("|cff00ff00[Tetris]|r " .. senderName .. " accepted your challenge!")
    addon.mpState.opponentBNetID = senderBNetID
    addon.mpState.isBNetMatch = true
    addon:StartMultiplayerMatch(senderName, opponentClass)
end

-- Handle incoming addon message
function addon:OnAddonMessage(prefix, msg, channel, sender)
    if prefix ~= COMM_PREFIX then return end
    if sender == UnitName("player") then return end
    
    local msgType, data = strsplit(":", msg, 2)
    
    if msgType == MESSAGE_TYPES.SYNC_STATS then
        addon:HandleStatsSync(sender, data, channel)
    elseif msgType == MESSAGE_TYPES.CHALLENGE then
        addon:HandleChallenge(sender, data)
    elseif msgType == MESSAGE_TYPES.CHALLENGE_ACCEPT then
        addon:HandleChallengeAccepted(sender, data)
    elseif msgType == MESSAGE_TYPES.CHALLENGE_DECLINE then
        addon:HandleChallengeDeclined(sender)
    elseif msgType == MESSAGE_TYPES.GAME_UPDATE then
        addon:HandleGameUpdate(sender, data)
    elseif msgType == MESSAGE_TYPES.GAME_OVER then
        addon:HandleOpponentGameOver(sender, data)
    elseif msgType == MESSAGE_TYPES.LOBBY then
        addon:HandleLobbyUpdate(sender, data)
    elseif msgType == MESSAGE_TYPES.PVP_SABOTAGE then
        addon:HandlePvPSabotage(sender, data)
    elseif msgType == MESSAGE_TYPES.ULTIMATE_CD then
        addon:HandleUltimateCooldown(sender, data)
    elseif msgType == MESSAGE_TYPES.SABOTAGE_CD then
        addon:HandleSabotageCooldown(sender, data)
    elseif msgType == MESSAGE_TYPES.PVP_WIN then
        addon:HandleOpponentWin(sender, data)
    -- Queue messages
    elseif msgType == MESSAGE_TYPES.QUEUE_JOIN then
        addon:HandleQueueJoin(sender, data)
    elseif msgType == MESSAGE_TYPES.QUEUE_LEAVE then
        addon:HandleQueueLeave(sender)
    elseif msgType == MESSAGE_TYPES.QUEUE_MATCH then
        addon:HandleQueueMatch(sender, data)
    elseif msgType == MESSAGE_TYPES.QUEUE_ACCEPT then
        addon:HandleQueueAccept(sender)
    elseif msgType == MESSAGE_TYPES.QUEUE_DECLINE then
        addon:HandleQueueDecline(sender)
    end
end

-- Handle opponent winning by reaching score
function addon:HandleOpponentWin(sender, data)
    if not addon.mpState.inMatch or addon.mpState.opponent ~= sender then return end
    
    local winScore = tonumber(data) or PVP_WIN_SCORE
    addon.mpState.opponentScore = winScore
    
    -- Stop our game - we lost
    addon.gameState.isPlaying = false
    addon.gameState.isGameOver = true
    
    print("|cffff0000[Tetris]|r " .. sender .. " reached " .. winScore .. " points and WINS!")
    
    -- Show results (we lost) - this will call RecordPvPResult
    addon:ShowPvPMatchResults(false, winScore)
end

-- ============================================================
-- RANDOM QUEUE SYSTEM
-- ============================================================

-- Record PvP win/loss
function addon:RecordPvPResult(won)
    if won then
        addon.db.pvpWins = (addon.db.pvpWins or 0) + 1
        addon.db.pvpRating = (addon.db.pvpRating or 1000) + 25
        print("|cff00ff00[Tetris PvP]|r Victory! Rating: " .. addon.db.pvpRating .. " (+" .. 25 .. ")")
    else
        addon.db.pvpLosses = (addon.db.pvpLosses or 0) + 1
        addon.db.pvpRating = math.max(0, (addon.db.pvpRating or 1000) - 20)
        print("|cffff0000[Tetris PvP]|r Defeat. Rating: " .. addon.db.pvpRating .. " (-" .. 20 .. ")")
    end
end

-- Get PvP stats string
function addon:GetPvPStatsString()
    local wins = addon.db.pvpWins or 0
    local losses = addon.db.pvpLosses or 0
    local rating = addon.db.pvpRating or 1000
    local total = wins + losses
    local winRate = total > 0 and math.floor((wins / total) * 100) or 0
    return string.format("%dW-%dL (%d%%) | Rating: %d", wins, losses, winRate, rating)
end

-- Join the random queue
function addon:JoinRandomQueue()
    if addon.mpState.inMatch then
        print("|cffff0000[Tetris]|r Already in a match!")
        return
    end
    
    if addon.mpState.inQueue then
        print("|cffffff00[Tetris]|r Already in queue!")
        return
    end
    
    addon.mpState.inQueue = true
    addon.mpState.queueStartTime = GetTime()
    addon.mpState.pendingMatch = nil
    addon.mpState.matchAccepted = false
    
    -- Broadcast that we're in queue
    addon:BroadcastQueueStatus()
    
    -- Start queue heartbeat
    addon:StartQueueHeartbeat()
    
    print("|cff00ff00[Tetris]|r Joined random PvP queue! Looking for opponents...")
    
    -- Update UI
    addon:UpdateQueueUI()
end

-- Leave the random queue
function addon:LeaveRandomQueue()
    if not addon.mpState.inQueue then return end
    
    addon.mpState.inQueue = false
    addon.mpState.queueStartTime = 0
    addon.mpState.pendingMatch = nil
    
    -- Broadcast that we left
    local msg = MESSAGE_TYPES.QUEUE_LEAVE .. ":"
    addon:BroadcastMessage(msg)
    
    -- Stop heartbeat
    if addon.queueHeartbeatTimer then
        addon.queueHeartbeatTimer:Cancel()
        addon.queueHeartbeatTimer = nil
    end
    
    print("|cffffff00[Tetris]|r Left PvP queue.")
    
    -- Update UI
    addon:UpdateQueueUI()
end

-- Broadcast queue status (heartbeat)
function addon:BroadcastQueueStatus()
    if not addon.mpState.inQueue then return end
    
    local class = addon.selectedClass or "WARRIOR"
    local race = addon.selectedRace or "HUMAN"
    local rating = addon.db.pvpRating or 1000
    local wins = addon.db.pvpWins or 0
    local losses = addon.db.pvpLosses or 0
    
    local msg = MESSAGE_TYPES.QUEUE_JOIN .. ":" .. class .. "," .. race .. "," .. rating .. "," .. wins .. "," .. losses
    addon:BroadcastMessage(msg)
end

-- Start queue heartbeat timer
function addon:StartQueueHeartbeat()
    if addon.queueHeartbeatTimer then
        addon.queueHeartbeatTimer:Cancel()
    end
    
    addon.queueHeartbeatTimer = C_Timer.NewTicker(QUEUE_BROADCAST_INTERVAL, function()
        if not addon.mpState.inQueue then
            addon.queueHeartbeatTimer:Cancel()
            addon.queueHeartbeatTimer = nil
            return
        end
        
        -- Broadcast our status
        addon:BroadcastQueueStatus()
        
        -- Clean up stale players
        addon:CleanupStaleQueuePlayers()
        
        -- Try to find a match if we don't have one pending
        if not addon.mpState.pendingMatch then
            addon:TryFindQueueMatch()
        end
        
        -- Update UI
        addon:UpdateQueueUI()
    end)
end

-- Handle someone joining the queue
function addon:HandleQueueJoin(sender, data)
    if sender == UnitName("player") then return end
    
    local class, race, rating, wins, losses = strsplit(",", data)
    
    addon.mpState.queuedPlayers[sender] = {
        class = class or "WARRIOR",
        race = race or "HUMAN",
        rating = tonumber(rating) or 1000,
        wins = tonumber(wins) or 0,
        losses = tonumber(losses) or 0,
        timestamp = GetTime(),
    }
    
    -- Update UI
    addon:UpdateQueueUI()
end

-- Handle someone leaving the queue
function addon:HandleQueueLeave(sender)
    addon.mpState.queuedPlayers[sender] = nil
    
    -- If they were our pending match, clear it
    if addon.mpState.pendingMatch == sender then
        addon.mpState.pendingMatch = nil
        addon.mpState.matchAccepted = false
    end
    
    -- Update UI
    addon:UpdateQueueUI()
end

-- Clean up stale players (no heartbeat for QUEUE_TIMEOUT seconds)
function addon:CleanupStaleQueuePlayers()
    local now = GetTime()
    for name, data in pairs(addon.mpState.queuedPlayers) do
        if now - data.timestamp > QUEUE_TIMEOUT then
            addon.mpState.queuedPlayers[name] = nil
        end
    end
end

-- Try to find a match from queued players
function addon:TryFindQueueMatch()
    if not addon.mpState.inQueue then return end
    if addon.mpState.pendingMatch then return end
    
    -- Get my name (with and without realm)
    local myName = UnitName("player")
    local myFullName = myName
    local realmName = GetRealmName()
    if realmName then
        myFullName = myName .. "-" .. realmName:gsub(" ", "")
    end
    
    -- Find the best match (closest rating)
    local myRating = addon.db.pvpRating or 1000
    local bestMatch = nil
    local bestRatingDiff = 9999
    
    for name, data in pairs(addon.mpState.queuedPlayers) do
        -- Skip self (check both with and without realm)
        if name ~= myName and name ~= myFullName and not name:find("^" .. myName .. "%-") then
            local ratingDiff = math.abs(data.rating - myRating)
            if ratingDiff < bestRatingDiff then
                bestRatingDiff = ratingDiff
                bestMatch = name
            end
        end
    end
    
    if bestMatch then
        -- Send match request
        addon.mpState.pendingMatch = bestMatch
        local msg = MESSAGE_TYPES.QUEUE_MATCH .. ":" .. (addon.db.pvpRating or 1000)
        addon:SendWhisperMessage(bestMatch, msg)
        print("|cff00ff00[Tetris]|r Match found! Waiting for " .. bestMatch .. " to accept...")
    end
end

-- Handle match request from another player
function addon:HandleQueueMatch(sender, data)
    if not addon.mpState.inQueue then return end
    if addon.mpState.pendingMatch and addon.mpState.pendingMatch ~= sender then return end
    
    local theirRating = tonumber(data) or 1000
    
    -- Auto-accept if we don't have a pending match, or if they're our pending match
    addon.mpState.pendingMatch = sender
    
    -- Send accept
    local msg = MESSAGE_TYPES.QUEUE_ACCEPT .. ":"
    addon:SendWhisperMessage(sender, msg)
    addon.mpState.matchAccepted = true
    
    print("|cff00ff00[Tetris]|r Accepted match with " .. sender .. "!")
end

-- Handle match accepted
function addon:HandleQueueAccept(sender)
    if addon.mpState.pendingMatch ~= sender then return end
    
    print("|cff00ff00[Tetris]|r " .. sender .. " accepted! Starting match...")
    
    -- Leave queue
    addon.mpState.inQueue = false
    if addon.queueHeartbeatTimer then
        addon.queueHeartbeatTimer:Cancel()
        addon.queueHeartbeatTimer = nil
    end
    
    -- Start the match (we are the challenger)
    addon:SendChallenge(sender)
end

-- Handle match declined
function addon:HandleQueueDecline(sender)
    if addon.mpState.pendingMatch == sender then
        addon.mpState.pendingMatch = nil
        addon.mpState.matchAccepted = false
        print("|cffffff00[Tetris]|r " .. sender .. " declined the match.")
    end
end

-- Broadcast message to guild/party
function addon:BroadcastMessage(msg)
    -- Try guild first
    if IsInGuild() then
        C_ChatInfo.SendAddonMessage(COMM_PREFIX, msg, "GUILD")
    end
    -- Also try party/raid
    if IsInGroup() then
        local channel = IsInRaid() and "RAID" or "PARTY"
        C_ChatInfo.SendAddonMessage(COMM_PREFIX, msg, channel)
    end
end

-- Send whisper message
function addon:SendWhisperMessage(target, msg)
    C_ChatInfo.SendAddonMessage(COMM_PREFIX, msg, "WHISPER", target)
end

-- ============================================================
-- QUEUE UI FRAME - Compact Clean Design
-- ============================================================
function addon:ShowQueueFrame()
    if not addon.queueFrame then
        local f = CreateFrame("Frame", "WoWTetrisQueueFrame", UIParent, "BackdropTemplate")
        f:SetSize(280, 320)
        f:SetPoint("CENTER")
        f:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 14,
            insets = {left=3, right=3, top=3, bottom=3}
        })
        f:SetBackdropColor(0.06, 0.06, 0.1, 0.98)
        f:SetBackdropBorderColor(0.5, 0.4, 0.2, 1)
        f:SetFrameStrata("DIALOG")
        f:SetFrameLevel(100)
        f:EnableMouse(true)
        f:SetMovable(true)
        f:RegisterForDrag("LeftButton")
        f:SetScript("OnDragStart", f.StartMoving)
        f:SetScript("OnDragStop", f.StopMovingOrSizing)
        
        -- Title
        f.title = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        f.title:SetPoint("TOP", 0, -10)
        f.title:SetText("|cffff6600PVP Matchmaking|r")
        
        -- Close button
        f.closeBtn = CreateFrame("Button", nil, f, "UIPanelCloseButton")
        f.closeBtn:SetPoint("TOPRIGHT", 0, 0)
        f.closeBtn:SetSize(24, 24)
        f.closeBtn:SetScript("OnClick", function() f:Hide() end)
        
        -- Divider
        local div1 = f:CreateTexture(nil, "ARTWORK")
        div1:SetSize(250, 1)
        div1:SetPoint("TOP", 0, -30)
        div1:SetColorTexture(0.4, 0.35, 0.2, 0.5)
        
        -- Your record
        f.recordLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.recordLabel:SetPoint("TOPLEFT", 15, -40)
        f.recordLabel:SetText("|cff888888Your Record:|r")
        
        f.winsLosses = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.winsLosses:SetPoint("TOPLEFT", 15, -55)
        
        f.rating = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.rating:SetPoint("TOPLEFT", 15, -72)
        
        -- Queue status
        f.queueStatus = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.queueStatus:SetPoint("TOP", 0, -95)
        f.queueStatus:SetText("|cff666666Not Queued|r")
        
        f.queueTime = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.queueTime:SetPoint("TOP", f.queueStatus, "BOTTOM", 0, -2)
        f.queueTime:SetText("")
        
        -- Divider
        local div2 = f:CreateTexture(nil, "ARTWORK")
        div2:SetSize(250, 1)
        div2:SetPoint("TOP", 0, -125)
        div2:SetColorTexture(0.4, 0.35, 0.2, 0.5)
        
        -- Players label
        f.playersLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.playersLabel:SetPoint("TOP", 0, -133)
        f.playersLabel:SetText("|cffffd700Queue:|r 0 players")
        
        -- Player list area
        local listBg = CreateFrame("Frame", nil, f, "BackdropTemplate")
        listBg:SetSize(250, 90)
        listBg:SetPoint("TOP", 0, -150)
        listBg:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 8,
            insets = {left=2, right=2, top=2, bottom=2}
        })
        listBg:SetBackdropColor(0.03, 0.03, 0.05, 0.9)
        f.listBg = listBg
        
        f.scrollChild = CreateFrame("Frame", nil, listBg)
        f.scrollChild:SetSize(240, 200)
        f.scrollChild:SetPoint("TOPLEFT", 5, -5)
        f.playerRows = {}
        
        -- Find Battle button
        f.findBattleBtn = CreateFrame("Button", nil, f, "BackdropTemplate")
        f.findBattleBtn:SetSize(180, 32)
        f.findBattleBtn:SetPoint("BOTTOM", 0, 45)
        f.findBattleBtn:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 10,
            insets = {left=2, right=2, top=2, bottom=2}
        })
        f.findBattleBtn:SetBackdropColor(0.1, 0.35, 0.1, 0.95)
        f.findBattleBtn:SetBackdropBorderColor(0.3, 0.6, 0.3, 1)
        
        f.findBattleBtn.text = f.findBattleBtn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.findBattleBtn.text:SetPoint("CENTER")
        f.findBattleBtn.text:SetText("|cffffffffFind Battle|r")
        
        f.findBattleBtn:SetScript("OnClick", function()
            if addon.mpState.inQueue then
                addon:LeaveRandomQueue()
            else
                addon:JoinRandomQueue()
            end
            addon:UpdateQueueUI()
        end)
        f.findBattleBtn:SetScript("OnEnter", function(self)
            if addon.mpState.inQueue then
                self:SetBackdropColor(0.5, 0.15, 0.15, 1)
            else
                self:SetBackdropColor(0.15, 0.45, 0.15, 1)
            end
        end)
        f.findBattleBtn:SetScript("OnLeave", function(self)
            if addon.mpState.inQueue then
                self:SetBackdropColor(0.4, 0.1, 0.1, 0.95)
            else
                self:SetBackdropColor(0.1, 0.35, 0.1, 0.95)
            end
        end)
        
        -- Challenge Friend button
        f.challengeBtn = CreateFrame("Button", nil, f, "BackdropTemplate")
        f.challengeBtn:SetSize(120, 22)
        f.challengeBtn:SetPoint("BOTTOM", 0, 15)
        f.challengeBtn:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 8,
            insets = {left=2, right=2, top=2, bottom=2}
        })
        f.challengeBtn:SetBackdropColor(0.15, 0.15, 0.2, 0.9)
        
        f.challengeBtn.text = f.challengeBtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.challengeBtn.text:SetPoint("CENTER")
        f.challengeBtn.text:SetText("|cffaaaaaaChallenge Friend|r")
        
        f.challengeBtn:SetScript("OnClick", function()
            StaticPopup_Show("TETRIS_CHALLENGE_PLAYER")
        end)
        f.challengeBtn:SetScript("OnEnter", function(self) 
            self:SetBackdropColor(0.25, 0.25, 0.3, 0.9) 
        end)
        f.challengeBtn:SetScript("OnLeave", function(self) 
            self:SetBackdropColor(0.15, 0.15, 0.2, 0.9) 
        end)
        
        addon.queueFrame = f
        
        -- Static popup
        StaticPopupDialogs["TETRIS_CHALLENGE_PLAYER"] = {
            text = "Enter player name:",
            button1 = "Challenge",
            button2 = "Cancel",
            hasEditBox = true,
            OnAccept = function(self)
                local name = self.editBox:GetText()
                if name and name ~= "" then
                    addon:SendChallenge(name)
                    if addon.queueFrame then addon.queueFrame:Hide() end
                end
            end,
            timeout = 0,
            whileDead = true,
            hideOnEscape = true,
        }
    end
    
    addon:UpdateQueueUI()
    addon.queueFrame:Show()
end

-- Update Queue UI display
function addon:UpdateQueueUI()
    local f = addon.queueFrame
    if not f or not f:IsShown() then return end
    
    -- Update stats
    local wins = addon.db.pvpWins or 0
    local losses = addon.db.pvpLosses or 0
    local rating = addon.db.pvpRating or 1000
    local total = wins + losses
    local winRate = total > 0 and math.floor((wins / total) * 100) or 0
    
    f.winsLosses:SetText("|cff00ff00" .. wins .. "W|r - |cffff0000" .. losses .. "L|r |cff666666(" .. winRate .. "%)|r")
    
    local rc = rating >= 1500 and "|cff00ff00" or (rating >= 1000 and "|cffffff00" or "|cffff0000")
    f.rating:SetText("Rating: " .. rc .. rating .. "|r")
    
    -- Update queue status
    if addon.mpState.inQueue then
        local qt = GetTime() - addon.mpState.queueStartTime
        local mins = math.floor(qt / 60)
        local secs = math.floor(qt % 60)
        
        if addon.mpState.pendingMatch then
            f.queueStatus:SetText("|cff00ff00Match Found!|r")
            f.queueTime:SetText("Connecting...")
        else
            f.queueStatus:SetText("|cffffff00Searching...|r")
            f.queueTime:SetText(string.format("%d:%02d", mins, secs))
        end
        
        f.findBattleBtn.text:SetText("|cffffffffCancel|r")
        f.findBattleBtn:SetBackdropColor(0.4, 0.1, 0.1, 0.95)
        f.findBattleBtn:SetBackdropBorderColor(0.6, 0.3, 0.3, 1)
    else
        f.queueStatus:SetText("|cff666666Not Queued|r")
        f.queueTime:SetText("")
        f.findBattleBtn.text:SetText("|cffffffffFind Battle|r")
        f.findBattleBtn:SetBackdropColor(0.1, 0.35, 0.1, 0.95)
        f.findBattleBtn:SetBackdropBorderColor(0.3, 0.6, 0.3, 1)
    end
    
    -- Clear old rows
    for _, row in ipairs(f.playerRows) do row:Hide() end
    
    -- Filter self
    local myName = UnitName("player")
    local yOffset = 0
    local rowIndex = 0
    local playerCount = 0
    
    for name, data in pairs(addon.mpState.queuedPlayers) do
        if name ~= myName and not name:find("^" .. myName .. "%-") then
            playerCount = playerCount + 1
            rowIndex = rowIndex + 1
            
            local row = f.playerRows[rowIndex]
            if not row then
                row = CreateFrame("Frame", nil, f.scrollChild)
                row:SetSize(230, 22)
                
                row.classIcon = row:CreateTexture(nil, "ARTWORK")
                row.classIcon:SetSize(18, 18)
                row.classIcon:SetPoint("LEFT", 0, 0)
                row.classIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
                
                row.name = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
                row.name:SetPoint("LEFT", row.classIcon, "RIGHT", 4, 0)
                row.name:SetWidth(100)
                row.name:SetJustifyH("LEFT")
                
                row.stats = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
                row.stats:SetPoint("RIGHT", -40, 0)
                
                row.rating = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
                row.rating:SetPoint("RIGHT", 0, 0)
                
                f.playerRows[rowIndex] = row
            end
            
            row:SetPoint("TOPLEFT", 0, -yOffset)
            
            local cd = addon.CLASSES[data.class]
            if cd then
                row.classIcon:SetTexture(cd.icon)
                row.name:SetText(cd.colorCode .. name .. "|r")
            else
                row.classIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
                row.name:SetText(name)
            end
            
            row.stats:SetText("|cff00ff00" .. (data.wins or 0) .. "|r-|cffff0000" .. (data.losses or 0) .. "|r")
            
            local pr = data.rating or 1000
            local prc = pr >= 1500 and "|cff00ff00" or (pr >= 1000 and "|cffffff00" or "|cffff0000")
            row.rating:SetText(prc .. pr .. "|r")
            
            row:Show()
            yOffset = yOffset + 24
        end
    end
    
    f.playersLabel:SetText("|cffffd700Queue:|r " .. playerCount .. " player" .. (playerCount ~= 1 and "s" or ""))
end

-- Handle opponent's ultimate cooldown
function addon:HandleUltimateCooldown(sender, data)
    if sender ~= addon.mpState.opponent then return end
    local cd, ultName = strsplit(",", data)
    addon.mpState.opponentUltimateCd = tonumber(cd) or 0
    addon.mpState.opponentUltimateName = ultName or ""
    addon:UpdateSplitScreenUI()
end

-- Handle opponent's sabotage cooldown
function addon:HandleSabotageCooldown(sender, data)
    if sender ~= addon.mpState.opponent then return end
    local cd, sabName = strsplit(",", data)
    addon.mpState.opponentSabotageCd = tonumber(cd) or 0
    addon.mpState.opponentSabotageName = sabName or ""
    addon:UpdateSplitScreenUI()
end

-- Helper: Send message to opponent (handles BNet vs regular)
function addon:SendToOpponent(msgType, data)
    if not addon.mpState.opponent then return end
    
    if addon.mpState.isBNetMatch and addon.mpState.opponentBNetID then
        addon:SendMessage(msgType, data, "BNET", addon.mpState.opponentBNetID)
    else
        addon:SendMessage(msgType, data, "WHISPER", addon.mpState.opponent)
    end
end

-- Send ultimate cooldown to opponent
function addon:SendUltimateCooldown()
    if not addon.mpState.inMatch or not addon.mpState.opponent then return end
    local cd = math.ceil(addon.ultimateCooldown)
    local ultName = addon.selectedUltimate and addon.selectedUltimate.name or "Unknown"
    addon:SendToOpponent(MESSAGE_TYPES.ULTIMATE_CD, cd .. "," .. ultName)
end

-- Send sabotage cooldown to opponent
function addon:SendSabotageCooldown()
    if not addon.mpState.inMatch or not addon.mpState.opponent then return end
    local cd = math.ceil(addon.mpState.pvpCooldown)
    local sabName = addon.mpState.selectedPvPAbility and addon.mpState.selectedPvPAbility.name or "Unknown"
    addon:SendToOpponent(MESSAGE_TYPES.SABOTAGE_CD, cd .. "," .. sabName)
end

-- Broadcast your stats
function addon:BroadcastStats()
    local stats = addon:GetClassStats(addon.selectedClass or "WARRIOR")
    local playerClass = addon.selectedClass or "WARRIOR"
    local data = string.format("%s,%d,%d", playerClass, stats.level, stats.highScore)
    
    addon:SendMessage(MESSAGE_TYPES.SYNC_STATS, data, "GUILD")
    
    -- Also broadcast to party if in one
    if IsInGroup() then
        addon:SendMessage(MESSAGE_TYPES.SYNC_STATS, data, "PARTY")
    end
end

-- Handle stats sync from another player
function addon:HandleStatsSync(sender, data, channel)
    if not data then return end
    
    local class, level, highScore = strsplit(",", data)
    level = tonumber(level) or 1
    highScore = tonumber(highScore) or 0
    
    local entry = {
        name = sender,
        class = class,
        level = level,
        highScore = highScore,
        lastSeen = time(),
    }
    
    -- Store in appropriate leaderboard
    if channel == "GUILD" then
        addon.leaderboard.guild[sender] = entry
    else
        addon.leaderboard.friends[sender] = entry
    end
    
    -- Update UI if leaderboard is open
    if addon.leaderboardFrame and addon.leaderboardFrame:IsShown() then
        addon:UpdateLeaderboardDisplay()
    end
end

-- Request sync from guild
function addon:RequestGuildSync()
    if IsInGuild() then
        addon:BroadcastStats()
    end
end

-- Request sync from friends
function addon:RequestFriendsSync()
    addon:BroadcastStats()
    -- Scan BNet friends for online WoW players
    addon:ScanBNetFriends()
end

-- Scan Battle.net friends
function addon:ScanBNetFriends()
    local numFriends = BNGetNumFriends()
    for i = 1, numFriends do
        local accountInfo = C_BattleNet.GetFriendAccountInfo(i)
        if accountInfo and accountInfo.gameAccountInfo then
            local gameInfo = accountInfo.gameAccountInfo
            if gameInfo.isOnline and gameInfo.clientProgram == "WoW" then
                local charName = gameInfo.characterName
                local realmName = gameInfo.realmName
                local gameAccountID = gameInfo.gameAccountID
                if charName and realmName then
                    local fullName = charName .. "-" .. realmName
                    -- Add to friends list with BNet info
                    addon.leaderboard.friends[fullName] = {
                        name = fullName,
                        class = gameInfo.className or "UNKNOWN",
                        level = 0,
                        highScore = 0,
                        lastSeen = time(),
                        isBNet = true,
                        bnetAccountID = accountInfo.bnetAccountID,
                        bnetGameAccountID = gameAccountID,
                        bnetName = accountInfo.accountName,
                        faction = gameInfo.factionName,
                    }
                end
            end
        end
    end
end

-- Send challenge to a player
function addon:SendChallenge(playerName, bnetID)
    if addon.mpState.inMatch then
        print("|cffff0000[Tetris]|r Already in a match!")
        return
    end
    
    local myClass = addon.selectedClass or "WARRIOR"
    
    if bnetID then
        -- BNet challenge (cross-faction)
        addon.mpState.pendingBNetChallenge = bnetID
        addon.mpState.pendingChallengeName = playerName
        addon:SendMessage(MESSAGE_TYPES.CHALLENGE, myClass, "BNET", bnetID)
        print("|cff00ff00[Tetris]|r BNet challenge sent to " .. playerName .. "!")
    else
        -- Regular same-faction challenge
        addon.mpState.pendingChallenge = playerName
        addon:SendMessage(MESSAGE_TYPES.CHALLENGE, myClass, "WHISPER", playerName)
        print("|cff00ff00[Tetris]|r Challenge sent to " .. playerName .. "!")
    end
end

-- Handle incoming challenge
function addon:HandleChallenge(sender, data)
    if addon.mpState.inMatch then
        addon:SendMessage(MESSAGE_TYPES.CHALLENGE_DECLINE, "busy", "WHISPER", sender)
        return
    end
    
    addon.mpState.challengeFrom = sender
    addon.mpState.challengeFromBNetID = nil
    addon.mpState.opponentClass = data
    addon.mpState.isBNetMatch = false
    
    -- Show challenge popup
    addon:ShowChallengePopup(sender, data)
end

-- Accept challenge
function addon:AcceptChallenge()
    local sender = addon.mpState.challengeFrom
    if not sender then return end
    
    local myClass = addon.selectedClass or "WARRIOR"
    
    if addon.mpState.challengeFromBNetID then
        -- BNet response
        addon:SendMessage(MESSAGE_TYPES.CHALLENGE_ACCEPT, myClass, "BNET", addon.mpState.challengeFromBNetID)
        addon.mpState.opponentBNetID = addon.mpState.challengeFromBNetID
        addon.mpState.isBNetMatch = true
    else
        -- Regular whisper response
        addon:SendMessage(MESSAGE_TYPES.CHALLENGE_ACCEPT, myClass, "WHISPER", sender)
        addon.mpState.isBNetMatch = false
    end
    
    -- Start match
    addon:StartMultiplayerMatch(sender, addon.mpState.opponentClass)
end

-- Decline challenge
function addon:DeclineChallenge()
    local sender = addon.mpState.challengeFrom
    if sender then
        if addon.mpState.challengeFromBNetID then
            addon:SendMessage(MESSAGE_TYPES.CHALLENGE_DECLINE, "", "BNET", addon.mpState.challengeFromBNetID)
        else
            addon:SendMessage(MESSAGE_TYPES.CHALLENGE_DECLINE, "", "WHISPER", sender)
        end
    end
    addon.mpState.challengeFrom = nil
    addon.mpState.challengeFromBNetID = nil
    addon.mpState.opponentClass = nil
    
    if addon.challengePopup then
        addon.challengePopup:Hide()
    end
end

-- Handle challenge accepted
function addon:HandleChallengeAccepted(sender, data)
    if addon.mpState.pendingChallenge ~= sender then return end
    
    -- data contains the opponent's class
    local opponentClass = data or "WARRIOR"
    
    print("|cff00ff00[Tetris]|r " .. sender .. " accepted your challenge!")
    addon:StartMultiplayerMatch(sender, opponentClass)
end

-- Handle challenge declined
function addon:HandleChallengeDeclined(sender)
    if addon.mpState.pendingChallenge == sender then
        print("|cffff6600[Tetris]|r " .. sender .. " declined your challenge.")
        addon.mpState.pendingChallenge = nil
    end
end

-- Start multiplayer match
function addon:StartMultiplayerMatch(opponent, opponentClass)
    -- Store opponent info
    addon.mpState.inMatch = false  -- Not yet, waiting for lobby
    addon.mpState.opponent = opponent
    addon.mpState.opponentClass = opponentClass or "WARRIOR"
    addon.mpState.opponentScore = 0
    addon.mpState.opponentLevel = 1
    addon.mpState.opponentLines = 0
    addon.mpState.opponentBoard = {}
    addon.mpState.pendingChallenge = nil
    addon.mpState.challengeFrom = nil
    addon.mpState.pvpCooldown = 0
    addon.mpState.selectedPvPAbility = nil
    addon.mpState.pvpAbilityLocked = false
    addon.mpState.playerReady = false
    addon.mpState.opponentReady = false
    addon.mpState.lobbyTimer = 30
    
    -- Initialize opponent board
    for y = 1, addon.BOARD_HEIGHT do
        addon.mpState.opponentBoard[y] = {}
        for x = 1, addon.BOARD_WIDTH do
            addon.mpState.opponentBoard[y][x] = nil
        end
    end
    
    -- Initialize PvP effects
    addon.pvpEffects = {}
    
    -- Hide challenge popup
    if addon.challengePopup then
        addon.challengePopup:Hide()
    end
    
    -- Hide leaderboard if open
    if addon.leaderboardFrame then
        addon.leaderboardFrame:Hide()
    end
    
    -- Show the PvP lobby
    addon:ShowPvPLobby()
end

-- Create and show PvP Lobby
function addon:ShowPvPLobby()
    -- Hide queue frame when entering lobby
    if addon.queueFrame then
        addon.queueFrame:Hide()
    end
    
    if not addon.pvpLobbyFrame then
        local f = CreateFrame("Frame", "WoWTetrisPvPLobby", UIParent, "BackdropTemplate")
        f:SetSize(350, 380)
        f:SetPoint("CENTER")
        f:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 14,
            insets = {left=3, right=3, top=3, bottom=3}
        })
        f:SetBackdropColor(0.05, 0.05, 0.08, 0.98)
        f:SetBackdropBorderColor(0.6, 0.3, 0.3, 1)
        f:SetFrameStrata("DIALOG")
        f:SetFrameLevel(100)
        
        -- Title
        f.title = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        f.title:SetPoint("TOP", 0, -12)
        f.title:SetText("|cffff0000PVP MATCH|r")
        
        -- Timer
        f.timerText = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.timerText:SetPoint("TOP", f.title, "BOTTOM", 0, -3)
        f.timerText:SetText("|cffffd700Time: 30s|r")
        
        -- VS section
        f.vsText = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        f.vsText:SetPoint("TOP", 0, -55)
        f.vsText:SetText("|cffff0000VS|r")
        
        f.oppName = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.oppName:SetPoint("TOP", f.vsText, "BOTTOM", 0, -3)
        
        -- Divider
        f.divider = f:CreateTexture(nil, "ARTWORK")
        f.divider:SetSize(300, 1)
        f.divider:SetPoint("TOP", 0, -95)
        f.divider:SetColorTexture(0.4, 0.4, 0.4, 0.5)
        
        -- Your selection display
        f.yourLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.yourLabel:SetPoint("TOP", 0, -105)
        f.yourLabel:SetText("|cff888888Your Selection:|r")
        
        -- Race + Class icons side by side
        f.yourRaceIcon = f:CreateTexture(nil, "ARTWORK")
        f.yourRaceIcon:SetSize(45, 45)
        f.yourRaceIcon:SetPoint("TOP", -50, -120)
        f.yourRaceIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        
        f.plusSign = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        f.plusSign:SetPoint("TOP", 0, -135)
        f.plusSign:SetText("|cffffd700+|r")
        
        f.yourClassIcon = f:CreateTexture(nil, "ARTWORK")
        f.yourClassIcon:SetSize(45, 45)
        f.yourClassIcon:SetPoint("TOP", 50, -120)
        f.yourClassIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        
        f.yourClassName = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.yourClassName:SetPoint("TOP", 0, -170)
        
        -- Ultimate display
        f.ultLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.ultLabel:SetPoint("TOP", 0, -190)
        f.ultLabel:SetText("|cffff6600Ultimate:|r")
        
        f.yourUltIcon = f:CreateTexture(nil, "ARTWORK")
        f.yourUltIcon:SetSize(35, 35)
        f.yourUltIcon:SetPoint("TOP", 0, -205)
        f.yourUltIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        
        -- PvP Sabotage selection
        f.sabLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.sabLabel:SetPoint("TOP", 0, -250)
        f.sabLabel:SetText("|cffff0000Select PvP Sabotage:|r")
        
        f.pvpButtons = {}
        for i = 1, 3 do
            local btn = CreateFrame("Button", nil, f, "BackdropTemplate")
            btn:SetSize(100, 40)
            btn:SetPoint("TOP", (i-2) * 105, -268)
            btn:SetBackdrop({
                bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
                edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
                tile = true, tileSize = 16, edgeSize = 6,
                insets = {left=1, right=1, top=1, bottom=1}
            })
            btn:SetBackdropColor(0.15, 0.05, 0.05, 0.95)
            btn:SetBackdropBorderColor(0.4, 0.2, 0.2, 1)
            
            btn.icon = btn:CreateTexture(nil, "ARTWORK")
            btn.icon:SetSize(28, 28)
            btn.icon:SetPoint("LEFT", 5, 0)
            btn.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
            
            btn.name = btn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
            btn.name:SetPoint("LEFT", btn.icon, "RIGHT", 3, 0)
            btn.name:SetWidth(58)
            btn.name:SetJustifyH("LEFT")
            
            btn:SetScript("OnEnter", function(self)
                if self.pvpData then
                    GameTooltip:SetOwner(self, "ANCHOR_TOP")
                    GameTooltip:SetText("|cffff0000" .. self.pvpData.name .. "|r")
                    GameTooltip:AddLine(self.pvpData.description, 1, 1, 1, true)
                    GameTooltip:Show()
                end
            end)
            btn:SetScript("OnLeave", function() GameTooltip:Hide() end)
            
            f.pvpButtons[i] = btn
        end
        
        -- Ready button
        f.readyBtn = CreateFrame("Button", nil, f, "BackdropTemplate")
        f.readyBtn:SetSize(150, 35)
        f.readyBtn:SetPoint("BOTTOM", 0, 45)
        f.readyBtn:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 10,
            insets = {left=2, right=2, top=2, bottom=2}
        })
        f.readyBtn:SetBackdropColor(0.2, 0.5, 0.2, 0.95)
        f.readyBtn:SetBackdropBorderColor(0.3, 0.7, 0.3, 1)
        f.readyBtn.text = f.readyBtn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.readyBtn.text:SetPoint("CENTER")
        f.readyBtn.text:SetText("|cff00ff00READY|r")
        f.readyBtn:SetScript("OnClick", function() addon:ToggleLobbyReady() end)
        
        -- Status text
        f.readyStatus = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.readyStatus:SetPoint("TOP", f.readyBtn, "BOTTOM", 0, -5)
        f.readyStatus:SetText("|cff888888Waiting for both players...|r")
        
        -- Cancel button
        f.cancelBtn = CreateFrame("Button", nil, f, "BackdropTemplate")
        f.cancelBtn:SetSize(80, 25)
        f.cancelBtn:SetPoint("BOTTOMRIGHT", -10, 10)
        f.cancelBtn:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 6,
            insets = {left=1, right=1, top=1, bottom=1}
        })
        f.cancelBtn:SetBackdropColor(0.3, 0.1, 0.1, 0.9)
        f.cancelBtn.text = f.cancelBtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.cancelBtn.text:SetPoint("CENTER")
        f.cancelBtn.text:SetText("|cffff6666Cancel|r")
        f.cancelBtn:SetScript("OnClick", function() addon:LeaveLobby() end)
        
        -- Close button
        local closeBtn = CreateFrame("Button", nil, f, "UIPanelCloseButton")
        closeBtn:SetPoint("TOPRIGHT", 0, 0)
        closeBtn:SetSize(22, 22)
        closeBtn:SetScript("OnClick", function() addon:LeaveLobby() end)
        
        addon.pvpLobbyFrame = f
    end
    
    local f = addon.pvpLobbyFrame
    
    -- Set opponent name
    local oppClassData = addon.CLASSES[addon.mpState.opponentClass]
    local oppColor = oppClassData and oppClassData.colorCode or "|cffffffff"
    f.oppName:SetText(oppColor .. (addon.mpState.opponent or "Unknown") .. "|r")
    
    -- Use pre-selected race/class/ultimate
    addon.mpState.lobbyClass = addon.selectedClass
    addon.mpState.lobbyRace = addon.selectedRace
    addon.mpState.lobbyUltimate = addon.selectedUltimate
    addon.mpState.gameStarted = false
    addon.ultimateChargeUsed = 0
    
    -- Display your selection
    local raceData = addon.RACES and addon.RACES[addon.selectedRace]
    local classData = addon.CLASSES[addon.selectedClass]
    
    if raceData then
        f.yourRaceIcon:SetTexture(raceData.icon)
    else
        f.yourRaceIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
    end
    
    if classData then
        f.yourClassIcon:SetTexture(classData.icon)
        f.yourClassName:SetText(classData.colorCode .. classData.name .. "|r")
    else
        f.yourClassIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
        f.yourClassName:SetText("|cff888888Unknown|r")
    end
    
    if addon.selectedUltimate then
        f.yourUltIcon:SetTexture(addon.selectedUltimate.icon)
    else
        f.yourUltIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
    end
    
    -- Setup PvP sabotage buttons
    local abilities = addon.PVP_ABILITIES[addon.selectedClass] or {}
    local stats = addon:GetClassStats(addon.selectedClass)
    local playerLevel = stats and stats.level or 1
    
    for i, btn in ipairs(f.pvpButtons) do
        local ability = abilities[i]
        if ability then
            local isLocked = playerLevel < (ability.unlockLevel or 1)
            btn.pvpData = ability
            btn.pvpData.locked = isLocked
            btn.icon:SetTexture(ability.icon)
            btn.icon:SetDesaturated(isLocked)
            
            if isLocked then
                btn.name:SetText("|cff666666Lv" .. ability.unlockLevel .. "|r")
                btn:SetBackdropColor(0.1, 0.1, 0.1, 0.9)
                btn:SetScript("OnClick", function()
                    print("|cffff0000[Tetris]|r Unlocks at Level " .. ability.unlockLevel)
                end)
            else
                btn.name:SetText(ability.name)
                btn:SetScript("OnClick", function()
                    addon.mpState.selectedPvPAbility = ability
                    addon:UpdateLobbySabotageHighlight()
                end)
            end
            btn:Show()
        else
            btn:Hide()
        end
    end
    
    -- Select first unlocked sabotage by default
    addon.mpState.selectedPvPAbility = nil
    for _, ability in ipairs(abilities) do
        if playerLevel >= (ability.unlockLevel or 1) then
            addon.mpState.selectedPvPAbility = ability
            break
        end
    end
    addon:UpdateLobbySabotageHighlight()
    
    -- Reset ready states
    addon.mpState.playerReady = false
    addon.mpState.opponentReady = false
    f.readyStatus:SetText("|cff888888Waiting for both players...|r")
    f.readyBtn.text:SetText("|cff00ff00READY|r")
    
    -- Start lobby timer
    addon.mpState.lobbyTimer = 30
    f.timerText:SetText("|cffffd700Time: 30s|r")
    
    -- Start timer update
    if f.timerTicker then f.timerTicker:Cancel() end
    f.timerTicker = C_Timer.NewTicker(1, function()
        addon:UpdateLobbyTimer()
    end)
    
    f:Show()
end

-- Update sabotage highlight in lobby
function addon:UpdateLobbySabotageHighlight()
    local f = addon.pvpLobbyFrame
    if not f then return end
    
    for _, btn in ipairs(f.pvpButtons) do
        if btn.pvpData and addon.mpState.selectedPvPAbility and btn.pvpData.name == addon.mpState.selectedPvPAbility.name then
            btn:SetBackdropColor(0.3, 0.15, 0.15, 1)
            btn:SetBackdropBorderColor(0.8, 0.3, 0.3, 1)
        elseif btn.pvpData and not btn.pvpData.locked then
            btn:SetBackdropColor(0.15, 0.05, 0.05, 0.95)
            btn:SetBackdropBorderColor(0.4, 0.2, 0.2, 1)
        end
    end
end

-- Select class in lobby
function addon:SelectLobbyClass(className)
    addon.mpState.lobbyClass = className
    addon.mpState.lobbyUltimate = nil  -- Reset ultimate when class changes
    addon.mpState.lobbyRace = nil  -- Reset race when class changes
    addon.mpState.playerReady = false  -- Un-ready when changing class
    addon:UpdateLobbyClassDisplay()
    addon:UpdateLobbyRaceDisplay()  -- Update race compatibility
    addon:SendLobbyUpdate()
end

-- Update lobby class display
function addon:UpdateLobbyClassDisplay()
    local f = addon.pvpLobbyFrame
    if not f then return end
    
    local className = addon.mpState.lobbyClass or "WARRIOR"
    local classData = addon.CLASSES[className]
    
    -- Highlight selected class and show lock status for premium
    for i, btn in ipairs(f.classButtons) do
        local isPremium = btn.isPremium
        local isOwned = not isPremium or addon:OwnsItem(btn.className, "class")
        
        if btn.className == className and isOwned then
            btn:SetBackdropColor(0.2, 0.5, 0.2, 0.9)
            btn:SetBackdropBorderColor(0.3, 0.8, 0.3, 1)
            if btn.icon then btn.icon:SetDesaturated(false) end
            if btn.lockOverlay then btn.lockOverlay:Hide() end
            if btn.lockIcon then btn.lockIcon:Hide() end
        elseif not isOwned then
            btn:SetBackdropColor(0.1, 0.05, 0.05, 0.8)
            btn:SetBackdropBorderColor(0.5, 0.3, 0.3, 1)
            if btn.icon then btn.icon:SetDesaturated(true) end
            if btn.lockOverlay then btn.lockOverlay:Show() end
            if btn.lockIcon then btn.lockIcon:Show() end
        else
            btn:SetBackdropColor(0.1, 0.1, 0.1, 0.8)
            btn:SetBackdropBorderColor(0.4, 0.4, 0.4, 1)
            if btn.icon then btn.icon:SetDesaturated(false) end
            if btn.lockOverlay then btn.lockOverlay:Hide() end
            if btn.lockIcon then btn.lockIcon:Hide() end
        end
    end
    
    -- Update selected text
    local color = classData and classData.colorCode or "|cffffffff"
    f.selectedClassText:SetText("Class: " .. color .. (classData and classData.name or className) .. "|r")
    
    -- Temporarily set selectedClass so GetAvailableUltimates works
    local oldClass = addon.selectedClass
    addon.selectedClass = className
    
    -- Update ultimate abilities for this class (including shop ultimates)
    local ultimates = addon:GetAvailableUltimates()
    
    addon.selectedClass = oldClass  -- Restore
    
    for i, btn in ipairs(f.ultButtons) do
        local ult = ultimates[i]
        if ult then
            btn.ultData = {
                name = ult.name,
                icon = ult.icon,
                description = ult.description,
                unlockLevel = ult.unlockLevel or 0,
                locked = ult.locked,
                original = ult,
                isShopItem = ult.isShopItem,
                execute = ult.execute
            }
            btn.icon:SetTexture(ult.icon)
            if ult.locked then
                btn.icon:SetDesaturated(true)
                btn:SetBackdropColor(0.05, 0.05, 0.05, 0.9)
            else
                btn.icon:SetDesaturated(false)
                btn:SetBackdropColor(0.1, 0.05, 0.02, 0.8)
            end
            btn:SetScript("OnClick", function()
                if not ult.locked then
                    addon:SelectLobbyUltimate(ult)
                end
            end)
            btn:Show()
        else
            btn:Hide()
        end
    end
    
    -- Auto-select first available ultimate if none selected
    if not addon.mpState.lobbyUltimate then
        for i, ult in ipairs(ultimates) do
            if not ult.locked then
                addon.mpState.lobbyUltimate = ult
                break
            end
        end
    end
    addon:UpdateLobbyUltimateDisplay()
    
    -- Update PvP abilities for this class (using GetAvailableSabotages)
    local abilities = addon:GetAvailableSabotages() or addon.PVP_ABILITIES[className] or addon.PVP_ABILITIES["WARRIOR"]
    for i, btn in ipairs(f.pvpButtons) do
        local ability = abilities[i]
        if ability then
            btn.ability = ability
            btn.icon:SetTexture(ability.icon)
            btn.name:SetText(ability.name)
            if ability.locked then
                btn.icon:SetDesaturated(true)
                btn:SetBackdropColor(0.05, 0.05, 0.05, 0.8)
            else
                btn.icon:SetDesaturated(false)
                btn:SetBackdropColor(0.15, 0.05, 0.05, 0.8)
            end
            btn:SetScript("OnClick", function()
                if not ability.locked then
                    addon:SelectLobbyPvPAbility(ability)
                end
            end)
            btn:Show()
        else
            btn:Hide()
        end
    end
    
    -- Reset PvP selection when class changes
    addon.mpState.selectedPvPAbility = nil
    f.selectedPvPText:SetText("|cff888888No sabotage selected|r")
    
    -- Update PvP button highlights
    addon:UpdateLobbyPvPDisplay()
end

-- Select ultimate in lobby
function addon:SelectLobbyUltimate(ult)
    addon.mpState.lobbyUltimate = ult
    addon.mpState.playerReady = false  -- Un-ready when changing
    addon:UpdateLobbyUltimateDisplay()
    addon:SendLobbyUpdate()
end

-- Select race in lobby
function addon:SelectLobbyRace(raceName)
    local raceData = addon.RACES and addon.RACES[raceName]
    if not raceData then return end
    
    -- Check if race is unlocked
    if raceData.cost > 0 and not addon:IsRaceUnlocked(raceName) then
        print("|cffff0000[Tetris]|r " .. raceData.name .. " is locked!")
        return
    end
    
    -- Check class compatibility
    local className = addon.mpState.lobbyClass or "WARRIOR"
    local compatible = false
    for _, c in ipairs(raceData.classes) do
        if c == className then compatible = true; break end
    end
    if not compatible then
        print("|cffff0000[Tetris]|r " .. raceData.name .. " cannot be " .. className .. "!")
        return
    end
    
    addon.mpState.lobbyRace = raceName
    addon.selectedRace = raceName
    addon.mpState.playerReady = false
    addon:UpdateLobbyRaceDisplay()
    addon:SendLobbyUpdate()
end

-- Update race display in lobby
function addon:UpdateLobbyRaceDisplay()
    local f = addon.pvpLobbyFrame
    if not f or not f.raceButtons then return end
    
    local selectedRace = addon.mpState.lobbyRace
    local selectedClass = addon.mpState.lobbyClass or "WARRIOR"
    
    for i, btn in ipairs(f.raceButtons) do
        if btn and btn.raceName then
            local raceData = addon.RACES[btn.raceName]
            local isUnlocked = raceData.cost == 0 or addon:IsRaceUnlocked(btn.raceName)
            local isCompatible = false
            for _, c in ipairs(raceData.classes) do
                if c == selectedClass then isCompatible = true; break end
            end
            
            if selectedRace == btn.raceName then
                btn:SetBackdropColor(0.1, 0.3, 0.1, 1)
                btn:SetBackdropBorderColor(0.3, 0.9, 0.3, 1)
                btn.icon:SetDesaturated(false)
            elseif not isUnlocked then
                btn:SetBackdropColor(0.15, 0.1, 0.1, 0.8)
                btn:SetBackdropBorderColor(0.5, 0.3, 0.3, 1)
                btn.icon:SetDesaturated(true)
            elseif not isCompatible then
                btn:SetBackdropColor(0.1, 0.1, 0.1, 0.7)
                btn:SetBackdropBorderColor(0.3, 0.3, 0.3, 1)
                btn.icon:SetDesaturated(true)
            else
                btn:SetBackdropColor(0.1, 0.1, 0.1, 0.8)
                btn:SetBackdropBorderColor(0.4, 0.4, 0.4, 1)
                btn.icon:SetDesaturated(false)
            end
        end
    end
    
    if selectedRace then
        local raceData = addon.RACES[selectedRace]
        local typeStr = raceData.abilityType == "pvp" and "|cffff4444PvP|r" or "|cff00ff00Solo|r"
        f.selectedRaceText:SetText("|cff00ff00" .. raceData.name .. "|r - " .. typeStr .. ": " .. raceData.ability.name)
    else
        f.selectedRaceText:SetText("|cff888888No race selected|r")
    end
end

-- Update ultimate display in lobby
function addon:UpdateLobbyUltimateDisplay()
    local f = addon.pvpLobbyFrame
    if not f then return end
    
    local selected = addon.mpState.lobbyUltimate
    
    for i, btn in ipairs(f.ultButtons) do
        if btn.ultData and not btn.ultData.locked then
            if selected and btn.ultData.name == selected.name then
                btn:SetBackdropColor(0.2, 0.15, 0.05, 1)
                btn:SetBackdropBorderColor(0.8, 0.6, 0.2, 1)
            else
                btn:SetBackdropColor(0.1, 0.05, 0.02, 0.8)
                btn:SetBackdropBorderColor(0.5, 0.3, 0.1, 1)
            end
        end
    end
    
    if selected then
        f.selectedUltText:SetText("|cffff6600Ultimate: " .. selected.name .. "|r")
    else
        f.selectedUltText:SetText("|cff888888No ultimate selected|r")
    end
end

-- Select PvP ability in lobby
function addon:SelectLobbyPvPAbility(ability)
    addon.mpState.selectedPvPAbility = ability
    addon.mpState.playerReady = false  -- Un-ready when changing ability
    addon:UpdateLobbyPvPDisplay()
    addon:SendLobbyUpdate()
end

-- Update PvP ability display
function addon:UpdateLobbyPvPDisplay()
    local f = addon.pvpLobbyFrame
    if not f then return end
    
    local selected = addon.mpState.selectedPvPAbility
    
    for i, btn in ipairs(f.pvpButtons) do
        if btn.ability and selected and btn.ability.name == selected.name then
            btn:SetBackdropColor(0.5, 0.2, 0.2, 0.9)
        else
            btn:SetBackdropColor(0.1, 0.1, 0.15, 0.8)
        end
    end
    
    if selected then
        f.selectedPvPText:SetText("|cffff6600" .. selected.name .. "|r")
    else
        f.selectedPvPText:SetText("|cff888888No ability selected|r")
    end
end

-- Toggle ready state
function addon:ToggleLobbyReady()
    local f = addon.pvpLobbyFrame
    if not f then return end
    
    -- Must have class, ultimate, and sabotage selected
    if not addon.mpState.lobbyClass then
        print("|cffff0000[Tetris]|r Select a class first!")
        return
    end
    if not addon.mpState.lobbyUltimate then
        print("|cffff0000[Tetris]|r Select an ultimate first!")
        return
    end
    if not addon.mpState.selectedPvPAbility then
        print("|cffff0000[Tetris]|r Select a PvP sabotage ability first!")
        return
    end
    
    addon.mpState.playerReady = not addon.mpState.playerReady
    
    if addon.mpState.playerReady then
        f.readyBtn:SetText("|cff00ff00READY!|r")
        -- Lock in selections
        addon.selectedClass = addon.mpState.lobbyClass
        addon.selectedUltimate = addon.mpState.lobbyUltimate
    else
        f.readyBtn:SetText("READY")
    end
    
    addon:SendLobbyUpdate()
    addon:UpdateLobbyReadyStatus()
    
    -- Check if both ready
    if addon.mpState.playerReady and addon.mpState.opponentReady then
        addon:StartPvPGame()
    end
end

-- Update ready status display
function addon:UpdateLobbyReadyStatus()
    local f = addon.pvpLobbyFrame
    if not f then return end
    
    local you = addon.mpState.playerReady and "|cff00ff00You: Ready|r" or "|cffff0000You: Not Ready|r"
    local opp = addon.mpState.opponentReady and "|cff00ff00Opponent: Ready|r" or "|cffff0000Opponent: Not Ready|r"
    f.readyStatus:SetText(you .. "  |  " .. opp)
end

-- Update lobby timer
function addon:UpdateLobbyTimer()
    local f = addon.pvpLobbyFrame
    if not f or not f:IsShown() then 
        if f and f.timerTicker then f.timerTicker:Cancel() end
        return 
    end
    
    addon.mpState.lobbyTimer = addon.mpState.lobbyTimer - 1
    
    if addon.mpState.lobbyTimer <= 0 then
        -- Time's up - auto-ready with defaults if not ready
        if not addon.mpState.playerReady then
            if not addon.mpState.selectedPvPAbility then
                local abilities = addon.PVP_ABILITIES[addon.mpState.lobbyClass or "WARRIOR"]
                addon.mpState.selectedPvPAbility = abilities and abilities[1]
            end
            addon.mpState.playerReady = true
            addon:SendLobbyUpdate()
        end
        
        -- Start game anyway
        addon:StartPvPGame()
        return
    end
    
    local color = addon.mpState.lobbyTimer <= 10 and "|cffff0000" or "|cffffd700"
    f.timerText:SetText(color .. "Time: " .. addon.mpState.lobbyTimer .. "s|r")
end

-- Send lobby update to opponent
function addon:SendLobbyUpdate()
    if not addon.mpState.opponent then return end
    
    local className = addon.mpState.lobbyClass or "WARRIOR"
    local pvpName = addon.mpState.selectedPvPAbility and addon.mpState.selectedPvPAbility.name or "none"
    local ready = addon.mpState.playerReady and "1" or "0"
    
    local data = className .. "," .. pvpName .. "," .. ready
    addon:SendToOpponent(MESSAGE_TYPES.LOBBY, data)
end

-- Handle lobby update from opponent
function addon:HandleLobbyUpdate(sender, data)
    if addon.mpState.opponent ~= sender then return end
    
    local className, pvpName, ready = strsplit(",", data)
    addon.mpState.opponentClass = className
    addon.mpState.opponentReady = (ready == "1")
    
    -- Update the lobby display
    addon:UpdateLobbyReadyStatus()
    
    -- Update opponent name display with their class
    if addon.pvpLobbyFrame and addon.pvpLobbyFrame:IsShown() then
        local oppClassData = addon.CLASSES[className]
        local oppColor = oppClassData and oppClassData.colorCode or "|cffffffff"
        addon.pvpLobbyFrame.oppName:SetText(oppColor .. sender .. " (" .. (oppClassData and oppClassData.name or className) .. ")|r")
    end
    
    -- Check if both ready
    if addon.mpState.playerReady and addon.mpState.opponentReady then
        C_Timer.After(0.5, function()
            addon:StartPvPGame()
        end)
    end
end

-- Cancel lobby
function addon:CancelPvPLobby()
    local f = addon.pvpLobbyFrame
    if f then
        if f.timerTicker then f.timerTicker:Cancel() end
        f:Hide()
    end
    
    addon.mpState.inMatch = false
    addon.mpState.opponent = nil
    print("|cffff6600[Tetris]|r Left PvP lobby.")
end

-- Actually start the PvP game
function addon:StartPvPGame()
    -- Prevent double-starting
    if addon.mpState.gameStarted then return end
    addon.mpState.gameStarted = true
    
    local f = addon.pvpLobbyFrame
    if f then
        if f.timerTicker then f.timerTicker:Cancel() end
        f:Hide()
    end
    
    -- Lock in selections
    addon.selectedClass = addon.mpState.lobbyClass or "WARRIOR"
    addon.selectedRace = addon.mpState.lobbyRace  -- Lock in race selection
    addon.mpState.pvpAbilityLocked = true
    addon.mpState.inMatch = true
    
    -- Reset racial for new round
    addon.racialUsedThisRound = false
    
    -- Make sure main frame exists
    if not addon.mainFrame then
        addon:CreateMainUI()
    end
    addon.mainFrame:Show()
    
    -- Use ShowGame to properly hide menu and show game frame
    addon:ShowGame()
    
    -- Initialize the game directly
    addon:InitializeBoard()
    addon:ResetPieceBag()
    
    local state = addon.gameState
    state.score = 0
    state.linesCleared = 0
    state.totalLines = 0
    state.gameTime = 0
    state.isPlaying = true
    state.isPaused = false
    state.isGameOver = false
    state.dropTimer = 0
    state.lockTimer = 0
    state.lockMoves = 0
    state.heldPiece = nil
    state.canHold = true
    state.combo = 0
    state.lastClearWasDifficult = false
    state.speedMultiplier = 1.0
    state.scoreMultiplier = 1.0
    state.lockDelayBonus = 0
    
    -- Reset ultimate
    addon.ultimateCooldown = 0
    addon.ultimateChargeUsed = 0  -- IMPORTANT: Reset charge tracking!
    addon.ultimateEffects = {}
    
    -- Use the ultimate selected in lobby, or first available
    if addon.mpState.lobbyUltimate then
        addon.selectedUltimate = addon.mpState.lobbyUltimate
    else
        local available = addon:GetAvailableUltimates()
        if available and available[1] then
            addon.selectedUltimate = available[1]
        end
    end
    
    -- Reset PvP effects
    addon.pvpEffects = {}
    addon.lastMoveTime = nil
    
    -- Fill next pieces
    state.nextPieces = {}
    for i = 1, 6 do
        table.insert(state.nextPieces, addon:GetNextPiece())
    end
    
    -- Spawn first piece
    addon:SpawnNextPiece()
    
    -- Reset quest counters for this game
    if addon.ResetGameQuestCounters then addon:ResetGameQuestCounters() end
    
    -- Update background and UI
    addon:UpdateClassBackground()
    addon:UpdateUI()
    
    -- Show split screen for opponent
    addon:ShowSplitScreenUI()
    
    -- Start background music
    addon:StartMusic()
    
    -- Reset gameStarted flag for next match
    C_Timer.After(1, function()
        addon.mpState.gameStarted = false
    end)
    
    print("|cff00ff00[Tetris]|r PvP Match started! Press [V] to sabotage!")
end

-- Send game update to opponent
function addon:SendGameUpdate()
    if not addon.mpState.inMatch or not addon.mpState.opponent then return end
    
    local state = addon.gameState
    
    -- Encode board as a simple string (0 for empty, 1 for filled)
    local boardStr = ""
    for y = 1, addon.BOARD_HEIGHT do
        for x = 1, addon.BOARD_WIDTH do
            if state.board[y] and state.board[y][x] then
                boardStr = boardStr .. "1"
            else
                boardStr = boardStr .. "0"
            end
        end
    end
    
    -- Include current piece info: type,x,y,rotation
    local pieceInfo = ""
    if state.currentPiece then
        pieceInfo = string.format("%s;%d;%d;%d", 
            state.currentPiece.type, 
            state.currentPiece.x, 
            state.currentPiece.y, 
            state.currentPiece.rotation)
    end
    
    local data = string.format("%d,%d,%d,%s,%s", state.score, 1, state.totalLines, boardStr, pieceInfo)
    
    addon:SendToOpponent(MESSAGE_TYPES.GAME_UPDATE, data)
end

-- Handle game update from opponent
function addon:HandleGameUpdate(sender, data)
    if not addon.mpState.inMatch or addon.mpState.opponent ~= sender then return end
    
    local score, level, lines, boardStr, pieceInfo = strsplit(",", data)
    addon.mpState.opponentScore = tonumber(score) or 0
    addon.mpState.opponentLevel = tonumber(level) or 1
    addon.mpState.opponentLines = tonumber(lines) or 0
    
    -- Decode board
    if boardStr and #boardStr == addon.BOARD_WIDTH * addon.BOARD_HEIGHT then
        local idx = 1
        for y = 1, addon.BOARD_HEIGHT do
            addon.mpState.opponentBoard[y] = addon.mpState.opponentBoard[y] or {}
            for x = 1, addon.BOARD_WIDTH do
                addon.mpState.opponentBoard[y][x] = boardStr:sub(idx, idx) == "1"
                idx = idx + 1
            end
        end
    end
    
    -- Decode current piece
    if pieceInfo and pieceInfo ~= "" then
        local pType, pX, pY, pRot = strsplit(";", pieceInfo)
        addon.mpState.opponentPiece = {
            type = pType,
            x = tonumber(pX) or 0,
            y = tonumber(pY) or 0,
            rotation = tonumber(pRot) or 0
        }
    else
        addon.mpState.opponentPiece = nil
    end
    
    -- Update split screen display
    addon:UpdateSplitScreenOpponent()
end

-- Send game over (player's board filled up = they lost)
function addon:SendGameOver(finalScore)
    if not addon.mpState.inMatch or not addon.mpState.opponent then return end
    
    addon:SendToOpponent(MESSAGE_TYPES.GAME_OVER, tostring(finalScore))
end

-- Send win message (player reached win score)
function addon:SendPvPWin(winScore)
    if not addon.mpState.inMatch or not addon.mpState.opponent then return end
    
    addon:SendToOpponent(MESSAGE_TYPES.PVP_WIN, tostring(winScore))
end

-- Handle opponent game over (their board filled up = they lost, we win)
function addon:HandleOpponentGameOver(sender, data)
    if not addon.mpState.inMatch or addon.mpState.opponent ~= sender then return end
    
    local opponentScore = tonumber(data) or 0
    addon.mpState.opponentScore = opponentScore
    
    -- Opponent's board filled up - they lost, we win!
    print("|cff00ff00[Tetris]|r " .. sender .. "'s board filled up! You WIN!")
    
    -- Stop our game
    addon.gameState.isPlaying = false
    addon.gameState.isGameOver = true
    addon:UpdateUI()
    
    -- Show victory
    addon:ShowPvPMatchResults(true, addon.gameState.score)
end

-- Check if we reached win score (called from game update)
function addon:CheckPvPWinCondition()
    if not addon.mpState.inMatch then return end
    
    if addon.gameState.score >= PVP_WIN_SCORE then
        -- We won by reaching the score!
        print("|cff00ff00[Tetris]|r You reached " .. PVP_WIN_SCORE .. " points! VICTORY!")
        
        -- Send win message to opponent
        addon:SendPvPWin(addon.gameState.score)
        
        -- Stop our game
        addon.gameState.isPlaying = false
        addon.gameState.isGameOver = true
        addon:UpdateUI()
        
        -- Show victory
        addon:ShowPvPMatchResults(true, addon.gameState.score)
    end
end

-- Show PvP match results
function addon:ShowPvPMatchResults(isWin, finalScore)
    local myScore = addon.gameState.score
    local oppScore = addon.mpState.opponentScore or 0
    local opponent = addon.mpState.opponent or "Opponent"
    local myClass = addon.selectedClass
    local oppClass = addon.mpState.opponentClass
    
    -- Stop background music
    addon:StopMusic(true)
    
    -- Record PvP result (win/loss and rating)
    addon:RecordPvPResult(isWin)
    
    -- Save class stats (XP from score)
    if addon.SaveClassStats then
        addon:SaveClassStats()
    end
    
    -- Create results popup
    if not addon.matchResultFrame then
        local f = CreateFrame("Frame", "WoWTetrisMatchResult", UIParent, "BackdropTemplate")
        f:SetSize(350, 250)
        f:SetPoint("CENTER")
        f:SetBackdrop({
            bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
            edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border",
            tile = true, tileSize = 32, edgeSize = 32,
            insets = {left=8, right=8, top=8, bottom=8}
        })
        f:SetFrameStrata("DIALOG")
        f:SetFrameLevel(200)
        
        f.title = f:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
        f.title:SetPoint("TOP", 0, -20)
        
        f.subtitle = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.subtitle:SetPoint("TOP", f.title, "BOTTOM", 0, -5)
        
        f.ratingChange = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        f.ratingChange:SetPoint("TOP", f.subtitle, "BOTTOM", 0, -5)
        
        f.myInfo = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.myInfo:SetPoint("TOPLEFT", 30, -95)
        
        f.oppInfo = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.oppInfo:SetPoint("TOPRIGHT", -30, -95)
        
        f.winCondition = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.winCondition:SetPoint("BOTTOM", 0, 55)
        
        local closeBtn = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
        closeBtn:SetSize(100, 25)
        closeBtn:SetPoint("BOTTOM", 0, 20)
        closeBtn:SetText("Main Menu")
        closeBtn:SetScript("OnClick", function()
            f:Hide()
            addon:HideSplitScreenUI()
            addon:ShowMenu()
        end)
        
        addon.matchResultFrame = f
    end
    
    local f = addon.matchResultFrame
    f.title:SetText(isWin and "|cff00ff00VICTORY!|r" or "|cffff0000DEFEAT|r")
    
    -- Show rating change
    local rating = addon.db.pvpRating or 1000
    if isWin then
        f.ratingChange:SetText("|cff00ff00+25 Rating|r (Now: " .. rating .. ")")
    else
        f.ratingChange:SetText("|cffff0000-20 Rating|r (Now: " .. rating .. ")")
    end
    
    -- Track PvP quests
    if addon.TrackPvPMatch then addon:TrackPvPMatch() end
    if isWin and addon.TrackPvPWin then addon:TrackPvPWin() end
    
    -- Award currency
    if isWin then
        if addon.AwardCurrencyForPvPWin then addon:AwardCurrencyForPvPWin() end
    else
        if addon.AwardCurrencyForPvPLoss then addon:AwardCurrencyForPvPLoss() end
    end
    
    -- Determine win reason
    local winReason = ""
    if isWin then
        if myScore >= PVP_WIN_SCORE then
            winReason = "Reached " .. PVP_WIN_SCORE .. " points!"
        else
            winReason = "Opponent's board filled up!"
        end
        f.subtitle:SetText("|cff00ff00" .. winReason .. "|r")
    else
        if oppScore >= PVP_WIN_SCORE then
            winReason = "Opponent reached " .. PVP_WIN_SCORE .. " points"
        else
            winReason = "Your board filled up"
        end
        f.subtitle:SetText("|cffff6600" .. winReason .. "|r")
    end
    
    local myClassData = addon.CLASSES[myClass]
    local oppClassData = addon.CLASSES[oppClass] or addon.CLASSES["WARRIOR"]
    
    -- Get reward amounts
    local coinsEarned = isWin and addon.CURRENCY_REWARDS.pvp_win or addon.CURRENCY_REWARDS.pvp_loss
    local tokensEarned = isWin and addon.CURRENCY_REWARDS.pvp_win_tokens or addon.CURRENCY_REWARDS.pvp_loss_tokens
    
    f.myInfo:SetText(UnitName("player") .. "\n" .. 
        (myClassData and myClassData.colorCode .. myClassData.name .. "|r" or myClass) .. "\n" ..
        "|cffffd700Score: " .. myScore .. "|r")
    
    f.oppInfo:SetText(opponent .. "\n" ..
        (oppClassData and oppClassData.colorCode .. oppClassData.name .. "|r" or oppClass) .. "\n" ..
        "|cffffd700Score: " .. oppScore .. "|r")
    
    f.winCondition:SetText("|cffffd700+" .. coinsEarned .. " Coins|r  |cffff4444+" .. tokensEarned .. " PvP Tokens|r")
    
    -- Reset match state
    addon.mpState.inMatch = false
    
    f:Show()
end

-- Show challenge popup
function addon:ShowChallengePopup(sender, theirClass)
    if not addon.challengePopup then
        local f = CreateFrame("Frame", "WoWTetrisChallengePopup", UIParent, "BackdropTemplate")
        f:SetSize(300, 150)
        f:SetPoint("CENTER", 0, 100)
        f:SetBackdrop({
            bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
            edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border",
            tile = true, tileSize = 32, edgeSize = 32,
            insets = {left=8, right=8, top=8, bottom=8}
        })
        f:SetFrameStrata("DIALOG")
        f:SetFrameLevel(200)
        
        f.title = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        f.title:SetPoint("TOP", 0, -15)
        f.title:SetText("|cff00ff00Tetris Challenge!|r")
        
        f.text = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.text:SetPoint("CENTER", 0, 10)
        f.text:SetWidth(260)
        
        local acceptBtn = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
        acceptBtn:SetSize(80, 25)
        acceptBtn:SetPoint("BOTTOMLEFT", 40, 20)
        acceptBtn:SetText("Accept")
        acceptBtn:SetScript("OnClick", function()
            addon:AcceptChallenge()
        end)
        
        local declineBtn = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
        declineBtn:SetSize(80, 25)
        declineBtn:SetPoint("BOTTOMRIGHT", -40, 20)
        declineBtn:SetText("Decline")
        declineBtn:SetScript("OnClick", function()
            addon:DeclineChallenge()
        end)
        
        addon.challengePopup = f
    end
    
    local classData = addon.CLASSES[theirClass]
    local className = classData and (classData.colorCode .. classData.name .. "|r") or theirClass
    
    addon.challengePopup.text:SetText(sender .. " (" .. className .. ")\nchallenges you to a 1v1 Tetris match!")
    addon.challengePopup:Show()
    
    -- Play sound
    PlaySound(SOUNDKIT.READY_CHECK)
end

-- Create Leaderboard UI
function addon:CreateLeaderboardFrame()
    if addon.leaderboardFrame then return end
    
    local f = CreateFrame("Frame", "WoWTetrisLeaderboard", addon.mainFrame, "BackdropTemplate")
    f:SetSize(420, 480)
    f:SetPoint("CENTER", UIParent, "CENTER")
    f:SetBackdrop({
        bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
        edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border",
        tile = true, tileSize = 32, edgeSize = 32,
        insets = {left=8, right=8, top=8, bottom=8}
    })
    f:SetFrameStrata("DIALOG")
    f:Hide()
    
    -- Title
    local title = f:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
    title:SetPoint("TOP", 0, -15)
    title:SetText("|cffffd700Leaderboard|r")
    
    -- Close button
    local closeBtn = CreateFrame("Button", nil, f, "UIPanelCloseButton")
    closeBtn:SetPoint("TOPRIGHT", -5, -5)
    
    -- Tab buttons
    local guildTab = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    guildTab:SetSize(100, 25)
    guildTab:SetPoint("TOPLEFT", 20, -45)
    guildTab:SetText("Guild")
    guildTab:SetScript("OnClick", function()
        f.currentTab = "guild"
        addon:UpdateLeaderboardDisplay()
    end)
    f.guildTab = guildTab
    
    local friendsTab = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    friendsTab:SetSize(100, 25)
    friendsTab:SetPoint("LEFT", guildTab, "RIGHT", 10, 0)
    friendsTab:SetText("Friends")
    friendsTab:SetScript("OnClick", function()
        f.currentTab = "friends"
        addon:UpdateLeaderboardDisplay()
    end)
    f.friendsTab = friendsTab
    
    -- Refresh button
    local refreshBtn = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    refreshBtn:SetSize(80, 25)
    refreshBtn:SetPoint("TOPRIGHT", -20, -45)
    refreshBtn:SetText("Refresh")
    refreshBtn:SetScript("OnClick", function()
        addon:BroadcastStats()
        print("|cff00ff00[Tetris]|r Requesting leaderboard update...")
    end)
    
    -- Scroll frame for entries
    local scrollFrame = CreateFrame("ScrollFrame", nil, f, "UIPanelScrollFrameTemplate")
    scrollFrame:SetPoint("TOPLEFT", 20, -80)
    scrollFrame:SetPoint("BOTTOMRIGHT", -40, 60)
    
    local scrollChild = CreateFrame("Frame")
    scrollChild:SetSize(360, 1)
    scrollFrame:SetScrollChild(scrollChild)
    f.scrollChild = scrollChild
    
    f.entries = {}
    
    -- Challenge selected player button
    local challengeBtn = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    challengeBtn:SetSize(150, 30)
    challengeBtn:SetPoint("BOTTOM", 0, 20)
    challengeBtn:SetText("Challenge Selected")
    challengeBtn:SetScript("OnClick", function()
        if f.selectedPlayer then
            -- Check if this is a BNet friend
            local friendData = addon.leaderboard.friends[f.selectedPlayer]
            if friendData and friendData.isBNet and friendData.bnetGameAccountID then
                addon:SendChallenge(f.selectedPlayer, friendData.bnetGameAccountID)
            else
                addon:SendChallenge(f.selectedPlayer)
            end
        end
    end)
    f.challengeBtn = challengeBtn
    
    f.currentTab = "guild"
    f.selectedPlayer = nil
    f.selectedBNetID = nil
    
    addon.leaderboardFrame = f
end

-- Update leaderboard display
function addon:UpdateLeaderboardDisplay()
    local f = addon.leaderboardFrame
    if not f then return end
    
    -- Clear existing entries
    for _, entry in ipairs(f.entries) do
        entry:Hide()
    end
    
    -- Get data for current tab
    local data = f.currentTab == "guild" and addon.leaderboard.guild or addon.leaderboard.friends
    
    -- Sort by level then score
    local sorted = {}
    for name, info in pairs(data) do
        table.insert(sorted, info)
    end
    table.sort(sorted, function(a, b)
        if a.level ~= b.level then
            return a.level > b.level
        end
        return a.highScore > b.highScore
    end)
    
    -- Create/update entries
    for i, info in ipairs(sorted) do
        local entry = f.entries[i]
        if not entry then
            entry = CreateFrame("Button", nil, f.scrollChild)
            entry:SetSize(360, 35)
            entry:SetPoint("TOPLEFT", 0, -(i-1) * 38)
            
            entry.bg = entry:CreateTexture(nil, "BACKGROUND")
            entry.bg:SetAllPoints()
            entry.bg:SetColorTexture(0.1, 0.1, 0.1, 0.5)
            
            entry.rank = entry:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            entry.rank:SetPoint("LEFT", 10, 0)
            entry.rank:SetWidth(30)
            
            entry.name = entry:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            entry.name:SetPoint("LEFT", 45, 0)
            entry.name:SetWidth(120)
            entry.name:SetJustifyH("LEFT")
            
            entry.class = entry:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
            entry.class:SetPoint("LEFT", 170, 0)
            entry.class:SetWidth(80)
            
            entry.level = entry:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            entry.level:SetPoint("LEFT", 255, 0)
            entry.level:SetWidth(40)
            
            entry.score = entry:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            entry.score:SetPoint("LEFT", 300, 0)
            entry.score:SetWidth(60)
            entry.score:SetJustifyH("RIGHT")
            
            entry:SetScript("OnClick", function(self)
                f.selectedPlayer = self.playerName
                addon:UpdateLeaderboardDisplay()
            end)
            
            entry:SetScript("OnEnter", function(self)
                self.bg:SetColorTexture(0.2, 0.2, 0.3, 0.7)
            end)
            entry:SetScript("OnLeave", function(self)
                if f.selectedPlayer == self.playerName then
                    self.bg:SetColorTexture(0.1, 0.3, 0.1, 0.7)
                else
                    self.bg:SetColorTexture(0.1, 0.1, 0.1, 0.5)
                end
            end)
            
            f.entries[i] = entry
        end
        
        local classData = addon.CLASSES[info.class]
        local className = classData and (classData.colorCode .. classData.name .. "|r") or info.class
        
        entry.rank:SetText("|cffffd700#" .. i .. "|r")
        entry.name:SetText(info.name)
        entry.class:SetText(className)
        entry.level:SetText("|cff00ff00Lv" .. info.level .. "|r")
        entry.score:SetText("|cffffd700" .. info.highScore .. "|r")
        entry.playerName = info.name
        
        if f.selectedPlayer == info.name then
            entry.bg:SetColorTexture(0.1, 0.3, 0.1, 0.7)
        else
            entry.bg:SetColorTexture(0.1, 0.1, 0.1, 0.5)
        end
        
        entry:Show()
    end
    
    -- Update scroll child height
    f.scrollChild:SetHeight(math.max(1, #sorted * 38))
    
    -- Update tab highlights
    f.guildTab:SetEnabled(f.currentTab ~= "guild")
    f.friendsTab:SetEnabled(f.currentTab ~= "friends")
    
    -- Show empty message if no data
    if #sorted == 0 then
        if not f.emptyText then
            f.emptyText = f.scrollChild:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            f.emptyText:SetPoint("CENTER", f.scrollChild, "CENTER", 0, 100)
        end
        f.emptyText:SetText("|cff888888No players found.\nClick Refresh to sync!|r")
        f.emptyText:Show()
    elseif f.emptyText then
        f.emptyText:Hide()
    end
end

-- Show leaderboard
function addon:ShowLeaderboard()
    addon:CreateLeaderboardFrame()
    addon.leaderboardFrame:Show()
    addon:UpdateLeaderboardDisplay()
end

-- Create Split Screen UI
function addon:ShowSplitScreenUI()
    -- Make sure main frame exists and is shown
    if addon.mainFrame then
        addon.mainFrame:Show()
    end
    
    if not addon.splitScreenFrame then
        local f = CreateFrame("Frame", "WoWTetrisSplitScreen", UIParent, "BackdropTemplate")
        f:SetSize(220, 540)
        f:SetBackdrop({
            bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
            edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border",
            tile = true, tileSize = 32, edgeSize = 32,
            insets = {left=8, right=8, top=8, bottom=8}
        })
        f:SetFrameStrata("HIGH")
        
        -- Close button
        local closeBtn = CreateFrame("Button", nil, f, "UIPanelCloseButton")
        closeBtn:SetPoint("TOPRIGHT", -2, -2)
        closeBtn:SetScript("OnClick", function()
            addon:HideSplitScreenUI()
            addon.mpState.inMatch = false
            addon.mpState.opponent = nil
            print("|cffff0000[Tetris]|r Left the PvP match.")
        end)
        
        -- Target score display
        f.targetLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.targetLabel:SetPoint("TOP", 0, -12)
        f.targetLabel:SetText("|cffff0000First to " .. PVP_WIN_SCORE .. " wins!|r")
        
        -- Opponent header
        f.oppName = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        f.oppName:SetPoint("TOP", 0, -28)
        
        f.oppClass = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.oppClass:SetPoint("TOP", f.oppName, "BOTTOM", 0, -3)
        
        -- Opponent stats
        local statsY = -68
        
        f.oppScoreLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.oppScoreLabel:SetPoint("TOPLEFT", 15, statsY)
        f.oppScoreLabel:SetText("|cff888888SCORE|r")
        
        f.oppScore = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        f.oppScore:SetPoint("TOPLEFT", f.oppScoreLabel, "BOTTOMLEFT", 0, -2)
        
        f.oppLevelLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.oppLevelLabel:SetPoint("TOPLEFT", 85, statsY)
        f.oppLevelLabel:SetText("|cff888888LEVEL|r")
        
        f.oppLevel = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.oppLevel:SetPoint("TOPLEFT", f.oppLevelLabel, "BOTTOMLEFT", 0, -2)
        
        f.oppLinesLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.oppLinesLabel:SetPoint("TOPLEFT", 150, statsY)
        f.oppLinesLabel:SetText("|cff888888LINES|r")
        
        f.oppLines = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.oppLines:SetPoint("TOPLEFT", f.oppLinesLabel, "BOTTOMLEFT", 0, -2)
        
        -- Mini board for opponent
        local miniBlockSize = 9
        local boardWidth = addon.BOARD_WIDTH * miniBlockSize
        local boardHeight = addon.BOARD_HEIGHT * miniBlockSize
        
        f.miniBoard = CreateFrame("Frame", nil, f, "BackdropTemplate")
        f.miniBoard:SetSize(boardWidth + 4, boardHeight + 4)
        f.miniBoard:SetPoint("TOP", 0, -95)
        f.miniBoard:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 8,
            insets = {left=2, right=2, top=2, bottom=2}
        })
        f.miniBoard:SetBackdropColor(0.05, 0.05, 0.1, 0.9)
        
        f.miniBlocks = {}
        for y = 1, addon.BOARD_HEIGHT do
            f.miniBlocks[y] = {}
            for x = 1, addon.BOARD_WIDTH do
                local b = f.miniBoard:CreateTexture(nil, "ARTWORK")
                b:SetSize(miniBlockSize - 1, miniBlockSize - 1)
                b:SetPoint("BOTTOMLEFT", f.miniBoard, "BOTTOMLEFT", 
                    2 + (x-1)*miniBlockSize, 2 + (addon.BOARD_HEIGHT-y)*miniBlockSize)
                b:SetColorTexture(0.1, 0.1, 0.1, 0.5)
                f.miniBlocks[y][x] = b
            end
        end
        
        -- YOUR ABILITIES SECTION
        f.yourAbilitiesLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.yourAbilitiesLabel:SetPoint("TOP", f.miniBoard, "BOTTOM", 0, -8)
        f.yourAbilitiesLabel:SetText("|cff00ff00YOUR ABILITIES|r")
        
        -- Race icon display (next to YOUR ABILITIES label)
        f.raceIconFrame = CreateFrame("Frame", nil, f, "BackdropTemplate")
        f.raceIconFrame:SetSize(30, 30)
        f.raceIconFrame:SetPoint("TOPRIGHT", f.miniBoard, "BOTTOMRIGHT", 0, -5)
        f.raceIconFrame:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 8,
            insets = {left=1, right=1, top=1, bottom=1}
        })
        f.raceIconFrame:SetBackdropColor(0.1, 0.2, 0.1, 0.9)
        f.raceIconFrame:SetBackdropBorderColor(0.3, 0.6, 0.3, 1)
        f.raceIconFrame:EnableMouse(true)
        
        f.raceIcon = f.raceIconFrame:CreateTexture(nil, "ARTWORK")
        f.raceIcon:SetSize(24, 24)
        f.raceIcon:SetPoint("CENTER")
        f.raceIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        
        f.raceCdText = f.raceIconFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.raceCdText:SetPoint("CENTER")
        f.raceCdText:SetText("")
        
        f.raceIconFrame:SetScript("OnEnter", function(self)
            local raceName = addon.selectedRace or addon.mpState.lobbyRace
            if raceName then
                local raceData = addon.RACES[raceName]
                if raceData then
                    GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
                    local typeStr = raceData.abilityType == "pvp" and "|cffff4444[PvP Racial]|r" or "|cff00ff00[Solo Racial]|r"
                    GameTooltip:SetText(raceData.name .. " " .. typeStr)
                    GameTooltip:AddLine(raceData.ability.name, 0, 1, 0)
                    GameTooltip:AddLine(raceData.ability.description, 1, 1, 1, true)
                    GameTooltip:AddLine(" ")
                    GameTooltip:AddLine("Press [B] to use racial", 0.7, 0.7, 0.7)
                    GameTooltip:Show()
                end
            end
        end)
        f.raceIconFrame:SetScript("OnLeave", function() GameTooltip:Hide() end)
        
        -- Your Sabotage frame (icon + name + CD)
        f.pvpAbilityFrame = CreateFrame("Frame", nil, f, "BackdropTemplate")
        f.pvpAbilityFrame:SetSize(190, 40)
        f.pvpAbilityFrame:SetPoint("TOP", f.yourAbilitiesLabel, "BOTTOM", 0, -3)
        f.pvpAbilityFrame:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 10,
            insets = {left=2, right=2, top=2, bottom=2}
        })
        f.pvpAbilityFrame:SetBackdropColor(0.1, 0.05, 0.05, 0.8)
        f.pvpAbilityFrame:SetBackdropBorderColor(0.5, 0.2, 0.2, 1)
        f.pvpAbilityFrame:EnableMouse(true)
        f.pvpAbilityFrame:SetScript("OnEnter", function(self)
            local ability = addon.mpState.selectedPvPAbility
            if ability then
                GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
                GameTooltip:SetText("|cffff0000" .. ability.name .. "|r")
                GameTooltip:AddLine(ability.description, 1, 1, 1, true)
                GameTooltip:AddLine(" ")
                GameTooltip:AddLine("Cooldown: 15s", 0.7, 0.7, 0.7)
                GameTooltip:AddLine("Press [V] to use", 0, 1, 0)
                GameTooltip:Show()
            end
        end)
        f.pvpAbilityFrame:SetScript("OnLeave", function() GameTooltip:Hide() end)
        
        f.pvpIcon = f.pvpAbilityFrame:CreateTexture(nil, "ARTWORK")
        f.pvpIcon:SetSize(30, 30)
        f.pvpIcon:SetPoint("LEFT", 5, 0)
        f.pvpIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        
        f.pvpName = f.pvpAbilityFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.pvpName:SetPoint("LEFT", f.pvpIcon, "RIGHT", 5, 5)
        f.pvpName:SetText("|cffff6600Sabotage [V]|r")
        
        f.pvpCooldownText = f.pvpAbilityFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.pvpCooldownText:SetPoint("LEFT", f.pvpIcon, "RIGHT", 5, -8)
        
        -- ENEMY ABILITIES SECTION
        f.enemyAbilitiesLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        f.enemyAbilitiesLabel:SetPoint("TOP", f.pvpAbilityFrame, "BOTTOM", 0, -12)
        f.enemyAbilitiesLabel:SetText("|cffff0000ENEMY ABILITIES|r")
        
        -- Enemy abilities container (horizontal with 2 icons)
        f.enemyAbilityContainer = CreateFrame("Frame", nil, f, "BackdropTemplate")
        f.enemyAbilityContainer:SetSize(190, 55)
        f.enemyAbilityContainer:SetPoint("TOP", f.enemyAbilitiesLabel, "BOTTOM", 0, -3)
        f.enemyAbilityContainer:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 10,
            insets = {left=2, right=2, top=2, bottom=2}
        })
        f.enemyAbilityContainer:SetBackdropColor(0.08, 0.02, 0.02, 0.9)
        f.enemyAbilityContainer:SetBackdropBorderColor(0.4, 0.1, 0.1, 1)
        
        -- Enemy Ultimate icon button
        f.oppUltBtn = CreateFrame("Button", nil, f.enemyAbilityContainer, "BackdropTemplate")
        f.oppUltBtn:SetSize(45, 45)
        f.oppUltBtn:SetPoint("LEFT", 20, 0)
        f.oppUltBtn:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 8,
            insets = {left=1, right=1, top=1, bottom=1}
        })
        f.oppUltBtn:SetBackdropColor(0.1, 0.05, 0.02, 1)
        f.oppUltBtn:SetBackdropBorderColor(0.6, 0.4, 0.1, 1)
        
        f.oppUltIcon = f.oppUltBtn:CreateTexture(nil, "ARTWORK")
        f.oppUltIcon:SetSize(38, 38)
        f.oppUltIcon:SetPoint("CENTER")
        f.oppUltIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        f.oppUltIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
        
        f.oppUltCdText = f.oppUltBtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.oppUltCdText:SetPoint("CENTER")
        f.oppUltCdText:SetText("")
        
        f.oppUltLabel = f.enemyAbilityContainer:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.oppUltLabel:SetPoint("TOP", f.oppUltBtn, "BOTTOM", 0, -2)
        f.oppUltLabel:SetText("|cffff6600Ultimate|r")
        
        f.oppUltBtn:SetScript("OnEnter", function(self)
            local ultName = addon.mpState.opponentUltimateName
            if ultName and ultName ~= "" then
                local oppClass = addon.mpState.opponentClass
                local ultimates = addon.ULTIMATES[oppClass] or {}
                for _, ult in ipairs(ultimates) do
                    if ult.name == ultName then
                        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
                        GameTooltip:SetText("|cffff6600" .. ult.name .. "|r")
                        GameTooltip:AddLine(ult.description, 1, 1, 1, true)
                        GameTooltip:AddLine(" ")
                        GameTooltip:AddLine("Cooldown: " .. (ult.cooldown or 30) .. "s", 0.7, 0.7, 0.7)
                        GameTooltip:Show()
                        break
                    end
                end
            else
                GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
                GameTooltip:SetText("|cff888888Unknown Ultimate|r")
                GameTooltip:Show()
            end
        end)
        f.oppUltBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)
        
        -- Enemy Sabotage icon button
        f.oppSabBtn = CreateFrame("Button", nil, f.enemyAbilityContainer, "BackdropTemplate")
        f.oppSabBtn:SetSize(45, 45)
        f.oppSabBtn:SetPoint("RIGHT", -20, 0)
        f.oppSabBtn:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 8,
            insets = {left=1, right=1, top=1, bottom=1}
        })
        f.oppSabBtn:SetBackdropColor(0.15, 0.02, 0.02, 1)
        f.oppSabBtn:SetBackdropBorderColor(0.6, 0.2, 0.2, 1)
        
        f.oppSabIcon = f.oppSabBtn:CreateTexture(nil, "ARTWORK")
        f.oppSabIcon:SetSize(38, 38)
        f.oppSabIcon:SetPoint("CENTER")
        f.oppSabIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
        f.oppSabIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
        
        f.oppSabCdText = f.oppSabBtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.oppSabCdText:SetPoint("CENTER")
        f.oppSabCdText:SetText("")
        
        f.oppSabLabel = f.enemyAbilityContainer:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        f.oppSabLabel:SetPoint("TOP", f.oppSabBtn, "BOTTOM", 0, -2)
        f.oppSabLabel:SetText("|cffff0000Sabotage|r")
        
        f.oppSabBtn:SetScript("OnEnter", function(self)
            local sabName = addon.mpState.opponentSabotageName
            if sabName and sabName ~= "" then
                local oppClass = addon.mpState.opponentClass
                local abilities = addon.PVP_ABILITIES[oppClass] or {}
                for _, ab in ipairs(abilities) do
                    if ab.name == sabName then
                        GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
                        GameTooltip:SetText("|cffff0000" .. ab.name .. "|r")
                        GameTooltip:AddLine(ab.description, 1, 1, 1, true)
                        GameTooltip:AddLine(" ")
                        GameTooltip:AddLine("Cooldown: 15s", 0.7, 0.7, 0.7)
                        GameTooltip:Show()
                        break
                    end
                end
            else
                GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
                GameTooltip:SetText("|cff888888Unknown Sabotage|r")
                GameTooltip:Show()
            end
        end)
        f.oppSabBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)
        
        -- VS indicator
        f.vsText = f:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
        f.vsText:SetPoint("BOTTOM", 0, 10)
        f.vsText:SetText("|cffff0000VS|r")
        
        addon.splitScreenFrame = f
    end
    
    local f = addon.splitScreenFrame
    
    -- Position to the right of main frame
    f:ClearAllPoints()
    if addon.mainFrame then
        f:SetPoint("LEFT", addon.mainFrame, "RIGHT", 10, 0)
    else
        f:SetPoint("CENTER", UIParent, "CENTER", 250, 0)
    end
    
    local oppClassData = addon.CLASSES[addon.mpState.opponentClass]
    
    f.oppName:SetText("|cffffffff" .. (addon.mpState.opponent or "Opponent") .. "|r")
    f.oppClass:SetText(oppClassData and (oppClassData.colorCode .. oppClassData.name .. "|r") or (addon.mpState.opponentClass or "Unknown"))
    
    -- Update race icon display
    local raceName = addon.selectedRace or addon.mpState.lobbyRace
    if raceName and addon.RACES[raceName] then
        local raceData = addon.RACES[raceName]
        f.raceIcon:SetTexture(raceData.icon)
        if raceData.abilityType == "pvp" then
            f.raceIconFrame:SetBackdropColor(0.2, 0.1, 0.1, 0.9)
            f.raceIconFrame:SetBackdropBorderColor(0.6, 0.3, 0.3, 1)
        else
            f.raceIconFrame:SetBackdropColor(0.1, 0.2, 0.1, 0.9)
            f.raceIconFrame:SetBackdropBorderColor(0.3, 0.6, 0.3, 1)
        end
        f.raceIconFrame:Show()
    else
        f.raceIconFrame:Hide()
    end
    
    -- Update PvP ability display
    addon:UpdatePvPAbilityDisplay()
    
    f:Show()
    addon:UpdateSplitScreenOpponent()
end

-- Update PvP ability display
function addon:UpdatePvPAbilityDisplay()
    local f = addon.splitScreenFrame
    if not f then return end
    
    local ability = addon.mpState.selectedPvPAbility
    if ability then
        f.pvpIcon:SetTexture(ability.icon)
        f.pvpName:SetText("|cffff6600" .. ability.name .. "|r")
    else
        f.pvpIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
        f.pvpName:SetText("|cff888888None selected|r")
    end
    
    if addon.mpState.pvpCooldown > 0 then
        f.pvpCooldownText:SetText("|cffff6600" .. math.ceil(addon.mpState.pvpCooldown) .. "s|r")
    else
        f.pvpCooldownText:SetText("|cff00ff00Ready!|r")
    end
    
    -- Hide/disable the change button if locked
    if f.changeAbilityBtn then
        if addon.mpState.pvpAbilityLocked and addon.mpState.selectedPvPAbility then
            f.changeAbilityBtn:Hide()
        else
            f.changeAbilityBtn:Show()
        end
    end
end

-- Update split screen opponent display
function addon:UpdateSplitScreenOpponent()
    local f = addon.splitScreenFrame
    if not f or not f:IsShown() then return end
    
    f.oppScore:SetText("|cffffd700" .. addon.mpState.opponentScore .. "|r")
    f.oppLevel:SetText("|cff00ff00" .. addon.mpState.opponentLevel .. "|r")
    f.oppLines:SetText("|cff00ffff" .. addon.mpState.opponentLines .. "|r")
    
    -- Update mini board
    if f.miniBlocks then
        -- First clear all blocks
        for y = 1, addon.BOARD_HEIGHT do
            for x = 1, addon.BOARD_WIDTH do
                local block = f.miniBlocks[y][x]
                if addon.mpState.opponentBoard[y] and addon.mpState.opponentBoard[y][x] then
                    block:SetColorTexture(0.4, 0.4, 0.8, 0.9)  -- Placed blocks
                else
                    block:SetColorTexture(0.1, 0.1, 0.1, 0.3)  -- Empty
                end
            end
        end
        
        -- Draw opponent's current piece
        local piece = addon.mpState.opponentPiece
        if piece and piece.type and addon.PIECES[piece.type] then
            local blocks = addon:GetPieceBlocks(piece.type, piece.rotation)
            for _, block in ipairs(blocks) do
                local bx = piece.x + block[1] + 1
                local by = piece.y + block[2] + 1
                if by >= 1 and by <= addon.BOARD_HEIGHT and bx >= 1 and bx <= addon.BOARD_WIDTH then
                    f.miniBlocks[by][bx]:SetColorTexture(0.8, 0.8, 0.2, 1)  -- Current piece in yellow
                end
            end
        end
    end
    
    -- Update PvP ability cooldown display
    if f.pvpCooldownText then
        if addon.mpState.pvpCooldown > 0 then
            f.pvpCooldownText:SetText("|cffff6600" .. math.ceil(addon.mpState.pvpCooldown) .. "s|r")
        else
            f.pvpCooldownText:SetText("|cff00ff00Ready!|r")
        end
    end
    
    -- Update opponent ultimate display (icon based)
    if f.oppUltIcon then
        local ultName = addon.mpState.opponentUltimateName
        if ultName and ultName ~= "" then
            -- Find the icon from opponent's class
            local oppClass = addon.mpState.opponentClass
            local ultimates = addon.ULTIMATES[oppClass] or {}
            local foundIcon = nil
            for _, ult in ipairs(ultimates) do
                if ult.name == ultName then
                    foundIcon = ult.icon
                    break
                end
            end
            f.oppUltIcon:SetTexture(foundIcon or "Interface\\Icons\\INV_Misc_QuestionMark")
            f.oppUltIcon:SetDesaturated(false)
        else
            f.oppUltIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
            f.oppUltIcon:SetDesaturated(true)
        end
    end
    if f.oppUltCdText then
        local cd = addon.mpState.opponentUltimateCd or 0
        if cd > 0 then
            f.oppUltCdText:SetText("|cffff0000" .. cd .. "s|r")
            if f.oppUltIcon then f.oppUltIcon:SetDesaturated(true) end
        else
            f.oppUltCdText:SetText("")
            if f.oppUltIcon and addon.mpState.opponentUltimateName and addon.mpState.opponentUltimateName ~= "" then 
                f.oppUltIcon:SetDesaturated(false) 
            end
        end
    end
    
    -- Update opponent sabotage display (icon based)
    if f.oppSabIcon then
        local sabName = addon.mpState.opponentSabotageName
        if sabName and sabName ~= "" then
            -- Find the icon from opponent's class
            local oppClass = addon.mpState.opponentClass
            local abilities = addon.PVP_ABILITIES[oppClass] or {}
            local foundIcon = nil
            for _, ab in ipairs(abilities) do
                if ab.name == sabName then
                    foundIcon = ab.icon
                    break
                end
            end
            f.oppSabIcon:SetTexture(foundIcon or "Interface\\Icons\\INV_Misc_QuestionMark")
            f.oppSabIcon:SetDesaturated(false)
        else
            f.oppSabIcon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
            f.oppSabIcon:SetDesaturated(true)
        end
    end
    if f.oppSabCdText then
        local cd = addon.mpState.opponentSabotageCd or 0
        if cd > 0 then
            f.oppSabCdText:SetText("|cffff0000" .. cd .. "s|r")
            if f.oppSabIcon then f.oppSabIcon:SetDesaturated(true) end
        else
            f.oppSabCdText:SetText("")
            if f.oppSabIcon and addon.mpState.opponentSabotageName and addon.mpState.opponentSabotageName ~= "" then 
                f.oppSabIcon:SetDesaturated(false) 
            end
        end
    end
end

-- Update split screen UI (alias for UpdateSplitScreenOpponent)
function addon:UpdateSplitScreenUI()
    addon:UpdateSplitScreenOpponent()
end

-- Hide split screen
function addon:HideSplitScreenUI()
    if addon.splitScreenFrame then
        addon.splitScreenFrame:Hide()
    end
    addon.mpState.inMatch = false
    addon.mpState.opponent = nil
end

-- Hook into game over
local originalGameOver = addon.GameOver
function addon:GameOver()
    originalGameOver(self)
    
    if addon.mpState.inMatch then
        addon:EndMultiplayerMatch()
    end
end

-- Hook into score updates to sync with opponent
local updateCounter = 0
local lastTime = GetTime()
local originalUpdateUI = addon.UpdateUI
function addon:UpdateUI()
    if originalUpdateUI then
        originalUpdateUI(self)
    end
    
    -- Calculate elapsed time
    local now = GetTime()
    local elapsed = now - lastTime
    lastTime = now
    
    -- Update PvP cooldown
    if addon.mpState.pvpCooldown > 0 then
        addon.mpState.pvpCooldown = addon.mpState.pvpCooldown - elapsed
        if addon.mpState.pvpCooldown < 0 then
            addon.mpState.pvpCooldown = 0
        end
        addon:UpdatePvPAbilityDisplay()
    end
    
    -- Send updates every few frames during match
    if addon.mpState.inMatch then
        updateCounter = updateCounter + 1
        if updateCounter >= 15 then  -- More frequent updates
            addon:SendGameUpdate()
            updateCounter = 0
        end
    end
end

-- ============================================================
-- PVP SABOTAGE ABILITIES (5 per class, 15 second cooldown)
-- BALANCED: Freeze/Stun = Instant Drop, No speed effects, Max 4 scattered blocks, Max 1 garbage row
-- ============================================================

addon.PVP_ABILITIES = {
    WARRIOR = {
        {name = "War Cry", icon = "Interface\\Icons\\Ability_Warrior_BattleShout", description = "Add 1 garbage row to opponent.", unlockLevel = 1},
        {name = "Shattering Throw", icon = "Interface\\Icons\\Ability_Warrior_ShatteringThrow", description = "Scatter 4 random blocks on opponent's board.", unlockLevel = 25},
        {name = "Recklessness", icon = "Interface\\Icons\\Ability_CriticalStrike", description = "Add 1 garbage row + force instant drop.", unlockLevel = 50},
    },
    PALADIN = {
        {name = "Blinding Light", icon = "Interface\\Icons\\Ability_Paladin_BlindingLight", description = "Hide opponent's next piece preview for 5 seconds.", unlockLevel = 1},
        {name = "Turn Evil", icon = "Interface\\Icons\\Spell_Holy_TurnUndead", description = "Reverse opponent's left/right controls for 5 seconds.", unlockLevel = 25},
        {name = "Avenging Wrath", icon = "Interface\\Icons\\Spell_Holy_AvengeWrath", description = "Disable opponent's ultimate for 12 seconds.", unlockLevel = 50},
    },
    HUNTER = {
        {name = "Freezing Trap", icon = "Interface\\Icons\\Spell_Frost_FreezingBreath", description = "Force opponent's current piece to instant drop.", unlockLevel = 1},
        {name = "Scatter Shot", icon = "Interface\\Icons\\Ability_GolemStormBolt", description = "Scatter 4 random blocks on opponent's board.", unlockLevel = 25},
        {name = "Intimidation", icon = "Interface\\Icons\\Ability_Devour", description = "Add 1 garbage row + instant drop.", unlockLevel = 50},
    },
    ROGUE = {
        {name = "Blind", icon = "Interface\\Icons\\Spell_Shadow_MindSteal", description = "Black out opponent's board for 3 seconds.", unlockLevel = 1},
        {name = "Crippling Poison", icon = "Interface\\Icons\\Ability_PoisonSting", description = "Disable opponent's hold function for 8 seconds.", unlockLevel = 25},
        {name = "Marked for Death", icon = "Interface\\Icons\\Ability_Hunter_MarkedForDeath", description = "Force next piece to S or Z + instant drop.", unlockLevel = 50},
    },
    PRIEST = {
        {name = "Psychic Scream", icon = "Interface\\Icons\\Spell_Shadow_PsychicScream", description = "Shuffle opponent's top 5 rows randomly.", unlockLevel = 1},
        {name = "Silence", icon = "Interface\\Icons\\Spell_Shadow_Impphaseshift", description = "Disable opponent's ultimate for 10 seconds.", unlockLevel = 25},
        {name = "Surrender to Madness", icon = "Interface\\Icons\\Achievement_Boss_GeneralVezax_01", description = "Shuffle board + 1 garbage row.", unlockLevel = 50},
    },
    DEATHKNIGHT = {
        {name = "Chains of Ice", icon = "Interface\\Icons\\Spell_Frost_ChainsOfIce", description = "Disable opponent's movement for 3 seconds.", unlockLevel = 1},
        {name = "Death Grip", icon = "Interface\\Icons\\Spell_DeathKnight_Strangulate", description = "Force opponent's piece to instant drop.", unlockLevel = 25},
        {name = "Apocalypse", icon = "Interface\\Icons\\Artifactability_UnholyDeathKnight_TheDarkestCrusade", description = "Add 1 garbage row + scatter 4 blocks.", unlockLevel = 50},
    },
    SHAMAN = {
        {name = "Hex", icon = "Interface\\Icons\\Spell_Shaman_Hex", description = "Transform opponent's piece into a random one.", unlockLevel = 1},
        {name = "Earthquake Totem", icon = "Interface\\Icons\\Spell_Nature_Earthquake", description = "Scatter 4 blocks on opponent's board.", unlockLevel = 25},
        {name = "Stormkeeper", icon = "Interface\\Icons\\Ability_Thunderking_LightningWhip", description = "Push blocks up 1 row + scatter 4 blocks.", unlockLevel = 50},
    },
    MAGE = {
        {name = "Polymorph", icon = "Interface\\Icons\\Spell_Nature_Polymorph", description = "Turn opponent's current piece into a square (O).", unlockLevel = 1},
        {name = "Frost Nova", icon = "Interface\\Icons\\Spell_Frost_FrostNova", description = "Force opponent's current piece to instant drop.", unlockLevel = 25},
        {name = "Deep Freeze", icon = "Interface\\Icons\\Ability_Mage_DeepFreeze", description = "Instant drop + hide preview for 5 seconds.", unlockLevel = 50},
    },
    WARLOCK = {
        {name = "Fear", icon = "Interface\\Icons\\Spell_Shadow_Possession", description = "Reverse opponent's controls for 4 seconds.", unlockLevel = 1},
        {name = "Shadowfury", icon = "Interface\\Icons\\Spell_Shadow_Shadowfury", description = "Add 1 garbage row to opponent.", unlockLevel = 25},
        {name = "Summon Infernal", icon = "Interface\\Icons\\Spell_Shadow_SummonInfernal", description = "Add 2 garbage rows to opponent.", unlockLevel = 50},
    },
    DRUID = {
        {name = "Entangling Roots", icon = "Interface\\Icons\\Spell_Nature_StrangleVines", description = "Disable opponent's rotation for 4 seconds.", unlockLevel = 1},
        {name = "Cyclone", icon = "Interface\\Icons\\Spell_Nature_Cyclone", description = "Spin opponent's current piece randomly for 3 seconds.", unlockLevel = 25},
        {name = "Incarnation", icon = "Interface\\Icons\\Spell_Druid_Incarnation", description = "Add 1 garbage row + disable rotation for 5 seconds.", unlockLevel = 50},
    },
    MONK = {
        {name = "Paralysis", icon = "Interface\\Icons\\Ability_Monk_Paralysis", description = "Force opponent's current piece to instant drop.", unlockLevel = 1},
        {name = "Leg Sweep", icon = "Interface\\Icons\\Ability_Monk_LegSweep", description = "Scatter 4 random blocks on opponent's board.", unlockLevel = 25},
        {name = "Touch of Karma", icon = "Interface\\Icons\\Ability_Monk_TouchOfKarma", description = "Reflect next sabotage back at opponent.", unlockLevel = 50},
    },
    DEMONHUNTER = {
        {name = "Imprison", icon = "Interface\\Icons\\Ability_DemonHunter_Imprison", description = "Hide opponent's board for 3 seconds.", unlockLevel = 1},
        {name = "Chaos Nova", icon = "Interface\\Icons\\Ability_DemonHunter_ChaosNova", description = "Scatter 4 random blocks on opponent's board.", unlockLevel = 25},
        {name = "Metamorphosis", icon = "Interface\\Icons\\Ability_DemonHunter_Metamorphasis", description = "Add 1 garbage row + reverse controls for 4 seconds.", unlockLevel = 50},
    },
    EVOKER = {
        {name = "Landslide", icon = "Interface\\Icons\\Ability_Evoker_Landslide", description = "Push opponent's blocks up by 1 row.", unlockLevel = 1},
        {name = "Oppressing Roar", icon = "Interface\\Icons\\Ability_Evoker_OppressingRoar", description = "Disable opponent's ultimate for 8 seconds.", unlockLevel = 25},
        {name = "Deep Breath", icon = "Interface\\Icons\\Ability_Evoker_DeepBreath", description = "Add 2 garbage rows to opponent.", unlockLevel = 50},
    },
}

addon.PVP_COOLDOWN = 15  -- 15 second cooldown

-- Send sabotage to opponent
function addon:SendPvPSabotage(sabotageType, data)
    if not addon.mpState.inMatch or not addon.mpState.opponent then return end
    local msg = sabotageType .. (data and ("," .. data) or "")
    addon:SendToOpponent(MESSAGE_TYPES.PVP_SABOTAGE, msg)
end

-- Racial ability state (once per round)
addon.racialUsedThisRound = false

-- Use Racial ability (once per round)
function addon:UseRacialAbility()
    local raceName = addon.selectedRace
    if not raceName then
        print("|cffff0000[Tetris]|r No race selected!")
        return
    end
    
    local raceData = addon.RACES[raceName]
    if not raceData then return end
    
    -- Check if already used this round
    if addon.racialUsedThisRound then
        print("|cffff6600[Tetris]|r Racial already used this round!")
        return
    end
    
    -- Check if game is playing
    if not addon.gameState.isPlaying or addon.gameState.isPaused then
        return
    end
    
    local abilityType = raceData.abilityType
    local ability = raceData.ability
    
    if abilityType == "pvp" then
        -- PvP racial - send sabotage to opponent
        if not addon.mpState or not addon.mpState.inMatch then
            print("|cffff0000[Tetris]|r " .. ability.name .. " is a PvP racial - only usable in PvP!")
            return
        end
        
        -- Send racial sabotage to opponent
        addon:SendPvPSabotage("RACIAL_" .. raceName)
        print("|cff00ff00[Tetris]|r Used racial " .. ability.name .. " on " .. addon.mpState.opponent .. "!")
    else
        -- Solo racial - execute local effect
        addon:ExecuteRacialEffect(raceName)
        print("|cff00ff00[Tetris]|r Used racial " .. ability.name .. "!")
    end
    
    -- Mark as used this round
    addon.racialUsedThisRound = true
    
    -- Update display
    addon:UpdateUI()
end

-- Execute solo racial effects
function addon:ExecuteRacialEffect(raceName)
    local raceData = addon.RACES[raceName]
    if not raceData then return end
    
    local ability = raceData.ability
    
    if raceName == "DWARF" then
        -- Stoneform: Remove ALL garbage blocks
        addon:Ult_RemoveGarbageBlocks()
        print("|cff00ff00[Racial]|r Stoneform removed all garbage blocks!")
        
    elseif raceName == "GNOME" then
        -- Engineering Genius: Next 5 pieces are I-pieces
        addon:Ult_SetForcedPieces(5, "I")
        
    elseif raceName == "DRAENEI" then
        -- Gift of the Naaru: Fill ALL gaps in bottom 6 rows
        addon:Ult_FillGaps(6)
        print("|cff00ff00[Racial]|r Gift of the Naaru healed bottom 6 rows!")
        
    elseif raceName == "WORGEN" then
        -- Darkflight Frenzy: +50% score for 20 sec
        addon:Ult_SetTimedEffect("bonusScore50", 20)
        print("|cff00ff00[Racial]|r Darkflight Frenzy! +50% score for 20 seconds!")
        
    elseif raceName == "TAUREN" then
        -- War Stomp: Clear bottom 5 rows
        addon:Ult_ClearBottom(5)
        print("|cff00ff00[Racial]|r War Stomp cleared bottom 5 rows!")
        
    elseif raceName == "TROLL" then
        -- Berserking: Ultimate charges 3x faster for 30 sec
        addon:Ult_SetTimedEffect("fastCharge3x", 30)
        print("|cff00ff00[Racial]|r Berserking! Ultimate charges 3x faster for 30 seconds!")
        
    elseif raceName == "BLOODELF" then
        -- Arcane Torrent: Fully charge ultimate instantly
        addon.ultimateCooldown = 0
        addon.ultimateChargeUsed = addon.gameState.score - 9999  -- This makes charge = 9999+
        print("|cff00ff00[Racial]|r Arcane Torrent fully charged your ultimate!")
        
    elseif raceName == "GOBLIN" then
        -- Rocket Barrage: Clear 3 rows + 15 random blocks
        addon:Ult_ClearRandomRows(3)
        addon:Ult_DestroyRandom(15)
        print("|cff00ff00[Racial]|r Rocket Barrage! 3 rows + 15 blocks destroyed!")
        
    elseif raceName == "PANDAREN" then
        -- Inner Peace: Slow drops 75% + double score 15 sec
        addon:Ult_SetTimedEffect("slowDrop75", 15)
        addon:Ult_SetTimedEffect("doubleScore", 15)
        print("|cff00ff00[Racial]|r Inner Peace! Slow drops + 2x score for 15 seconds!")
        
    elseif raceName == "DRACTHYR" then
        -- Soar: Next 3 pieces are I-pieces
        addon:Ult_SetForcedPieces(3, "I")
    end
    
    addon:UpdateUI()
end

-- Update racial cooldown display
function addon:UpdateRacialCooldownDisplay()
    local f = addon.splitScreenFrame
    if not f or not f.raceCdText then return end
    
    if addon.racialCooldown > 0 then
        f.raceCdText:SetText("|cffff6600" .. math.ceil(addon.racialCooldown) .. "|r")
    else
        f.raceCdText:SetText("")
    end
end

-- Use PvP ability
function addon:UsePvPAbility()
    if not addon.mpState.inMatch then
        print("|cffff0000[Tetris]|r Not in a PvP match!")
        return
    end
    if not addon.mpState.selectedPvPAbility then
        print("|cffff0000[Tetris]|r No PvP ability selected!")
        return
    end
    if addon.mpState.pvpCooldown > 0 then
        print("|cffff6600[Tetris]|r PvP ability on cooldown: " .. math.ceil(addon.mpState.pvpCooldown) .. "s")
        return
    end
    
    local ability = addon.mpState.selectedPvPAbility
    local className = addon.selectedClass or "WARRIOR"
    local abilityIndex = 0
    
    -- Find ability index
    for i, ab in ipairs(addon.PVP_ABILITIES[className] or {}) do
        if ab.name == ability.name then
            abilityIndex = i
            break
        end
    end
    
    -- Send to opponent
    addon:SendPvPSabotage(className .. "_" .. abilityIndex)
    
    -- Track sabotage use for quests
    if addon.TrackSabotageUse then addon:TrackSabotageUse() end
    
    -- Start cooldown
    addon.mpState.pvpCooldown = addon.PVP_COOLDOWN
    
    -- Send sabotage cooldown to opponent
    addon:SendSabotageCooldown()
    
    print("|cff00ff00[Tetris]|r Used " .. ability.name .. " on " .. addon.mpState.opponent .. "!")
    addon:UpdatePvPUI()
end

-- Handle incoming sabotage
function addon:HandlePvPSabotage(sender, data)
    if not addon.mpState.inMatch or addon.mpState.opponent ~= sender then return end
    
    -- Check if this is a racial sabotage
    if data:sub(1, 7) == "RACIAL_" then
        local raceName = data:sub(8)
        addon:HandleRacialSabotage(sender, raceName)
        return
    end
    
    local className, abilityIndex = strsplit("_", data)
    abilityIndex = tonumber(abilityIndex) or 1
    
    local abilities = addon.PVP_ABILITIES[className]
    if not abilities or not abilities[abilityIndex] then return end
    
    local ability = abilities[abilityIndex]
    print("|cffff0000[Tetris]|r " .. sender .. " used " .. ability.name .. " on you!")
    
    -- Show big visual notification
    addon:ShowSabotageNotification(ability.name)
    
    -- Execute sabotage effect
    addon:ExecuteSabotage(className, abilityIndex)
end

-- Handle racial PvP sabotage
function addon:HandleRacialSabotage(sender, raceName)
    local raceData = addon.RACES[raceName]
    if not raceData then return end
    
    local ability = raceData.ability
    print("|cffff0000[Tetris]|r " .. sender .. " used racial " .. ability.name .. " on you!")
    addon:ShowSabotageNotification(ability.name)
    
    -- Execute racial sabotage effect (balanced)
    if raceName == "HUMAN" then
        -- Diplomatic Pressure: Lose 10% of current score
        addon.gameState.score = math.floor(addon.gameState.score * 0.9)
    elseif raceName == "NIGHTELF" then
        -- Shadowmeld Ambush: Hide board 5 seconds (reduced from 8)
        addon:ApplySabotageEffect("blackout", 5)
    elseif raceName == "ORC" then
        -- Blood Fury Assault: 1 garbage row + instant drop (balanced)
        addon:AddGarbageRow()
        addon:ForceInstantDrop()
    elseif raceName == "UNDEAD" then
        -- Will of the Forsaken: Disable ultimate 15 sec (reduced from 30)
        addon:ApplySabotageEffect("ultimateDisabled", 15)
    end
end

-- Show big notification when hit by sabotage
function addon:ShowSabotageNotification(abilityName)
    if not addon.mainFrame then return end
    
    -- Create notification frame if needed
    if not addon.sabotageNotification then
        local f = CreateFrame("Frame", nil, addon.mainFrame)
        f:SetSize(300, 60)
        f:SetPoint("CENTER", addon.mainFrame, "CENTER", 0, 100)
        f:SetFrameLevel(addon.mainFrame:GetFrameLevel() + 100)
        
        f.bg = f:CreateTexture(nil, "BACKGROUND")
        f.bg:SetAllPoints()
        f.bg:SetColorTexture(0.4, 0, 0, 0.8)
        
        f.text = f:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
        f.text:SetPoint("CENTER")
        
        f:Hide()
        addon.sabotageNotification = f
    end
    
    local f = addon.sabotageNotification
    f.text:SetText("|cffff0000" .. abilityName .. "!|r")
    f:Show()
    f:SetAlpha(1)
    
    -- Fade out after 1.5 seconds
    local elapsed = 0
    f:SetScript("OnUpdate", function(self, dt)
        elapsed = elapsed + dt
        if elapsed > 1.5 then
            local alpha = 1 - ((elapsed - 1.5) / 0.5)
            if alpha <= 0 then
                self:Hide()
                self:SetScript("OnUpdate", nil)
            else
                self:SetAlpha(alpha)
            end
        end
    end)
end

-- Execute sabotage effects on YOUR board
function addon:ExecuteSabotage(className, abilityIndex)
    local state = addon.gameState
    if not state or not state.isPlaying then return end
    
    -- WARRIOR sabotages
    if className == "WARRIOR" then
        if abilityIndex == 1 then -- War Cry: Add 1 garbage row
            addon:AddGarbageRows(1)
        elseif abilityIndex == 2 then -- Shattering Throw: Scatter 4 blocks
            addon:AddScatteredBlocks(4)
        elseif abilityIndex == 3 then -- Recklessness: 1 garbage row + instant drop
            addon:AddGarbageRows(1)
            addon:ForceInstantDrop()
        end
    
    -- PALADIN sabotages
    elseif className == "PALADIN" then
        if abilityIndex == 1 then -- Blinding Light: Hide preview 5 sec
            addon:HidePreview(5)
        elseif abilityIndex == 2 then -- Turn Evil: Reverse controls 5 sec
            addon:ReverseControls(5)
        elseif abilityIndex == 3 then -- Avenging Wrath: Disable ultimate 12 sec
            addon:DisableUltimate(12)
        end
    
    -- HUNTER sabotages
    elseif className == "HUNTER" then
        if abilityIndex == 1 then -- Freezing Trap: Instant drop
            addon:ForceInstantDrop()
        elseif abilityIndex == 2 then -- Scatter Shot: Scatter 4 blocks
            addon:AddScatteredBlocks(4)
        elseif abilityIndex == 3 then -- Intimidation: 1 garbage + instant drop
            addon:AddGarbageRows(1)
            addon:ForceInstantDrop()
        end
    
    -- ROGUE sabotages
    elseif className == "ROGUE" then
        if abilityIndex == 1 then -- Blind: Blackout 3 sec
            addon:BlackoutBoard(3)
        elseif abilityIndex == 2 then -- Crippling Poison: Disable hold 8 sec
            addon:DisableHold(8)
        elseif abilityIndex == 3 then -- Marked for Death: Force S/Z + instant drop
            addon:ForceBadPiece()
            addon:ForceInstantDrop()
        end
    
    -- PRIEST sabotages
    elseif className == "PRIEST" then
        if abilityIndex == 1 then -- Psychic Scream: Shuffle top 5 rows
            addon:JumbleBoard()
        elseif abilityIndex == 2 then -- Silence: Disable ultimate 10 sec
            addon:DisableUltimate(10)
        elseif abilityIndex == 3 then -- Surrender to Madness: Shuffle + 1 garbage
            addon:JumbleBoard()
            addon:AddGarbageRows(1)
        end
    
    -- DEATHKNIGHT sabotages
    elseif className == "DEATHKNIGHT" then
        if abilityIndex == 1 then -- Chains of Ice: Disable movement 3 sec
            addon:SlowMovement(3)
        elseif abilityIndex == 2 then -- Death Grip: Instant drop
            addon:ForceInstantDrop()
        elseif abilityIndex == 3 then -- Apocalypse: 1 garbage + scatter 4
            addon:AddGarbageRows(1)
            addon:AddScatteredBlocks(4)
        end
    
    -- SHAMAN sabotages
    elseif className == "SHAMAN" then
        if abilityIndex == 1 then -- Hex: Transform piece randomly
            addon:TransformCurrentPiece()
        elseif abilityIndex == 2 then -- Earthquake Totem: Scatter 4 blocks
            addon:AddScatteredBlocks(4)
        elseif abilityIndex == 3 then -- Stormkeeper: Push up 1 + scatter 4
            addon:PushBoardUp(1)
            addon:AddScatteredBlocks(4)
        end
    
    -- MAGE sabotages
    elseif className == "MAGE" then
        if abilityIndex == 1 then -- Polymorph: Turn to O piece
            addon:TransformToO()
        elseif abilityIndex == 2 then -- Frost Nova: Instant drop
            addon:ForceInstantDrop()
        elseif abilityIndex == 3 then -- Deep Freeze: Instant drop + hide preview 5 sec
            addon:ForceInstantDrop()
            addon:HidePreview(5)
        end
    
    -- WARLOCK sabotages
    elseif className == "WARLOCK" then
        if abilityIndex == 1 then -- Fear: Reverse controls 4 sec
            addon:ReverseControls(4)
        elseif abilityIndex == 2 then -- Shadowfury: 1 garbage row
            addon:AddGarbageRows(1)
        elseif abilityIndex == 3 then -- Summon Infernal: 2 garbage rows
            addon:AddGarbageRows(2)
        end
    
    -- DRUID sabotages
    elseif className == "DRUID" then
        if abilityIndex == 1 then -- Entangling Roots: Disable rotation 4 sec
            addon:DisableRotation(4)
        elseif abilityIndex == 2 then -- Cyclone: Spin piece for 3 sec
            addon:SpinPiece(3)
        elseif abilityIndex == 3 then -- Incarnation: 1 garbage + disable rotation 5 sec
            addon:AddGarbageRows(1)
            addon:DisableRotation(5)
        end
    
    -- MONK sabotages
    elseif className == "MONK" then
        if abilityIndex == 1 then -- Paralysis: Instant drop
            addon:ForceInstantDrop()
        elseif abilityIndex == 2 then -- Leg Sweep: Scatter 4 blocks
            addon:AddScatteredBlocks(4)
        elseif abilityIndex == 3 then -- Touch of Karma: Reflect next sabotage
            addon:ApplySabotageEffect("karmaReflect", 15)
        end
    
    -- DEMONHUNTER sabotages
    elseif className == "DEMONHUNTER" then
        if abilityIndex == 1 then -- Imprison: Blackout 3 sec
            addon:BlackoutBoard(3)
        elseif abilityIndex == 2 then -- Chaos Nova: Scatter 4 blocks
            addon:AddScatteredBlocks(4)
        elseif abilityIndex == 3 then -- Metamorphosis: 1 garbage + reverse 4 sec
            addon:AddGarbageRows(1)
            addon:ReverseControls(4)
        end
    
    -- EVOKER sabotages
    elseif className == "EVOKER" then
        if abilityIndex == 1 then -- Landslide: Push up 1 row
            addon:PushBoardUp(1)
        elseif abilityIndex == 2 then -- Oppressing Roar: Disable ultimate 8 sec
            addon:DisableUltimate(8)
        elseif abilityIndex == 3 then -- Deep Breath: 2 garbage rows
            addon:AddGarbageRows(2)
        end
    end
end

-- ============================================================
-- SABOTAGE EFFECT IMPLEMENTATIONS
-- ============================================================

-- Add garbage rows at the bottom
function addon:AddGarbageRows(count)
    local state = addon.gameState
    
    -- Shift everything up
    for i = 1, count do
        for y = 1, addon.BOARD_HEIGHT - 1 do
            state.board[y] = state.board[y + 1]
        end
        -- Create garbage row with one gap
        state.board[addon.BOARD_HEIGHT] = {}
        local gap = math.random(1, addon.BOARD_WIDTH)
        for x = 1, addon.BOARD_WIDTH do
            if x ~= gap then
                state.board[addon.BOARD_HEIGHT][x] = {type = "G", texture = "Interface\\Icons\\INV_Stone_05"}
            end
        end
    end
    print("|cffff6600[Tetris]|r " .. count .. " garbage rows added!")
end

-- Scramble next pieces
function addon:ScrambleNextPieces(count)
    local state = addon.gameState
    local types = {"I", "O", "T", "L", "J", "S", "Z"}
    for i = 1, math.min(count, #state.nextPieces) do
        state.nextPieces[i] = types[math.random(#types)]
    end
    print("|cffff6600[Tetris]|r Next pieces scrambled!")
end

-- Add scattered blocks
function addon:AddScatteredBlocks(count)
    local state = addon.gameState
    local added = 0
    local attempts = 0
    while added < count and attempts < 100 do
        local x = math.random(1, addon.BOARD_WIDTH)
        local y = math.random(math.floor(addon.BOARD_HEIGHT/2), addon.BOARD_HEIGHT)
        if not state.board[y] then state.board[y] = {} end
        if not state.board[y][x] then
            state.board[y][x] = {type = "G", texture = "Interface\\Icons\\INV_Stone_05"}
            added = added + 1
        end
        attempts = attempts + 1
    end
    print("|cffff6600[Tetris]|r " .. added .. " blocks scattered!")
end

-- ============================================================
-- UNIFIED SABOTAGE EFFECT HANDLER
-- Routes effect names to specific functions
-- ============================================================
function addon:ApplySabotageEffect(effectName, duration)
    duration = duration or 5  -- Default 5 seconds
    
    if effectName == "blackout" then
        addon:BlackoutBoard(duration)
    elseif effectName == "hidePreview" then
        addon:HidePreview(duration)
    elseif effectName == "reverseControls" then
        addon:ReverseControls(duration)
    elseif effectName == "freeze" or effectName == "frozen" then
        addon:FreezePiece(duration)
    elseif effectName == "disableRotation" then
        addon:DisableRotation(duration)
    elseif effectName == "disableHold" then
        addon:DisableHold(duration)
    elseif effectName == "ultimateDisabled" then
        addon:DisableUltimate(duration)
    elseif effectName == "hidePiece" then
        addon:HideCurrentPiece(duration)
    elseif effectName == "slowMovement" then
        addon:SlowMovement(duration)
    elseif effectName == "speedUp" then
        addon:SpeedUp(1.5, duration)
    else
        -- Unknown effect - just set the flag directly
        addon.pvpEffects = addon.pvpEffects or {}
        addon.pvpEffects[effectName] = true
        C_Timer.After(duration, function()
            if addon.pvpEffects then addon.pvpEffects[effectName] = false end
        end)
    end
end

-- Disable rotation
function addon:DisableRotation(duration)
    addon.pvpEffects = addon.pvpEffects or {}
    addon.pvpEffects.rotationDisabled = true
    C_Timer.After(duration, function()
        if addon.pvpEffects then addon.pvpEffects.rotationDisabled = false end
        print("|cff00ff00[Tetris]|r Rotation enabled again!")
    end)
    print("|cffff6600[Tetris]|r Rotation DISABLED for " .. duration .. "s!")
end

-- Hide preview
function addon:HidePreview(duration)
    addon.pvpEffects = addon.pvpEffects or {}
    addon.pvpEffects.hidePreview = true
    addon:UpdateUI()  -- Force immediate update
    C_Timer.After(duration, function()
        if addon.pvpEffects then addon.pvpEffects.hidePreview = false end
        addon:UpdateUI()  -- Force update when effect ends
    end)
    print("|cffff6600[Tetris]|r Preview hidden for " .. duration .. "s!")
end

-- Reverse controls
function addon:ReverseControls(duration)
    addon.pvpEffects = addon.pvpEffects or {}
    addon.pvpEffects.reversedControls = true
    C_Timer.After(duration, function()
        if addon.pvpEffects then addon.pvpEffects.reversedControls = false end
        print("|cff00ff00[Tetris]|r Controls back to normal!")
    end)
    print("|cffff6600[Tetris]|r Controls REVERSED for " .. duration .. "s!")
end

-- Freeze piece
function addon:FreezePiece(duration)
    addon.pvpEffects = addon.pvpEffects or {}
    addon.pvpEffects.frozen = true
    C_Timer.After(duration, function()
        if addon.pvpEffects then addon.pvpEffects.frozen = false end
        print("|cff00ff00[Tetris]|r Unfrozen!")
    end)
    print("|cffff6600[Tetris]|r FROZEN for " .. duration .. "s!")
end

-- Speed up
function addon:SpeedUp(multiplier, duration)
    addon.pvpEffects = addon.pvpEffects or {}
    addon.pvpEffects.speedMultiplier = multiplier
    C_Timer.After(duration, function()
        if addon.pvpEffects then addon.pvpEffects.speedMultiplier = nil end
        print("|cff00ff00[Tetris]|r Speed back to normal!")
    end)
    print("|cffff6600[Tetris]|r Speed increased " .. multiplier .. "x for " .. duration .. "s!")
end

-- Blackout board
function addon:BlackoutBoard(duration)
    addon.pvpEffects = addon.pvpEffects or {}
    addon.pvpEffects.blackout = true
    C_Timer.After(duration, function()
        if addon.pvpEffects then addon.pvpEffects.blackout = false end
        addon:UpdateUI()
        print("|cff00ff00[Tetris]|r Blackout ended!")
    end)
    print("|cffff6600[Tetris]|r BLACKOUT for " .. duration .. "s!")
end

-- Hide current piece
function addon:HideCurrentPiece(duration)
    addon.pvpEffects = addon.pvpEffects or {}
    addon.pvpEffects.hidePiece = true
    C_Timer.After(duration, function()
        if addon.pvpEffects then addon.pvpEffects.hidePiece = false end
        print("|cff00ff00[Tetris]|r Piece visible again!")
    end)
    print("|cffff6600[Tetris]|r Current piece HIDDEN for " .. duration .. "s!")
end

-- Disable hold
function addon:DisableHold(duration)
    addon.pvpEffects = addon.pvpEffects or {}
    addon.pvpEffects.holdDisabled = true
    C_Timer.After(duration, function()
        if addon.pvpEffects then addon.pvpEffects.holdDisabled = false end
        print("|cff00ff00[Tetris]|r Hold enabled again!")
    end)
    print("|cffff6600[Tetris]|r Hold DISABLED for " .. duration .. "s!")
end

-- Jumble/shuffle board
function addon:JumbleBoard()
    local state = addon.gameState
    local allBlocks = {}
    
    -- Collect all blocks
    for y = 1, addon.BOARD_HEIGHT do
        for x = 1, addon.BOARD_WIDTH do
            if state.board[y] and state.board[y][x] then
                table.insert(allBlocks, state.board[y][x])
                state.board[y][x] = nil
            end
        end
    end
    
    -- Randomly place them back
    for _, block in ipairs(allBlocks) do
        local placed = false
        local attempts = 0
        while not placed and attempts < 100 do
            local x = math.random(1, addon.BOARD_WIDTH)
            local y = math.random(1, addon.BOARD_HEIGHT)
            if not state.board[y] then state.board[y] = {} end
            if not state.board[y][x] then
                state.board[y][x] = block
                placed = true
            end
            attempts = attempts + 1
        end
    end
    
    -- Apply gravity
    addon:ApplyGravity()
    print("|cffff6600[Tetris]|r Board JUMBLED!")
end

-- Force bad piece (S or Z)
function addon:ForceBadPiece()
    local state = addon.gameState
    local badPieces = {"S", "Z"}
    if state.nextPieces and #state.nextPieces > 0 then
        state.nextPieces[1] = badPieces[math.random(#badPieces)]
    end
    print("|cffff6600[Tetris]|r Next piece is now S or Z!")
end

-- Disable ultimate
function addon:DisableUltimate(duration)
    addon.pvpEffects = addon.pvpEffects or {}
    addon.pvpEffects.ultimateDisabled = true
    C_Timer.After(duration, function()
        if addon.pvpEffects then addon.pvpEffects.ultimateDisabled = false end
        print("|cff00ff00[Tetris]|r Ultimate enabled again!")
    end)
    print("|cffff6600[Tetris]|r Ultimate DISABLED for " .. duration .. "s!")
end

-- Slow movement
function addon:SlowMovement(duration)
    addon.pvpEffects = addon.pvpEffects or {}
    addon.pvpEffects.slowMovement = true
    C_Timer.After(duration, function()
        if addon.pvpEffects then addon.pvpEffects.slowMovement = false end
        print("|cff00ff00[Tetris]|r Movement back to normal!")
    end)
    print("|cffff6600[Tetris]|r Movement SLOWED for " .. duration .. "s!")
end

-- Force instant drop
function addon:ForceInstantDrop()
    if addon.HardDrop then
        addon:HardDrop()
        print("|cffff6600[Tetris]|r Piece forced down!")
    end
end

-- Transform current piece randomly
function addon:TransformCurrentPiece()
    local state = addon.gameState
    if state.currentPiece then
        local types = {"I", "O", "T", "L", "J", "S", "Z"}
        state.currentPiece.type = types[math.random(#types)]
        state.currentPiece.rotation = 0
        print("|cffff6600[Tetris]|r Piece transformed!")
    end
end

-- Transform to O piece
function addon:TransformToO()
    local state = addon.gameState
    if state.currentPiece then
        state.currentPiece.type = "O"
        state.currentPiece.rotation = 0
        print("|cffff6600[Tetris]|r Piece turned into a square!")
    end
end

-- Push board up
function addon:PushBoardUp(rows)
    local state = addon.gameState
    
    -- Move everything up
    for y = 1, addon.BOARD_HEIGHT - rows do
        state.board[y] = state.board[y + rows]
    end
    
    -- Add empty rows at bottom
    for y = addon.BOARD_HEIGHT - rows + 1, addon.BOARD_HEIGHT do
        state.board[y] = {}
    end
    
    print("|cffff6600[Tetris]|r Board pushed UP by " .. rows .. " rows!")
end

-- Screen shake effect
function addon:ScreenShake(duration)
    addon.pvpEffects = addon.pvpEffects or {}
    addon.pvpEffects.shaking = true
    
    local shakeFrame = addon.mainFrame
    if not shakeFrame then return end
    
    local originalPoint = {shakeFrame:GetPoint()}
    local elapsed = 0
    
    local shaker = CreateFrame("Frame")
    shaker:SetScript("OnUpdate", function(self, dt)
        elapsed = elapsed + dt
        if elapsed >= duration then
            shakeFrame:ClearAllPoints()
            shakeFrame:SetPoint(unpack(originalPoint))
            addon.pvpEffects.shaking = false
            self:SetScript("OnUpdate", nil)
        else
            local offsetX = math.random(-5, 5)
            local offsetY = math.random(-5, 5)
            shakeFrame:ClearAllPoints()
            shakeFrame:SetPoint(originalPoint[1], originalPoint[2], originalPoint[3], 
                (originalPoint[4] or 0) + offsetX, (originalPoint[5] or 0) + offsetY)
        end
    end)
    
    print("|cffff6600[Tetris]|r EARTHQUAKE!")
end

-- Spin piece randomly
function addon:SpinPiece()
    local state = addon.gameState
    if state.currentPiece then
        state.currentPiece.rotation = math.random(0, 3)
        print("|cffff6600[Tetris]|r Piece spun randomly!")
    end
end

-- Slow garbage (add 1 row every X seconds)
function addon:SlowGarbage(interval, duration)
    local count = math.floor(duration / interval)
    for i = 1, count do
        C_Timer.After(i * interval, function()
            if addon.gameState and addon.gameState.isPlaying and addon.mpState.inMatch then
                addon:AddGarbageRows(1)
            end
        end)
    end
    print("|cffff6600[Tetris]|r Vines growing for " .. duration .. "s!")
end

-- Update PvP cooldown
function addon:UpdatePvPCooldown(elapsed)
    if addon.mpState.pvpCooldown > 0 then
        addon.mpState.pvpCooldown = addon.mpState.pvpCooldown - elapsed
        if addon.mpState.pvpCooldown < 0 then
            addon.mpState.pvpCooldown = 0
        end
    end
    
    -- Update racial cooldown
    if addon.racialCooldown > 0 then
        addon.racialCooldown = addon.racialCooldown - elapsed
        if addon.racialCooldown < 0 then
            addon.racialCooldown = 0
        end
        addon:UpdateRacialCooldownDisplay()
    end
end

-- Update PvP UI (cooldown display)
function addon:UpdatePvPUI()
    -- Will be called to refresh PvP button state
end

-- Show PvP ability selector
function addon:ShowPvPAbilitySelector()
    -- Don't show if ability is already locked
    if addon.mpState.pvpAbilityLocked and addon.mpState.selectedPvPAbility then
        print("|cffff6600[Tetris]|r PvP ability already locked for this match!")
        return
    end
    
    local className = addon.selectedClass or "WARRIOR"
    local classData = addon.CLASSES[className]
    
    if not addon.pvpAbilityFrame then
        local f = CreateFrame("Frame", "WoWTetrisPvPSelect", UIParent, "BackdropTemplate")
        f:SetSize(320, 240)
        f:SetPoint("CENTER", UIParent, "CENTER", 0, 50)
        f:SetBackdrop({
            bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
            edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border",
            tile = true, tileSize = 32, edgeSize = 24,
            insets = {left=6, right=6, top=6, bottom=6}
        })
        f:SetFrameStrata("DIALOG")
        f:SetFrameLevel(200)
        
        -- Close button
        local closeBtn = CreateFrame("Button", nil, f, "UIPanelCloseButton")
        closeBtn:SetPoint("TOPRIGHT", -2, -2)
        
        f.title = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        f.title:SetPoint("TOP", 0, -15)
        
        f.buttons = {}
        addon.pvpAbilityFrame = f
    end
    
    local f = addon.pvpAbilityFrame
    local abilities = addon.PVP_ABILITIES[className] or addon.PVP_ABILITIES["WARRIOR"]
    
    -- Update title with class name
    local classColor = classData and classData.colorCode or "|cffffffff"
    f.title:SetText(classColor .. (classData and classData.name or className) .. "|r PvP Sabotage:")
    
    -- Clear old buttons
    for _, btn in pairs(f.buttons) do btn:Hide() end
    
    for i, ability in ipairs(abilities) do
        local btn = f.buttons[i]
        if not btn then
            btn = CreateFrame("Button", nil, f, "BackdropTemplate")
            btn:SetSize(290, 55)
            btn:SetBackdrop({
                bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
                edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
                tile = true, tileSize = 16, edgeSize = 10,
                insets = {left=2, right=2, top=2, bottom=2}
            })
            btn:SetBackdropColor(0.1, 0.1, 0.15, 0.8)
            
            btn.icon = btn:CreateTexture(nil, "ARTWORK")
            btn.icon:SetSize(45, 45)
            btn.icon:SetPoint("LEFT", 5, 0)
            btn.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
            
            btn.name = btn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            btn.name:SetPoint("TOPLEFT", btn.icon, "TOPRIGHT", 8, -5)
            
            btn.desc = btn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
            btn.desc:SetPoint("TOPLEFT", btn.name, "BOTTOMLEFT", 0, -3)
            btn.desc:SetWidth(220)
            btn.desc:SetTextColor(0.8, 0.8, 0.8)
            
            f.buttons[i] = btn
        end
        
        btn:SetPoint("TOP", f, "TOP", 0, -45 - (i-1)*60)
        btn.icon:SetTexture(ability.icon)
        btn.name:SetText("|cffff6600" .. ability.name .. "|r")
        btn.desc:SetText(ability.description)
        btn.desc:SetJustifyH("LEFT")
        
        btn:SetScript("OnClick", function()
            addon.mpState.selectedPvPAbility = ability
            addon.mpState.pvpAbilityLocked = true  -- Lock the choice
            f:Hide()
            addon:UpdatePvPAbilityDisplay()
            print("|cff00ff00[Tetris]|r Selected: " .. ability.name .. " (locked for this match)")
        end)
        
        btn:SetScript("OnEnter", function(self)
            self:SetBackdropColor(0.2, 0.2, 0.3, 0.9)
        end)
        btn:SetScript("OnLeave", function(self)
            self:SetBackdropColor(0.1, 0.1, 0.15, 0.8)
        end)
        
        btn:Show()
    end
    
    f:Show()
end
