local addonName, ns = ...

-- ============================================================
-- Constants & Addon Prefix
-- ============================================================
local PREFIX = "BBIGAMBLE"
local MUSIC_FILE = "Interface\\AddOns\\BrosBeforeIOsGambling\\MUS_1110_Drive_6684200.mp3"
C_ChatInfo.RegisterAddonMessagePrefix(PREFIX)

-- ============================================================
-- State
-- ============================================================
local Players = {}           -- { {name, hasRolled}, ... }
local Rolls = {}             -- { {name, value}, ... }
local Channel = "RAID"
local ChannelIndex = 2
local CurrentRollValue = 1000
local Locked = false
local GameActive = false
local TestMode = false
local Me

local CHANNELS = {"PARTY", "RAID", "GUILD"}
local CHANNEL_LABELS = {
    PARTY = format("|cffaaaaff%s|r", "Party"),
    RAID  = format("|cffff8000%s|r", "Raid"),
    GUILD = format("|cff40ff40%s|r", "Guild"),
}
local ROLL_PATTERN = "^(%S+)%s%S+%s(%d+)%s%((%d+)-(%d+)%)"
local CHAT_EVENTS = {
    PARTY = {"CHAT_MSG_PARTY", "CHAT_MSG_PARTY_LEADER"},
    RAID  = {"CHAT_MSG_RAID", "CHAT_MSG_RAID_LEADER"},
    GUILD = {"CHAT_MSG_GUILD"},
}

-- Forward declarations (assigned during UI creation / chat integration)
local MainFrame, MessageLog
local btnNewGame, btnChannel, btnEnterSelf, btnLastCall
local editRollValue, btnSelfRoll, btnRoll, btnStats
local btnResetGame, btnResetStats
local presetBtns = {}
local RegisterChatEvents, UnregisterChatEvents

-- ============================================================
-- Utilities
-- ============================================================

local function GetBaseName(name)
    if not name then return "Unknown" end
    return (strsplit("-", name))
end

local function Comma(number)
    if not number then return "0" end
    if type(number) ~= "number" then number = tonumber(number) end
    if not number then return "0" end
    local s = format("%.0f", math.floor(number + 0.5))
    local l, m, r = string.match(s, "^([^%d]*%d)(%d+)(.-)$")
    if l then
        return l .. string.reverse(string.gsub(string.reverse(m), "(%d%d%d)", "%1,")) .. r
    end
    return s
end

local function IsLeader()
    if TestMode then return true end
    if not IsInGroup() then return true end
    return UnitIsGroupLeader("player")
end

local function SendMsg(msg)
    if TestMode then return end
    local chan = Channel
    if chan == "RAID" and not IsInRaid() then
        chan = IsInGroup() and "PARTY" or "GUILD"
    elseif chan == "PARTY" and not IsInGroup() then
        chan = "GUILD"
    end
    C_ChatInfo.SendAddonMessage(PREFIX, msg, chan)
end

local function FindPlayer(name)
    for i = 1, #Players do
        if Players[i][1] == name then return i end
    end
end

-- ============================================================
-- Message Log Helpers
-- ============================================================

local function Log(text, r, g, b)
    if MessageLog then MessageLog:AddMessage(text, r or 1, g or 1, b or 1) end
end

local function LogSystem(t) Log(t, 1.0, 0.82, 0.0)  end -- gold
local function LogGood(t)   Log(t, 0.1, 1.0,  0.1)  end -- green
local function LogBad(t)    Log(t, 1.0, 0.1,  0.1)  end -- red
local function LogInfo(t)   Log(t, 0.82, 0.82, 0.82) end -- light grey
local function LogAlert(t)  Log(t, 1.0, 0.5,  0.0)  end -- orange

-- ============================================================
-- State Helpers
-- ============================================================

local function ResetGameState()
    wipe(Rolls)
    wipe(Players)
    Locked = false
    GameActive = false
    StopMusic()
    if UnregisterChatEvents then UnregisterChatEvents() end
end

local function UpdateChannelLabel()
    if btnChannel then btnChannel:SetText(CHANNEL_LABELS[Channel] or Channel) end
end

local function UpdateButtons()
    if not MainFrame or not Me then return end
    local leader = IsLeader()

    if leader and not GameActive then btnNewGame:Enable()   else btnNewGame:Disable()   end
    if leader and not GameActive then btnChannel:Enable()   else btnChannel:Disable()   end
    if leader and not GameActive then editRollValue:Enable() else editRollValue:Disable() end

    if leader and GameActive and not Locked then btnLastCall:Enable() else btnLastCall:Disable() end
    if leader and GameActive then btnRoll:Enable()       else btnRoll:Disable()       end
    if leader and GameActive then btnResetGame:Enable()  else btnResetGame:Disable()  end

    if GameActive and not Locked then
        btnEnterSelf:Enable()
        if FindPlayer(Me) then
            btnEnterSelf:SetText("Leave Game")
        else
            btnEnterSelf:SetText("Enter Self")
        end
    else
        btnEnterSelf:Disable()
        btnEnterSelf:SetText("Enter Self")
    end

    local idx = FindPlayer(Me)
    if GameActive and Locked and idx and not Players[idx][2] then
        btnSelfRoll:Enable()
    else
        btnSelfRoll:Disable()
    end

    btnStats:Enable()
    if leader then btnResetStats:Enable() else btnResetStats:Disable() end

    for _, btn in ipairs(presetBtns) do
        if not GameActive then btn:Enable() else btn:Disable() end
    end
end

-- ============================================================
-- Stats
-- ============================================================

local function UpdateStats(winName, loseName, diff)
    if not BBIGStats then BBIGStats = {All = {}, Specific = {}} end
    if not BBIGStats.All then BBIGStats.All = {} end
    if not BBIGStats.Specific then BBIGStats.Specific = {} end

    BBIGStats.All[winName]  = (BBIGStats.All[winName] or 0)  + diff
    BBIGStats.All[loseName] = (BBIGStats.All[loseName] or 0) - diff

    if not BBIGStats.Specific[winName]  then BBIGStats.Specific[winName]  = {} end
    if not BBIGStats.Specific[loseName] then BBIGStats.Specific[loseName] = {} end
    BBIGStats.Specific[winName][loseName]  = (BBIGStats.Specific[winName][loseName] or 0)  + diff
    BBIGStats.Specific[loseName][winName]  = (BBIGStats.Specific[loseName][winName] or 0) - diff
end

local function PostStats(player)
    if not BBIGStats or (not BBIGStats.All and not BBIGStats.Specific) then
        LogSystem("No stats recorded yet.")
        return
    end

    if player then
        if BBIGStats.Specific and BBIGStats.Specific[player] and next(BBIGStats.Specific[player]) then
            local temp = {}
            for k, v in pairs(BBIGStats.Specific[player]) do tinsert(temp, {k, v}) end
            table.sort(temp, function(a, b) return a[2] > b[2] end)

            LogSystem(format("Specific stats for %s:", player))
            for i = 1, #temp do
                if temp[i][2] > 0 then
                    LogInfo(format("  %s owes %s %sg", temp[i][1], player, Comma(temp[i][2])))
                else
                    LogInfo(format("  %s owes %s %sg", player, temp[i][1], Comma(math.abs(temp[i][2]))))
                end
            end
        else
            LogSystem(format("No stats for %s.", player))
        end
    else
        if not BBIGStats.All or not next(BBIGStats.All) then
            LogSystem("No stats recorded yet.")
            return
        end
        local temp = {}
        for k, v in pairs(BBIGStats.All) do tinsert(temp, {k, v}) end
        table.sort(temp, function(a, b) return a[2] > b[2] end)

        LogSystem("--- Session Stats ---")
        for i = 1, #temp do
            local sign = temp[i][2] >= 0 and "+" or ""
            LogInfo(format("  %d. %s: %s%s", i, temp[i][1], sign, Comma(temp[i][2])))
        end
    end
end

-- ============================================================
-- Core Game Logic
-- ============================================================

local function SortRolls()
    table.sort(Rolls, function(a, b) return a[2] > b[2] end)

    local winner = Rolls[1]
    local loser  = Rolls[#Rolls]
    local diff   = winner[2] - loser[2]

    UpdateStats(winner[1], loser[1], diff)

    LogAlert(format("%s owes %s %sg!", loser[1], winner[1], Comma(diff)))

    if Me == winner[1] then
        RaidNotice_AddMessage(RaidWarningFrame,
            format("You WON! %s owes you %sg!", loser[1], Comma(diff)),
            {r = 0.1, g = 1.0, b = 0.1})
    elseif Me == loser[1] then
        RaidNotice_AddMessage(RaidWarningFrame,
            format("You LOST! You owe %s %sg!", winner[1], Comma(diff)),
            {r = 1.0, g = 0.1, b = 0.1})
    end

    SendMsg(format("RESULT:%s:%d:%s:%d:%d", winner[1], winner[2], loser[1], loser[2], diff))

    ResetGameState()
    UpdateButtons()
end

local function StillNeedToRoll()
    local names = {}
    for i = 1, #Players do
        if not Players[i][2] then tinsert(names, Players[i][1]) end
    end
    return names
end

-- ============================================================
-- Test Mode Bot Simulation
-- ============================================================

local TEST_BOTS = {"OctoBro", "GoldGoblin", "LuckyFin"}

local function SimulateBotRolls()
    if not TestMode or not GameActive or not Locked then return end
    for i = 1, #Players do
        if Players[i][1] ~= Me and not Players[i][2] then
            Players[i][2] = true
            local roll = math.random(1, CurrentRollValue)
            tinsert(Rolls, {Players[i][1], roll})
            LogInfo(format("%s rolled %d (1-%s)", Players[i][1], roll, Comma(CurrentRollValue)))
        end
    end
    UpdateButtons()
    if #Rolls == #Players then
        SortRolls()
    end
end

-- ============================================================
-- Button Click Handlers
-- ============================================================

local function OnNewGameClick()
    if not IsLeader() or GameActive then return end

    local val = editRollValue:GetText():gsub(",", ""):gsub("%D", "")
    CurrentRollValue = tonumber(val) or 1000
    editRollValue:SetText(Comma(CurrentRollValue))

    ResetGameState()
    GameActive = true
    PlayMusic(MUSIC_FILE)

    RegisterChatEvents()
    SendMsg("NEW_GAME:" .. CurrentRollValue)
    LogSystem(format("New game started! Roll value: %sg.", Comma(CurrentRollValue)))

    if TestMode then
        tinsert(Players, {Me})
        for _, bot in ipairs(TEST_BOTS) do
            tinsert(Players, {bot})
            LogInfo(format("%s has entered the game.", bot))
        end
        LogSystem("Test mode: you and 3 bots are in. Click 'Roll' to lock, then 'Self Roll'.")
    else
        LogSystem("Click 'Enter Self' to join, or type 1 in chat.")
    end

    UpdateButtons()
end

local function OnLastCallClick()
    if not IsLeader() or not GameActive or Locked then return end
    PlaySound(5964, "SFX")
    SendMsg("LAST_CALL")
    LogAlert("Last call to enter!")
end

local function OnRollClick()
    if not IsLeader() or not GameActive then return end

    if Locked then
        local still = StillNeedToRoll()
        if #still > 0 then
            local list = table.concat(still, ", ")
            SendMsg("STILL:" .. table.concat(still, ","))
            LogAlert("Still need to roll: " .. list)
        else
            LogInfo("All rolls are in. Processing...")
        end
    else
        if #Players < 2 then
            LogBad("Not enough players to start rolling!")
            return
        end
        Locked = true
        SendMsg("CLOSE:" .. CurrentRollValue)
        LogSystem(format("Game is closed! /roll %s now!", Comma(CurrentRollValue)))
        UpdateButtons()
        if TestMode then
            C_Timer.After(0.5, SimulateBotRolls)
        end
    end
end

local function OnEnterSelfClick()
    if not GameActive or Locked then return end
    if FindPlayer(Me) then
        SendMsg("QUIT")
    else
        SendMsg("JOIN")
    end
end

local function OnSelfRollClick()
    if not GameActive or not Locked then return end
    local idx = FindPlayer(Me)
    if not idx or Players[idx][2] then return end
    PlaySound(36629, "SFX")
    RandomRoll(1, CurrentRollValue)
end

local function OnResetGameClick()
    if not IsLeader() or not GameActive then return end
    ResetGameState()
    SendMsg("GAME_RESET")
    LogSystem("Game has been reset.")
    UpdateButtons()
end

local function OnStatsClick()
    PostStats()
end

local function OnResetStatsClick()
    if not IsLeader() then return end
    BBIGStats = {All = {}, Specific = {}}
    SendMsg("STATS_RESET")
    LogSystem("All stats have been reset.")
end

local function OnChannelClick()
    if GameActive then return end
    ChannelIndex = ChannelIndex + 1
    if ChannelIndex > #CHANNELS then ChannelIndex = 1 end
    Channel = CHANNELS[ChannelIndex]
    UpdateChannelLabel()
end

-- ============================================================
-- Addon Message Handler
-- ============================================================

local function OnAddonMessage(prefix, msg, dist, sender)
    if prefix ~= PREFIX then return end
    local senderBase = GetBaseName(sender)
    local cmd, a1, a2, a3, a4, a5 = strsplit(":", msg)

    -- ---- Messages broadcast by the leader ----

    if cmd == "NEW_GAME" then
        if senderBase == Me then return end
        local rollVal = tonumber(a1)
        if rollVal then
            ResetGameState()
            CurrentRollValue = rollVal
            GameActive = true
            PlayMusic(MUSIC_FILE)
            Channel = dist
            for i, ch in ipairs(CHANNELS) do
                if ch == dist then ChannelIndex = i; break end
            end
            UpdateChannelLabel()
            editRollValue:SetText(Comma(CurrentRollValue))
            LogSystem(format("New game started by %s! Roll value: %sg.", senderBase, Comma(CurrentRollValue)))
            LogSystem("Click 'Enter Self' to join.")
            UpdateButtons()
        end

    elseif cmd == "LAST_CALL" then
        if senderBase == Me then return end
        LogAlert("Last call to enter!")

    elseif cmd == "CLOSE" then
        if senderBase == Me then return end
        Locked = true
        local rollVal = tonumber(a1)
        if rollVal then CurrentRollValue = rollVal end
        LogSystem(format("Game is closed! /roll %s now!", Comma(CurrentRollValue)))
        UpdateButtons()

    elseif cmd == "ENTERED" then
        if senderBase == Me then return end
        local playerName = a1
        if playerName and not FindPlayer(playerName) then
            tinsert(Players, {playerName})
            LogInfo(format("%s has entered the game.", playerName))
            UpdateButtons()
        end

    elseif cmd == "LEFT" then
        if senderBase == Me then return end
        local playerName = a1
        local idx = FindPlayer(playerName)
        if idx then
            tremove(Players, idx)
            LogInfo(format("%s has left the game.", playerName))
            UpdateButtons()
        end

    elseif cmd == "STILL" then
        if senderBase == Me then return end
        if a1 and a1 ~= "" then
            LogAlert("Still need to roll: " .. a1:gsub(",", ", "))
        end

    elseif cmd == "RESULT" then
        if senderBase == Me then return end
        local winName  = a1
        local winRoll  = tonumber(a2)
        local loseName = a3
        local loseRoll = tonumber(a4)
        local diff     = tonumber(a5)
        if winName and loseName and diff then
            UpdateStats(winName, loseName, diff)
            LogAlert(format("%s owes %s %sg!", loseName, winName, Comma(diff)))

            if Me == winName then
                RaidNotice_AddMessage(RaidWarningFrame,
                    format("You WON! %s owes you %sg!", loseName, Comma(diff)),
                    {r = 0.1, g = 1.0, b = 0.1})
            elseif Me == loseName then
                RaidNotice_AddMessage(RaidWarningFrame,
                    format("You LOST! You owe %s %sg!", winName, Comma(diff)),
                    {r = 1.0, g = 0.1, b = 0.1})
            end

            ResetGameState()
            UpdateButtons()
        end

    elseif cmd == "GAME_RESET" then
        if senderBase == Me then return end
        ResetGameState()
        LogSystem("Game has been reset by the leader.")
        UpdateButtons()

    elseif cmd == "STATS_RESET" then
        if senderBase == Me then return end
        BBIGStats = {All = {}, Specific = {}}
        LogSystem("Stats have been reset by the leader.")

    -- ---- Messages from players → processed by leader only ----

    elseif cmd == "JOIN" then
        if not IsLeader() then return end
        if not GameActive or Locked then return end

        if not FindPlayer(senderBase) then
            tinsert(Players, {senderBase})
            SendMsg("ENTERED:" .. senderBase)
            LogInfo(format("%s has entered the game.", senderBase))
            UpdateButtons()
        end

    elseif cmd == "QUIT" then
        if not IsLeader() then return end
        local idx = FindPlayer(senderBase)
        if idx then
            tremove(Players, idx)
            SendMsg("LEFT:" .. senderBase)
            LogInfo(format("%s has left the game.", senderBase))
            UpdateButtons()
        end
    end
end

-- ============================================================
-- System Roll Detection (all clients track, leader resolves)
-- ============================================================

local function OnSystemMessage(msg)
    if not GameActive or not Locked then return end

    local name, roll, minR, maxR = string.match(msg, ROLL_PATTERN)
    if not name then return end
    if tonumber(minR) ~= 1 or tonumber(maxR) ~= CurrentRollValue then return end

    local baseName = GetBaseName(name)
    local idx = FindPlayer(baseName)
    if not idx or Players[idx][2] then return end

    Players[idx][2] = true
    tinsert(Rolls, {baseName, tonumber(roll)})
    LogInfo(format("%s rolled %d (%d-%s)", baseName, tonumber(roll), 1, Comma(CurrentRollValue)))

    if IsLeader() and #Rolls == #Players then
        SortRolls()
    else
        UpdateButtons()
    end
end

-- ============================================================
-- UI: Style Helpers
-- ============================================================

local FLAT = "Interface\\Buttons\\WHITE8x8"

local function MakeSep(parent, y)
    local t = parent:CreateTexture(nil, "ARTWORK")
    t:SetHeight(1)
    t:SetPoint("LEFT", 8, 0)
    t:SetPoint("RIGHT", -8, 0)
    t:SetPoint("TOP", 0, y)
    t:SetColorTexture(0.55, 0.10, 0.10, 0.35)
    return t
end

local function StyledBtn(parent, w, h, gold)
    local btn = CreateFrame("Button", nil, parent, "BackdropTemplate")
    btn:SetSize(w, h)
    btn:RegisterForClicks("LeftButtonUp")
    btn:SetBackdrop({bgFile = FLAT, edgeFile = FLAT, edgeSize = 1})

    local nBg  = gold and {0.16, 0.14, 0.06, 0.95} or {0.13, 0.13, 0.18, 0.95}
    local nBdr = gold and {0.60, 0.50, 0.10, 0.80} or {0.40, 0.10, 0.10, 0.75}
    local hBg  = gold and {0.24, 0.20, 0.06, 0.95} or {0.24, 0.10, 0.10, 0.95}
    local hBdr = gold and {1.00, 0.82, 0.20, 1.00} or {0.90, 0.20, 0.15, 1.00}

    btn:SetBackdropColor(unpack(nBg))
    btn:SetBackdropBorderColor(unpack(nBdr))

    btn.label = btn:CreateFontString(nil, "OVERLAY")
    btn.label:SetFont(STANDARD_TEXT_FONT, 11, "OUTLINE")
    btn.label:SetPoint("CENTER")
    btn.label:SetTextColor(1, 0.85, 0.55)

    btn._on = true

    local function Sync(s)
        if s._on then
            s:SetBackdropColor(unpack(nBg))
            s:SetBackdropBorderColor(unpack(nBdr))
            s.label:SetTextColor(1, 0.85, 0.55)
        else
            s:SetBackdropColor(0.07, 0.07, 0.09, 0.70)
            s:SetBackdropBorderColor(0.14, 0.14, 0.17, 0.50)
            s.label:SetTextColor(0.32, 0.32, 0.36)
        end
    end

    function btn:SetText(t) self.label:SetText(t) end
    function btn:GetText()  return self.label:GetText() end
    function btn:Enable()   self._on = true;  self:EnableMouse(true);  Sync(self) end
    function btn:Disable()  self._on = false; self:EnableMouse(false); Sync(self) end

    btn:SetScript("OnEnter", function(s)
        if s._on then
            s:SetBackdropColor(unpack(hBg))
            s:SetBackdropBorderColor(unpack(hBdr))
        end
    end)
    btn:SetScript("OnLeave", function(s) Sync(s) end)

    Sync(btn)
    return btn
end

-- ============================================================
-- UI: Main Frame
-- ============================================================

MainFrame = CreateFrame("Frame", "BBIG_MainFrame", UIParent, "BackdropTemplate")
MainFrame:SetSize(400, 430)
MainFrame:SetPoint("CENTER")
MainFrame:SetMovable(true)
MainFrame:EnableMouse(true)
MainFrame:RegisterForDrag("LeftButton")
MainFrame:SetScript("OnDragStart", MainFrame.StartMoving)
MainFrame:SetScript("OnDragStop", MainFrame.StopMovingOrSizing)
MainFrame:SetBackdrop({bgFile = FLAT, edgeFile = FLAT, edgeSize = 2})
MainFrame:SetBackdropColor(0.07, 0.07, 0.11, 0.96)
MainFrame:SetBackdropBorderColor(0.50, 0.08, 0.08, 0.85)
MainFrame:SetFrameStrata("DIALOG")
MainFrame:Hide()

local f = MainFrame

local titleBar = CreateFrame("Frame", nil, f, "BackdropTemplate")
titleBar:SetHeight(36)
titleBar:SetPoint("TOPLEFT", 2, -2)
titleBar:SetPoint("TOPRIGHT", -2, -2)
titleBar:SetBackdrop({bgFile = FLAT})
titleBar:SetBackdropColor(0.10, 0.10, 0.16, 1)

local tIcon = titleBar:CreateTexture(nil, "ARTWORK")
tIcon:SetSize(24, 24)
tIcon:SetPoint("LEFT", 10, 0)
tIcon:SetTexture("Interface\\AddOns\\BrosBeforeIOsGambling\\icon")
tIcon:SetTexCoord(0.08, 0.92, 0.25, 0.95)

local tText = titleBar:CreateFontString(nil, "OVERLAY")
tText:SetFont(STANDARD_TEXT_FONT, 13, "OUTLINE")
tText:SetPoint("LEFT", tIcon, "RIGHT", 8, 0)
tText:SetText("|cffcc2222BROS BEFORE IOs|r  |cffffcc66GAMBLING|r")

local closeBtn = CreateFrame("Button", nil, titleBar)
closeBtn:SetSize(20, 20)
closeBtn:SetPoint("RIGHT", -4, 0)
closeBtn:SetNormalTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Up")
closeBtn:SetPushedTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Down")
closeBtn:SetHighlightTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Highlight", "ADD")
closeBtn:SetScript("OnClick", function() f:Hide() end)

MakeSep(f, -40)

-- ============================================================
-- UI: Scrolling Message Log
-- ============================================================

local logBg = CreateFrame("Frame", nil, f, "BackdropTemplate")
logBg:SetPoint("TOPLEFT", 8, -44)
logBg:SetPoint("TOPRIGHT", -8, -44)
logBg:SetHeight(170)
logBg:SetBackdrop({bgFile = FLAT, edgeFile = FLAT, edgeSize = 1})
logBg:SetBackdropColor(0.04, 0.04, 0.06, 1)
logBg:SetBackdropBorderColor(0.22, 0.22, 0.28, 0.50)

MessageLog = CreateFrame("ScrollingMessageFrame", "BBIG_MessageLog", logBg)
MessageLog:SetPoint("TOPLEFT", 8, -6)
MessageLog:SetPoint("BOTTOMRIGHT", -8, 6)
MessageLog:SetFontObject(GameFontNormalSmall)
MessageLog:SetJustifyH("LEFT")
MessageLog:SetFading(false)
MessageLog:SetMaxLines(500)
MessageLog:EnableMouseWheel(true)
MessageLog:SetScript("OnMouseWheel", function(self, delta)
    if delta > 0 then self:ScrollUp() else self:ScrollDown() end
end)

MakeSep(f, -218)

-- ============================================================
-- UI: Controls
-- ============================================================

local CY = -224
local CW = 126
local BW = 118
local BH = 24
local CH = 28

btnNewGame = StyledBtn(f, BW, BH)
btnNewGame:SetPoint("TOPLEFT", 10, CY)
btnNewGame:SetText("New Game")

btnChannel = StyledBtn(f, BW, BH)
btnChannel:SetPoint("TOPLEFT", 10 + CW, CY)
btnChannel:SetText(CHANNEL_LABELS[Channel])

btnEnterSelf = StyledBtn(f, BW, BH)
btnEnterSelf:SetPoint("TOPLEFT", 10 + CW * 2, CY)
btnEnterSelf:SetText("Enter Self")

btnLastCall = StyledBtn(f, BW, BH)
btnLastCall:SetPoint("TOPLEFT", 10, CY - CH)
btnLastCall:SetText("Last Call")

editRollValue = CreateFrame("EditBox", "BBIG_EditRollValue", f, "BackdropTemplate")
editRollValue:SetSize(BW - 6, BH - 2)
editRollValue:SetPoint("TOPLEFT", 10 + CW + 3, CY - CH - 1)
editRollValue:SetBackdrop({bgFile = FLAT, edgeFile = FLAT, edgeSize = 1})
editRollValue:SetBackdropColor(0.05, 0.05, 0.08, 1)
editRollValue:SetBackdropBorderColor(0.35, 0.35, 0.40, 0.60)
editRollValue:SetFont(STANDARD_TEXT_FONT, 12, "OUTLINE")
editRollValue:SetTextColor(1, 0.85, 0.55)
editRollValue:SetAutoFocus(false)
editRollValue:SetJustifyH("CENTER")
editRollValue:SetTextInsets(4, 4, 0, 0)
editRollValue:SetText(Comma(CurrentRollValue))
editRollValue:SetScript("OnEnterPressed", function(self)
    self:ClearFocus()
    local val = self:GetText():gsub(",", ""):gsub("%D", "")
    if val == "" then self:SetText(Comma(CurrentRollValue)); return end
    CurrentRollValue = tonumber(val) or CurrentRollValue
    self:SetText(Comma(CurrentRollValue))
end)
editRollValue:SetScript("OnEscapePressed", function(self)
    self:ClearFocus()
    self:SetText(Comma(CurrentRollValue))
end)

btnSelfRoll = StyledBtn(f, BW, BH)
btnSelfRoll:SetPoint("TOPLEFT", 10 + CW * 2, CY - CH)
btnSelfRoll:SetText("Self Roll")

btnRoll = StyledBtn(f, BW, BH)
btnRoll:SetPoint("TOPLEFT", 10, CY - CH * 2)
btnRoll:SetText("Roll")

btnStats = StyledBtn(f, BW, BH)
btnStats:SetPoint("TOPLEFT", 10 + CW, CY - CH * 2)
btnStats:SetText("Stats")

btnResetGame = StyledBtn(f, BW, BH)
btnResetGame:SetPoint("TOPLEFT", 10 + CW * 2, CY - CH * 2)
btnResetGame:SetText("Reset Game")

btnResetStats = StyledBtn(f, BW, BH)
btnResetStats:SetPoint("TOPLEFT", 10, CY - CH * 3)
btnResetStats:SetText("Reset Stats")

MakeSep(f, CY - CH * 4 - 2)

local qLabel = f:CreateFontString(nil, "OVERLAY")
qLabel:SetFont(STANDARD_TEXT_FONT, 9, "OUTLINE")
qLabel:SetPoint("TOPLEFT", 12, CY - CH * 4 - 8)
qLabel:SetTextColor(0.55, 0.55, 0.60)
qLabel:SetText("QUICK BET")

local PW = 90
local PG = 4
local PX = math.floor((400 - 4 * PW - 3 * PG) / 2)
local PY = CY - CH * 4 - 22
local PRESETS = {10000, 25000, 50000, 100000}
for i, amount in ipairs(PRESETS) do
    local btn = StyledBtn(f, PW, BH, true)
    btn:SetPoint("TOPLEFT", PX + (i - 1) * (PW + PG), PY)
    btn:SetText(Comma(amount))
    btn:SetScript("OnClick", function()
        if GameActive then return end
        CurrentRollValue = amount
        editRollValue:SetText(Comma(amount))
    end)
    presetBtns[i] = btn
end

btnNewGame:SetScript("OnClick",    OnNewGameClick)
btnChannel:SetScript("OnClick",    OnChannelClick)
btnEnterSelf:SetScript("OnClick",  OnEnterSelfClick)
btnLastCall:SetScript("OnClick",   OnLastCallClick)
btnSelfRoll:SetScript("OnClick",   OnSelfRollClick)
btnRoll:SetScript("OnClick",       OnRollClick)
btnStats:SetScript("OnClick",      OnStatsClick)
btnResetGame:SetScript("OnClick",  OnResetGameClick)
btnResetStats:SetScript("OnClick", OnResetStatsClick)

-- ============================================================
-- UI: Twitch Plug
-- ============================================================

local twitchBar = CreateFrame("Frame", nil, f, "BackdropTemplate")
twitchBar:SetHeight(22)
twitchBar:SetPoint("BOTTOMLEFT", 2, 2)
twitchBar:SetPoint("BOTTOMRIGHT", -2, 2)
twitchBar:SetBackdrop({bgFile = FLAT, edgeFile = FLAT, edgeSize = 1})
twitchBar:SetBackdropColor(0.18, 0.10, 0.30, 0.85)
twitchBar:SetBackdropBorderColor(0.40, 0.25, 0.65, 0.70)
twitchBar:EnableMouse(true)

local twitchLabel = twitchBar:CreateFontString(nil, "OVERLAY")
twitchLabel:SetFont(STANDARD_TEXT_FONT, 10, "OUTLINE")
twitchLabel:SetPoint("CENTER")
twitchLabel:SetText("|cff9146fftwitch.tv/|r|cffffffffrespls|r")

twitchBar:SetScript("OnEnter", function(self)
    self:SetBackdropColor(0.25, 0.14, 0.42, 0.95)
    self:SetBackdropBorderColor(0.57, 0.35, 0.87, 0.90)
    GameTooltip:SetOwner(self, "ANCHOR_TOP")
    GameTooltip:AddLine("|cff9146fftwitch.tv/respls|r")
    GameTooltip:AddLine("Click to copy URL", 0.7, 0.7, 0.7)
    GameTooltip:Show()
end)
twitchBar:SetScript("OnLeave", function(self)
    self:SetBackdropColor(0.18, 0.10, 0.30, 0.85)
    self:SetBackdropBorderColor(0.40, 0.25, 0.65, 0.70)
    GameTooltip:Hide()
end)
twitchBar:SetScript("OnMouseUp", function()
    if not BBIG_URLPopup then
        local pop = CreateFrame("Frame", "BBIG_URLPopup", UIParent, "BackdropTemplate")
        pop:SetSize(280, 56)
        pop:SetPoint("CENTER")
        pop:SetBackdrop({bgFile = FLAT, edgeFile = FLAT, edgeSize = 1})
        pop:SetBackdropColor(0.10, 0.07, 0.16, 0.97)
        pop:SetBackdropBorderColor(0.57, 0.35, 0.87, 0.90)
        pop:SetFrameStrata("TOOLTIP")

        local pLbl = pop:CreateFontString(nil, "OVERLAY")
        pLbl:SetFont(STANDARD_TEXT_FONT, 10, "OUTLINE")
        pLbl:SetPoint("TOP", 0, -8)
        pLbl:SetText("|cff9146ffPress Ctrl+C to copy:|r")

        local pBox = CreateFrame("EditBox", nil, pop, "BackdropTemplate")
        pBox:SetSize(260, 22)
        pBox:SetPoint("BOTTOM", 0, 8)
        pBox:SetBackdrop({bgFile = FLAT, edgeFile = FLAT, edgeSize = 1})
        pBox:SetBackdropColor(0.05, 0.03, 0.08, 1)
        pBox:SetBackdropBorderColor(0.35, 0.25, 0.50, 0.60)
        pBox:SetFont(STANDARD_TEXT_FONT, 11, "OUTLINE")
        pBox:SetTextColor(1, 1, 1)
        pBox:SetAutoFocus(true)
        pBox:SetJustifyH("CENTER")
        pBox:SetTextInsets(4, 4, 0, 0)
        pBox:SetText("https://twitch.tv/respls")
        pBox:HighlightText()
        pBox:SetScript("OnEscapePressed", function() pop:Hide() end)
        pBox:SetScript("OnEnterPressed", function() pop:Hide() end)
        pop.box = pBox
    end
    BBIG_URLPopup:Show()
    BBIG_URLPopup.box:SetText("https://twitch.tv/respls")
    BBIG_URLPopup.box:HighlightText()
    BBIG_URLPopup.box:SetFocus()
end)

-- ============================================================
-- UI: Minimap Button
-- ============================================================

local minimapBtn = CreateFrame("Button", "BBIG_MinimapButton", Minimap)
minimapBtn:SetSize(32, 32)
minimapBtn:SetFrameStrata("MEDIUM")
minimapBtn:SetFrameLevel(8)
minimapBtn.angle = 220

local function UpdateMinimapPosition()
    local r = 104
    local x = math.cos(math.rad(minimapBtn.angle)) * r
    local y = math.sin(math.rad(minimapBtn.angle)) * r
    minimapBtn:ClearAllPoints()
    minimapBtn:SetPoint("CENTER", Minimap, "CENTER", x, y)
end
UpdateMinimapPosition()

local mmBorder = minimapBtn:CreateTexture(nil, "OVERLAY")
mmBorder:SetSize(56, 56)
mmBorder:SetPoint("TOPLEFT", 0, 0)
mmBorder:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")

local mmBg = minimapBtn:CreateTexture(nil, "BACKGROUND")
mmBg:SetSize(21, 21)
mmBg:SetPoint("TOPLEFT", 7, -5)
mmBg:SetTexture("Interface\\Minimap\\UI-Minimap-Background")

local mmIcon = minimapBtn:CreateTexture(nil, "ARTWORK")
mmIcon:SetSize(21, 21)
mmIcon:SetPoint("TOPLEFT", 7, -5)
mmIcon:SetTexture("Interface\\AddOns\\BrosBeforeIOsGambling\\icon")
mmIcon:SetTexCoord(0.08, 0.92, 0.25, 0.95)

minimapBtn:RegisterForClicks("LeftButtonUp", "RightButtonUp")
minimapBtn:RegisterForDrag("LeftButton")

minimapBtn:SetScript("OnDragStart", function(self)
    self:LockHighlight()
    self:SetScript("OnUpdate", function(btn)
        local mx, my = Minimap:GetCenter()
        local px, py = GetCursorPosition()
        local s = Minimap:GetEffectiveScale()
        px, py = px / s, py / s
        btn.angle = math.deg(math.atan2(py - my, px - mx))
        UpdateMinimapPosition()
    end)
end)

minimapBtn:SetScript("OnDragStop", function(self)
    self:UnlockHighlight()
    self:SetScript("OnUpdate", nil)
    if BBIGSettings then BBIGSettings.minimapAngle = self.angle end
end)

minimapBtn:SetScript("OnClick", function()
    if f:IsShown() then f:Hide() else f:Show() end
end)

minimapBtn:SetScript("OnEnter", function(self)
    GameTooltip:SetOwner(self, "ANCHOR_LEFT")
    GameTooltip:AddLine("Bros Before IOs Gambling")
    GameTooltip:AddLine("Click to toggle window", 1, 1, 1)
    GameTooltip:AddLine("Drag to reposition", 0.7, 0.7, 0.7)
    GameTooltip:Show()
end)

minimapBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)

-- ============================================================
-- Chat Integration (non-addon players: type 1 to enter, -1 to leave)
-- ============================================================

local chatFrame = CreateFrame("Frame")

RegisterChatEvents = function()
    chatFrame:UnregisterAllEvents()
    local events = CHAT_EVENTS[Channel]
    if events then
        for _, ev in ipairs(events) do
            chatFrame:RegisterEvent(ev)
        end
    end
end

UnregisterChatEvents = function()
    chatFrame:UnregisterAllEvents()
end

chatFrame:SetScript("OnEvent", function(self, event, message, sender)
    if not IsLeader() or not GameActive then return end
    local senderBase = GetBaseName(sender)

    if message == "1" and not Locked then
        if not FindPlayer(senderBase) then
            tinsert(Players, {senderBase})
            SendMsg("ENTERED:" .. senderBase)
            LogInfo(format("%s has entered the game.", senderBase))
            UpdateButtons()
        end
    elseif message == "-1" and not Locked then
        local idx = FindPlayer(senderBase)
        if idx then
            tremove(Players, idx)
            SendMsg("LEFT:" .. senderBase)
            LogInfo(format("%s has left the game.", senderBase))
            UpdateButtons()
        end
    end
end)

-- ============================================================
-- Options Panel (WoW Settings API)
-- ============================================================

local optionsFrame = CreateFrame("Frame", "BBIG_OptionsFrame")
optionsFrame.name = "Bros Before IOs Gambling"

local optTitle = optionsFrame:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
optTitle:SetPoint("TOPLEFT", 16, -16)
optTitle:SetText("Bros Before IOs Gambling")

local optDesc = optionsFrame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
optDesc:SetPoint("TOPLEFT", optTitle, "BOTTOMLEFT", 0, -8)
optDesc:SetText("Type /bbig to toggle the gambling window, or click the minimap dice icon.")

local optOpenBtn = CreateFrame("Button", nil, optionsFrame, "UIPanelButtonTemplate")
optOpenBtn:SetSize(120, 22)
optOpenBtn:SetPoint("TOPLEFT", optDesc, "BOTTOMLEFT", 0, -16)
optOpenBtn:SetText("Open Window")
optOpenBtn:SetScript("OnClick", function()
    f:Show()
    SettingsPanel:Hide()
end)

local category = Settings.RegisterCanvasLayoutCategory(optionsFrame, optionsFrame.name)
Settings.RegisterAddOnCategory(category)

-- ============================================================
-- Slash Commands
-- ============================================================

SLASH_BBIG1 = "/bbig"
SlashCmdList["BBIG"] = function(input)
    local cmd, rest = strsplit(" ", input, 2)
    cmd = (cmd or ""):lower()

    if cmd == "" then
        if f:IsShown() then f:Hide() else f:Show() end
    elseif cmd == "show" then
        f:Show()
    elseif cmd == "hide" then
        f:Hide()
    elseif cmd == "help" then
        print("|cffff8000[BBIG]|r Commands:")
        print("  /bbig          - Toggle window")
        print("  /bbig leave    - Leave current game")
        print("  /bbig stats [name]  - View stats")
        print("  /bbig resetstats")
        print("  /bbig test     - Toggle test mode (solo with bots)")
    elseif cmd == "test" then
        TestMode = not TestMode
        if TestMode then
            if GameActive then
                ResetGameState()
                UpdateButtons()
            end
            if not f:IsShown() then f:Show() end
            LogSystem("|cff00ccffTEST MODE ON|r - You are the leader with 3 bots.")
            LogSystem("Click 'New Game' to start, 'Roll' to lock, then 'Self Roll'.")
            print("|cffff8000[BBIG]|r |cff00ccffTest mode enabled.|r")
        else
            if GameActive then
                ResetGameState()
            end
            LogSystem("|cff00ccffTEST MODE OFF|r - Back to normal.")
            print("|cffff8000[BBIG]|r Test mode disabled.")
        end
        UpdateButtons()
    elseif cmd == "stats" then
        if not f:IsShown() then f:Show() end
        PostStats(rest)
    elseif cmd == "leave" then
        if GameActive and not Locked and FindPlayer(Me) then
            SendMsg("QUIT")
        else
            print("|cffff8000[BBIG]|r Cannot leave right now.")
        end
    elseif cmd == "resetstats" then
        BBIGStats = {All = {}, Specific = {}}
        LogSystem("All stats have been reset.")
    else
        print("|cffff8000[BBIG]|r Commands:")
        print("  /bbig          - Toggle window")
        print("  /bbig leave    - Leave current game")
        print("  /bbig stats [name]  - View stats")
        print("  /bbig resetstats")
        print("  /bbig test     - Toggle test mode (solo with bots)")
    end
end

-- ============================================================
-- Event Handler
-- ============================================================

local eventFrame = CreateFrame("Frame")
eventFrame:RegisterEvent("ADDON_LOADED")
eventFrame:RegisterEvent("PLAYER_LOGIN")
eventFrame:RegisterEvent("CHAT_MSG_ADDON")
eventFrame:RegisterEvent("CHAT_MSG_SYSTEM")
eventFrame:RegisterEvent("GROUP_ROSTER_UPDATE")

eventFrame:SetScript("OnEvent", function(self, event, ...)
    if event == "ADDON_LOADED" then
        local loaded = ...
        if loaded == addonName then
            BBIGStats    = BBIGStats    or {All = {}, Specific = {}}
            BBIGSettings = BBIGSettings or {minimapAngle = 220}

            if BBIGSettings.minimapAngle then
                minimapBtn.angle = BBIGSettings.minimapAngle
                UpdateMinimapPosition()
            end
        end

    elseif event == "PLAYER_LOGIN" then
        Me = GetBaseName(UnitName("player"))
        UpdateButtons()
        LogSystem("Bros Before IOs Gambling v2.1 loaded. Type /bbig to toggle window, /bbig help for commands.")

    elseif event == "CHAT_MSG_ADDON" then
        OnAddonMessage(...)

    elseif event == "CHAT_MSG_SYSTEM" then
        OnSystemMessage(...)

    elseif event == "GROUP_ROSTER_UPDATE" then
        UpdateButtons()
    end
end)
