-- ==============================================================
-- DebugHUD.lua — Premium Debug Console
-- Usage: Debug_Search("minimap") to find all functions with "minimap"
--        Debug_Print("your message") to add a line
--        Debug_Clear() to clear the output
-- ==============================================================

DebugHUDData = { DebugText = "" }
DebugLines = {}
DEBUG_MAX_LINES = 500

-- ========== CORE FUNCTIONS ==========

function Debug_AddLine(line)
    table.insert(DebugLines, tostring(line))
    if #DebugLines > DEBUG_MAX_LINES then
        table.remove(DebugLines, 1)
    end
    Debug_Refresh()
end

function Debug_Print(msg)
    Debug_AddLine(msg)
end

function Debug_Clear()
    DebugLines = {}
    Debug_Refresh()
end

function Debug_Refresh()
    local numbered = {}
    local width = math.max(3, #tostring(#DebugLines))
    for i, line in ipairs(DebugLines) do
        table.insert(numbered, string.format("%" .. width .. "d | %s", i, line))
    end
    DebugHUDData.DebugText = table.concat(numbered, "\n")
    pcall(function() UI_SetDataContext("DebugHUD", DebugHUDData) end)
end

-- ========== SEARCH & DISCOVERY ==========

function SafeToString(val)
    local ok, result = pcall(tostring, val)
    if ok then return result else return "???" end
end

function Debug_Search(pattern)
    Debug_Clear()
    Debug_SearchAdd(pattern)
end

function Debug_SearchAdd(pattern)
    Debug_AddLine("===================================================================")
    Debug_AddLine("  [?] SEARCH: " .. SafeToString(pattern))
    Debug_AddLine("===================================================================")
    Debug_AddLine("")

    local found = {}
    local pat = string.lower(SafeToString(pattern))

    for k, v in pairs(_G) do
        local ok, name = pcall(tostring, k)
        if ok and name then
            local lowerName = string.lower(name)
            if string.find(lowerName, pat, 1, true) then
                local vtype = type(v)
                table.insert(found, { name = name, vtype = vtype })
            end
        end
    end

    table.sort(found, function(a, b) return a.name < b.name end)

    local funcCount, tableCount, otherCount = 0, 0, 0

    for i, item in ipairs(found) do
        local icon = ""
        if item.vtype == "function" then
            icon = "[F]"
            funcCount = funcCount + 1
        elseif item.vtype == "table" then
            icon = "[T]"
            tableCount = tableCount + 1
        else
            icon = "*"
            otherCount = otherCount + 1
        end
        Debug_AddLine(string.format("  %s %s", icon, item.name))
    end

    Debug_AddLine("")
    Debug_AddLine("-------------------------------------------------------------------")
    Debug_AddLine(string.format("  Total: %d  |  Functions: %d  |  Tables: %d  |  Other: %d",
        #found, funcCount, tableCount, otherCount))
    Debug_AddLine("-------------------------------------------------------------------")
end

function Debug_Exists(name)
    local ok, v = pcall(function() return _G[name] end)
    if not ok or v == nil then
        Debug_AddLine("[X] NOT FOUND: " .. SafeToString(name))
        return false
    else
        Debug_AddLine("[OK] EXISTS: " .. SafeToString(name) .. " [" .. type(v) .. "]")
        return true
    end
end

function Debug_ExistsMultiple(names)
    Debug_AddLine("===================================================================")
    Debug_AddLine("  [?] CHECKING EXISTENCE")
    Debug_AddLine("===================================================================")
    Debug_AddLine("")
    local found, missing = 0, 0
    for _, name in ipairs(names) do
        local ok, v = pcall(function() return _G[name] end)
        if ok and v ~= nil then
            Debug_AddLine("  [OK] " .. SafeToString(name) .. " (" .. type(v) .. ")")
            found = found + 1
        else
            Debug_AddLine("  [X] " .. SafeToString(name))
            missing = missing + 1
        end
    end
    Debug_AddLine("")
    Debug_AddLine("-------------------------------------------------------------------")
    Debug_AddLine(string.format("  Found: %d  |  Missing: %d", found, missing))
    Debug_AddLine("-------------------------------------------------------------------")
end

function Debug_TableFuncs(tableName)
    local ok, t = pcall(function() return _G[tableName] end)
    if not ok or type(t) ~= "table" then
        Debug_AddLine("[X] ERROR: " .. SafeToString(tableName) .. " is not a table")
        return
    end

    Debug_Clear()
    Debug_AddLine("===================================================================")
    Debug_AddLine("  [T] TABLE FUNCTIONS: " .. SafeToString(tableName))
    Debug_AddLine("===================================================================")
    Debug_AddLine("")

    local funcs = {}
    for k, v in pairs(t) do
        local ok2, kstr = pcall(tostring, k)
        if ok2 and type(v) == "function" then
            table.insert(funcs, kstr)
        end
    end
    table.sort(funcs)

    for i, name in ipairs(funcs) do
        Debug_AddLine(string.format("  [F] %s.%s()", tableName, name))
    end

    Debug_AddLine("")
    Debug_AddLine("-------------------------------------------------------------------")
    Debug_AddLine("  Total Functions: " .. #funcs)
    Debug_AddLine("-------------------------------------------------------------------")
end

-- ========== UI CREATION ==========

function ShowDebugHUD()
    pcall(function()
        if Rule_Remove and UpdateDebugHUD then Rule_Remove(UpdateDebugHUD) end
        if UI_Remove then UI_Remove("DebugHUD") end
    end)

    local xaml = [[
<Border xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
        Margin="40,40,40,40">
    
    <!-- Outer glow effect -->
    <Border.Effect>
        <DropShadowEffect Color="#00FF88" BlurRadius="30" ShadowDepth="0" Opacity="0.5"/>
    </Border.Effect>
    
    <Border Background="#FF000000" 
            BorderThickness="4" 
            CornerRadius="12">
        <Border.BorderBrush>
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                <GradientStop Color="#00FF88" Offset="0"/>
                <GradientStop Color="#00AAFF" Offset="0.5"/>
                <GradientStop Color="#AA00FF" Offset="1"/>
            </LinearGradientBrush>
        </Border.BorderBrush>

        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>

            <!-- Header with gradient -->
            <Border Grid.Row="0" 
                    CornerRadius="9,9,0,0" 
                    Padding="25,18">
                <Border.Background>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                        <GradientStop Color="#1A003300" Offset="0"/>
                        <GradientStop Color="#3A004400" Offset="0.5"/>
                        <GradientStop Color="#1A003300" Offset="1"/>
                    </LinearGradientBrush>
                </Border.Background>
                
                <StackPanel>
                    <TextBlock FontFamily="Consolas" 
                               FontSize="24" 
                               FontWeight="Bold"
                               HorizontalAlignment="Center"
                               Margin="0,0,0,8">
                        <TextBlock.Foreground>
                            <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                                <GradientStop Color="#00FF88" Offset="0"/>
                                <GradientStop Color="#00DDFF" Offset="1"/>
                            </LinearGradientBrush>
                        </TextBlock.Foreground>
                        <TextBlock.Effect>
                            <DropShadowEffect Color="#00FF88" BlurRadius="20" ShadowDepth="0" Opacity="0.9"/>
                        </TextBlock.Effect>
                        DEBUG CONSOLE
                    </TextBlock>
                    
                    <TextBlock Text="Ctrl+A = Select All | Ctrl+C = Copy" 
                               Foreground="#00FFAA" 
                               FontFamily="Consolas"
                               FontSize="12" 
                               FontWeight="Bold"
                               HorizontalAlignment="Center"/>
                </StackPanel>
            </Border>

            <!-- Main content area -->
            <Border Grid.Row="1"
                    Margin="4"
                    Background="#FF000000"
                    CornerRadius="0">

                <TextBox Text="{Binding [DebugText], Mode=OneWay}"
                         Foreground="#00FFAA"
                         Background="#FF000000"
                         FontSize="15"
                         FontFamily="Consolas"
                         FontWeight="Medium"
                         TextWrapping="NoWrap"
                         IsReadOnly="True"
                         BorderThickness="0"
                         Padding="25"
                         VerticalScrollBarVisibility="Auto"
                         HorizontalScrollBarVisibility="Auto"
                         AcceptsReturn="True"
                         CaretBrush="#00FF99"
                         SelectionBrush="#00FF88"
                         SelectionOpacity="0.5">
                    <TextBox.Style>
                        <Style TargetType="TextBox">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="TextBox">
                                        <Border Background="{TemplateBinding Background}" BorderThickness="0">
                                            <ScrollViewer x:Name="PART_ContentHost" Background="{TemplateBinding Background}"/>
                                        </Border>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </TextBox.Style>
                    <TextBox.Effect>
                        <DropShadowEffect Color="#00FF88" BlurRadius="10" ShadowDepth="0" Opacity="0.4"/>
                    </TextBox.Effect>
                </TextBox>
            </Border>

            <!-- Footer with command info -->
            <Border Grid.Row="2" 
                    CornerRadius="0,0,9,9" 
                    Padding="20,15">
                <Border.Background>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                        <GradientStop Color="#1A002200" Offset="0"/>
                        <GradientStop Color="#3A003300" Offset="0.5"/>
                        <GradientStop Color="#1A002200" Offset="1"/>
                    </LinearGradientBrush>
                </Border.Background>
                
                <StackPanel>
                    <TextBlock FontFamily="Consolas" 
                               FontSize="11" 
                               Foreground="#00DD88"
                               HorizontalAlignment="Center"
                               Margin="0,0,0,5">
                        <Run Text="[F] COMMANDS: " FontWeight="Bold"/>
                        <Run Text="Debug_Search(" Foreground="#00CCFF"/>
                        <Run Text="&quot;text&quot;" Foreground="#00FF88"/>
                        <Run Text=")" Foreground="#00CCFF"/>
                        <Run Text="  •  " Foreground="#006666"/>
                        <Run Text="Debug_Clear()" Foreground="#00CCFF"/>
                        <Run Text="  •  " Foreground="#006666"/>
                        <Run Text="HideDebugHUD()" Foreground="#00CCFF"/>
                    </TextBlock>
                    
                    <TextBlock FontFamily="Consolas" 
                               FontSize="10" 
                               Foreground="#008866"
                               HorizontalAlignment="Center"
                               Opacity="0.8">
                        <Run Text="Quick Aliases: "/>
                        <Run Text="DS(" Foreground="#00AA88"/>
                        <Run Text="&quot;text&quot;" Foreground="#00CC88"/>
                        <Run Text=")" Foreground="#00AA88"/>
                        <Run Text="  •  "/>
                        <Run Text="DC()" Foreground="#00AA88"/>
                        <Run Text="  •  "/>
                        <Run Text="DP(" Foreground="#00AA88"/>
                        <Run Text="&quot;msg&quot;" Foreground="#00CC88"/>
                        <Run Text=")" Foreground="#00AA88"/>
                    </TextBlock>
                </StackPanel>
            </Border>
        </Grid>
    </Border>
</Border>
]]

    local initText = [[===================================================================
  DEBUG CONSOLE v2.0
===================================================================

  MAIN COMMANDS:

  Debug_Search("keyword")
     Find all globals matching keyword (case-insensitive)

  Debug_TableFuncs("TableName")
     List all functions in a specific table

  Debug_Exists("FunctionName")
     Check if a function or variable exists

  Debug_Print("message")
     Add a custom message to the console

  Debug_Clear()
     Clear the console output

  HideDebugHUD()
     Close this debug console

-------------------------------------------------------------------
  QUICK ALIASES:
-------------------------------------------------------------------

  DS("text")   =  Debug_Search
  DP("msg")    =  Debug_Print
  DC()         =  Debug_Clear
  DE("name")   =  Debug_Exists

-------------------------------------------------------------------
  EXAMPLES:
-------------------------------------------------------------------

  DS("player")              -- Find all player-related functions
  DS("squad")               -- Find all squad functions
  Debug_TableFuncs("SBP")   -- List Squad Blueprint functions

===================================================================
  Ready for input. Type a command to begin...
===================================================================]]

    DebugLines = {}
    for line in string.gmatch(initText .. "\n", "(.-)\n") do
        table.insert(DebugLines, line)
    end
    Debug_Refresh()

    UI_AddChild("ScarDefault", "XamlPresenter", "DebugHUD", {
        IsHitTestVisible = true,
        Xaml = xaml,
        DataContext = UI_CreateDataContext(DebugHUDData)
    })
end

function HideDebugHUD()
    pcall(function()
        if UI_Remove then UI_Remove("DebugHUD") end
    end)
    DebugLines = {}
end

-- ========== ERROR TESTING HELPERS ==========

function Debug_TryCall(func, ...)
    if func == nil then
        Debug_Print("[X] ERROR: Function is nil")
        return nil
    end

    if type(func) ~= "function" then
        Debug_Print("[X] ERROR: Not a function, got: " .. type(func))
        return nil
    end

    local results = {pcall(func, ...)}
    local ok = results[1]

    if ok then
        Debug_Print("[OK] Call succeeded")
        for i = 2, #results do
            local val = results[i]
            Debug_Print("  -> Return[" .. (i-1) .. "]: " .. SafeToString(val) .. " [" .. type(val) .. "]")
        end
        return results[2]
    else
        local errMsg = results[2] or "unknown error"
        Debug_Print("[X] FAILED: " .. SafeToString(errMsg))
        return nil
    end
end

function Debug_TestBP(name, bpFunc)
    bpFunc = bpFunc or BP_GetUpgradeBlueprint
    Debug_Print("===================================================================")
    Debug_Print("  [BP] TESTING BLUEPRINT: " .. SafeToString(name))
    Debug_Print("===================================================================")

    if bpFunc == nil then
        Debug_Print("[X] ERROR: BP function is nil")
        return
    end
    Debug_Print("  [OK] BP function exists")

    local ok, result = pcall(bpFunc, name)
    if not ok then
        Debug_Print("  [X] pcall failed: " .. SafeToString(result))
        return
    end
    if result == nil then
        Debug_Print("  [X] BP returned nil - name not found")
        return
    end
    Debug_Print("  [OK] Got BP handle [" .. type(result) .. "]")

    if BP_GetName == nil then
        Debug_Print("  [X] BP_GetName not available")
        return
    end
    local ok2, bpName = pcall(BP_GetName, result)
    if not ok2 then
        Debug_Print("  [X] BP_GetName failed: " .. SafeToString(bpName))
        return
    end
    Debug_Print("  [OK] BP_GetName: " .. SafeToString(bpName))

    Debug_Print("")
    Debug_Print("  [OK] ALL TESTS PASSED")
    Debug_Print("===================================================================")
end

function Debug_Test(label, func)
    Debug_Print("▬▬▬ " .. SafeToString(label) .. " ▬▬▬")

    if type(func) ~= "function" then
        Debug_Print("[X] ERROR: Second arg must be a function")
        return
    end

    local ok, result, extra = pcall(func)
    if ok then
        Debug_Print("[OK] " .. SafeToString(result) .. " [" .. type(result) .. "]")
        if extra ~= nil then
            Debug_Print("  (extra: " .. SafeToString(extra) .. ")")
        end
        return result
    else
        Debug_Print("[X] ERROR: " .. SafeToString(result))
        return nil
    end
end

function Debug_TestMulti(tests)
    Debug_Print("===================================================================")
    Debug_Print("  [TEST] RUNNING TESTS")
    Debug_Print("===================================================================")
    local passed, failed = 0, 0
    for _, test in ipairs(tests) do
        local label, func = test[1], test[2]
        local ok, result = pcall(func)
        if ok and result ~= nil then
            Debug_Print("  [OK] " .. SafeToString(label) .. " = " .. SafeToString(result))
            passed = passed + 1
        else
            local err = ok and "returned nil" or SafeToString(result)
            Debug_Print("  [X] " .. SafeToString(label) .. ": " .. err)
            failed = failed + 1
        end
    end
    Debug_Print("")
    Debug_Print("-------------------------------------------------------------------")
    Debug_Print(string.format("  Passed: %d  |  Failed: %d", passed, failed))
    Debug_Print("-------------------------------------------------------------------")
end

-- ========== QUICK DEBUG HELPERS ==========

function Debug_FuncExists(name)
    local v = _G[name]
    Debug_Print((v and "[OK] " or "[X] ") .. SafeToString(name) .. (v and (" [" .. type(v) .. "]") or ""))
    return v ~= nil
end

function Debug_FuncExistsMulti(names)
    Debug_Print("===================================================================")
    Debug_Print("  [?] FUNCTION CHECK")
    Debug_Print("===================================================================")
    local found, missing = 0, 0
    for _, name in ipairs(names) do
        if Debug_FuncExists(name) then found = found + 1 else missing = missing + 1 end
    end
    Debug_Print("")
    Debug_Print("-------------------------------------------------------------------")
    Debug_Print(string.format("  Found: %d  |  Missing: %d", found, missing))
    Debug_Print("-------------------------------------------------------------------")
end

function Debug_BPCheck(name, bpFunc)
    bpFunc = bpFunc or BP_GetUpgradeBlueprint
    local ok, bp = pcall(bpFunc, name)
    Debug_Print((ok and bp and "[OK] " or "[X] ") .. SafeToString(name))
    return ok and bp ~= nil
end

function Debug_BPList(list, bpFunc)
    bpFunc = bpFunc or BP_GetUpgradeBlueprint
    Debug_Print("===================================================================")
    Debug_Print("  [LIST] BLUEPRINT LIST CHECK")
    Debug_Print("===================================================================")
    local found = 0
    for _, name in ipairs(list) do
        local ok, bp = pcall(bpFunc, name)
        local exists = ok and bp ~= nil
        if exists then found = found + 1 end
        Debug_Print("  " .. (exists and "[OK]" or "[X]") .. " " .. SafeToString(name))
    end
    Debug_Print("")
    Debug_Print("-------------------------------------------------------------------")
    Debug_Print(string.format("  Found: %d / %d", found, #list))
    Debug_Print("-------------------------------------------------------------------")
end

function Debug_BPName(name, bpFunc)
    bpFunc = bpFunc or BP_GetUpgradeBlueprint
    local ok, bp = pcall(bpFunc, name)
    if not (ok and bp) then
        Debug_Print("[X] " .. SafeToString(name) .. ": BP missing")
        return
    end
    local ok2, bpName = pcall(BP_GetName, bp)
    Debug_Print((ok2 and "[OK] " or "[X] ") .. SafeToString(name) .. (ok2 and (" -> " .. SafeToString(bpName)) or ""))
end

function Debug_SBPPath(pathStr)
    local parts = {}
    for part in string.gmatch(pathStr, "[^%.]+") do
        table.insert(parts, part)
    end

    local current = _G
    for i, part in ipairs(parts) do
        if current == nil then
            Debug_Print("[X] " .. pathStr .. ": missing at " .. SafeToString(parts[i-1] or "root"))
            return false
        end
        current = current[part]
    end

    if current then
        Debug_Print("[OK] " .. pathStr .. " [" .. type(current) .. "]")
        local ok, n = pcall(BP_GetName, current)
        if ok and n then Debug_Print("  -> BP_GetName = " .. SafeToString(n)) end
        return true
    else
        Debug_Print("[X] " .. pathStr .. ": nil")
        return false
    end
end

function Debug_SquadType(typeName)
    local ok, p = pcall(Game_GetLocalPlayer)
    if not (ok and p) then Debug_Print("[X] No local player") return end

    local ok2, sg = pcall(Player_GetSquads, p)
    if not (ok2 and sg) then Debug_Print("[X] No squads") return end

    local ok3, sq = pcall(SGroup_GetSquadAt, sg, 1)
    if not (ok3 and sq) then Debug_Print("[X] No squad at index 1") return end

    local ok4, isType = pcall(Squad_IsOfType, sq, typeName)
    Debug_Print((ok4 and isType and "[OK]" or "[X]") .. " First squad is '" .. SafeToString(typeName) .. "'")
end

function Debug_AllSquads()
    local ok, p = pcall(Game_GetLocalPlayer)
    if not (ok and p) then Debug_Print("[X] No local player") return end

    local ok2, sg = pcall(Player_GetSquads, p)
    if not (ok2 and sg) then Debug_Print("[X] No squads") return end

    local ok3, count = pcall(SGroup_Count, sg)
    if not ok3 then Debug_Print("[X] Can't count squads") return end

    Debug_Print("===================================================================")
    Debug_Print("  [SQ] YOUR SQUADS (" .. count .. ")")
    Debug_Print("===================================================================")
    for i = 1, math.min(count, 50) do
        local ok4, sq = pcall(SGroup_GetSquadAt, sg, i)
        if ok4 and sq then
            local ok5, bp = pcall(Squad_GetBlueprint, sq)
            local name = "?"
            if ok5 and bp then
                local ok6, n = pcall(BP_GetName, bp)
                if ok6 then name = SafeToString(n) end
            end
            Debug_Print(string.format("  %02d. %s", i, name))
        end
    end
    Debug_Print("-------------------------------------------------------------------")
end

-- ========== SBP & TYPE HELPERS ==========

function Debug_ListCivs()
    Debug_Clear()
    Debug_Print("===================================================================")
    Debug_Print("  [CIV] CIVILIZATIONS IN SBP")
    Debug_Print("===================================================================")
    Debug_Print("")
    if not SBP then
        Debug_Print("[X] SBP table not found")
        return
    end
    local civs = {}
    for civName, _ in pairs(SBP) do
        table.insert(civs, civName)
    end
    table.sort(civs)
    for _, name in ipairs(civs) do
        Debug_Print("  " .. name)
    end
    Debug_Print("")
    Debug_Print("-------------------------------------------------------------------")
    Debug_Print("  Total: " .. #civs)
    Debug_Print("-------------------------------------------------------------------")
end

function Debug_SBPCiv(civName)
    Debug_Clear()
    if not SBP then
        Debug_Print("[X] SBP table not found")
        return
    end
    local civ = SBP[civName]
    if not civ then
        Debug_Print("[X] SBP." .. SafeToString(civName) .. " not found")
        Debug_Print("Use Debug_ListCivs() to see available civilizations")
        return
    end
    Debug_Print("===================================================================")
    Debug_Print("  [SBP] " .. SafeToString(civName) .. " BLUEPRINTS")
    Debug_Print("===================================================================")
    Debug_Print("")
    local items = {}
    for name, _ in pairs(civ) do
        table.insert(items, tostring(name))
    end
    table.sort(items)
    for _, name in ipairs(items) do
        Debug_Print("  " .. name)
    end
    Debug_Print("")
    Debug_Print("-------------------------------------------------------------------")
    Debug_Print("  Total: " .. #items)
    Debug_Print("-------------------------------------------------------------------")
end

function Debug_SearchTable(tableName, pattern)
    Debug_Clear()
    local t = _G[tableName]
    if type(t) ~= "table" then
        Debug_Print("[X] " .. SafeToString(tableName) .. " is not a table")
        return
    end
    Debug_Print("===================================================================")
    Debug_Print("  [?] SEARCH: " .. SafeToString(tableName) .. " for '" .. SafeToString(pattern) .. "'")
    Debug_Print("===================================================================")
    Debug_Print("")
    local pat = string.lower(SafeToString(pattern))
    local found = {}
    for k, v in pairs(t) do
        local kstr = tostring(k)
        if string.find(string.lower(kstr), pat, 1, true) then
            table.insert(found, {name = kstr, vtype = type(v)})
        end
    end
    table.sort(found, function(a, b) return a.name < b.name end)
    for _, item in ipairs(found) do
        local icon = item.vtype == "function" and "[F]" or item.vtype == "table" and "[T]" or "*"
        Debug_Print("  " .. icon .. " " .. item.name)
    end
    Debug_Print("")
    Debug_Print("-------------------------------------------------------------------")
    Debug_Print("  Found: " .. #found)
    Debug_Print("-------------------------------------------------------------------")
end

function Debug_SBPSearch(civName, pattern)
    Debug_Clear()
    if not SBP then
        Debug_Print("[X] SBP table not found")
        return
    end
    local civ = SBP[civName]
    if not civ then
        Debug_Print("[X] SBP." .. SafeToString(civName) .. " not found")
        return
    end
    Debug_Print("===================================================================")
    Debug_Print("  [?] SBP." .. SafeToString(civName) .. " matching '" .. SafeToString(pattern) .. "'")
    Debug_Print("===================================================================")
    Debug_Print("")
    local pat = string.lower(SafeToString(pattern))
    local found = {}
    for name, _ in pairs(civ) do
        if string.find(string.lower(tostring(name)), pat, 1, true) then
            table.insert(found, tostring(name))
        end
    end
    table.sort(found)
    for _, name in ipairs(found) do
        Debug_Print("  " .. name)
    end
    Debug_Print("")
    Debug_Print("-------------------------------------------------------------------")
    Debug_Print("  Found: " .. #found)
    Debug_Print("-------------------------------------------------------------------")
end

function Debug_ScarType(varName, var)
    local st = scartype(var)
    local typeName = "UNKNOWN (" .. tostring(st) .. ")"

    -- Check against known ST_ constants
    if st == ST_NIL then typeName = "ST_NIL"
    elseif ST_SGROUP and st == ST_SGROUP then typeName = "ST_SGROUP"
    elseif ST_EGROUP and st == ST_EGROUP then typeName = "ST_EGROUP"
    elseif ST_SQUAD and st == ST_SQUAD then typeName = "ST_SQUAD"
    elseif ST_ENTITY and st == ST_ENTITY then typeName = "ST_ENTITY"
    elseif ST_PLAYER and st == ST_PLAYER then typeName = "ST_PLAYER"
    elseif ST_PBG and st == ST_PBG then typeName = "ST_PBG"
    elseif ST_TABLE and st == ST_TABLE then typeName = "ST_TABLE"
    elseif ST_NUMBER and st == ST_NUMBER then typeName = "ST_NUMBER"
    elseif ST_STRING and st == ST_STRING then typeName = "ST_STRING"
    elseif ST_BOOLEAN and st == ST_BOOLEAN then typeName = "ST_BOOLEAN"
    elseif ST_FUNCTION and st == ST_FUNCTION then typeName = "ST_FUNCTION"
    elseif ST_MARKER and st == ST_MARKER then typeName = "ST_MARKER"
    elseif ST_SCARPOS and st == ST_SCARPOS then typeName = "ST_SCARPOS"
    end

    Debug_Print(SafeToString(varName) .. " = " .. typeName)
    return st
end

function Debug_ListScarTypes()
    Debug_Clear()
    Debug_Print("===================================================================")
    Debug_Print("  [ST] SCAR TYPE CONSTANTS")
    Debug_Print("===================================================================")
    Debug_Print("")

    local types = {"ST_NIL", "ST_SGROUP", "ST_EGROUP", "ST_SQUAD", "ST_ENTITY",
                   "ST_PLAYER", "ST_PBG", "ST_TABLE", "ST_NUMBER", "ST_STRING",
                   "ST_BOOLEAN", "ST_FUNCTION", "ST_MARKER", "ST_SCARPOS"}

    for _, name in ipairs(types) do
        local val = _G[name]
        if val ~= nil then
            Debug_Print("  [OK] " .. name .. " = " .. tostring(val))
        else
            Debug_Print("  [X] " .. name .. " (not defined)")
        end
    end

    Debug_Print("")
    Debug_Print("-------------------------------------------------------------------")
end

function Debug_ListPlayers()
    Debug_Clear()
    Debug_Print("===================================================================")
    Debug_Print("  [P] PLAYERS IN GAME")
    Debug_Print("===================================================================")
    Debug_Print("")

    local ok, count = pcall(World_GetPlayerCount)
    if not ok or not count then
        Debug_Print("[X] Can't get player count")
        return
    end

    for i = 1, count do
        local ok2, p = pcall(World_GetPlayerAt, i)
        if ok2 and p then
            local isAI = false
            local isLocal = false
            pcall(function() isAI = AI_IsLocalAIPlayer(p) end)
            pcall(function() isLocal = (p == Game_GetLocalPlayer()) end)

            local tag = isLocal and "[YOU]" or (isAI and "[AI]" or "[HUMAN]")
            Debug_Print("  " .. i .. ". Player " .. tag)
        end
    end

    Debug_Print("")
    Debug_Print("-------------------------------------------------------------------")
    Debug_Print("  Total: " .. count)
    Debug_Print("-------------------------------------------------------------------")
end

function Debug_FOWReveal()
    local ok, err = pcall(function()
        FOW_PlayerExploreAll(Game_GetLocalPlayer())
    end)
    if ok then
        Debug_Print("[OK] FOW Revealed")
    else
        Debug_Print("[X] FOW Reveal failed: " .. SafeToString(err))
    end
end

function Debug_FOWHide()
    local ok, err = pcall(function()
        FOW_UIUnRevealAll()
    end)
    if ok then
        Debug_Print("[OK] FOW Hidden")
    else
        Debug_Print("[X] FOW Hide failed: " .. SafeToString(err))
    end
end

function Debug_CameraPos()
    local ok, pos = pcall(Camera_GetCurrentTargetPos)
    if ok and pos then
        Debug_Print("Camera: X=" .. string.format("%.2f", pos.x) .. " Y=" .. string.format("%.2f", pos.y) .. " Z=" .. string.format("%.2f", pos.z))
    else
        Debug_Print("[X] Can't get camera position")
    end
end

function Debug_PlayerInfo()
    Debug_Clear()
    Debug_Print("===================================================================")
    Debug_Print("  [P] PLAYER INFO")
    Debug_Print("===================================================================")
    Debug_Print("")

    local ok, p = pcall(Game_GetLocalPlayer)
    if not ok or not p then
        Debug_Print("[X] Can't get local player")
        return
    end

    -- Get race/civ
    local raceName = "Unknown"
    pcall(function() raceName = Player_GetRaceName(p) end)
    Debug_Print("  Race: " .. SafeToString(raceName))

    -- Get age
    local age = 0
    pcall(function() age = Player_GetCurrentAge(p) end)
    local ageName = (age == 1 and "Dark") or (age == 2 and "Feudal") or (age == 3 and "Castle") or (age == 4 and "Imperial") or "Unknown"
    Debug_Print("  Age: " .. ageName .. " (" .. tostring(age) .. ")")

    Debug_Print("")
    Debug_Print("-------------------------------------------------------------------")
end

function Debug_Resources()
    Debug_Clear()
    Debug_Print("===================================================================")
    Debug_Print("  [$] RESOURCES")
    Debug_Print("===================================================================")
    Debug_Print("")

    local ok, p = pcall(Game_GetLocalPlayer)
    if not ok or not p then
        Debug_Print("[X] Can't get local player")
        return
    end

    local food, wood, gold, stone = 0, 0, 0, 0
    pcall(function() food = Player_GetResource(p, RT_Food) end)
    pcall(function() wood = Player_GetResource(p, RT_Wood) end)
    pcall(function() gold = Player_GetResource(p, RT_Gold) end)
    pcall(function() stone = Player_GetResource(p, RT_Stone) end)

    Debug_Print("  Food:  " .. string.format("%d", food))
    Debug_Print("  Wood:  " .. string.format("%d", wood))
    Debug_Print("  Gold:  " .. string.format("%d", gold))
    Debug_Print("  Stone: " .. string.format("%d", stone))

    Debug_Print("")
    Debug_Print("-------------------------------------------------------------------")
end

function Debug_GameInfo()
    Debug_Clear()
    Debug_Print("===================================================================")
    Debug_Print("  [G] GAME INFO")
    Debug_Print("===================================================================")
    Debug_Print("")

    local diff = -1
    pcall(function() diff = Game_GetSPDifficulty() end)
    local diffName = (diff == 0 and "Easy") or (diff == 1 and "Normal") or (diff == 2 and "Hard") or (diff == 3 and "Hardest") or "Unknown"
    Debug_Print("  Difficulty: " .. diffName .. " (" .. tostring(diff) .. ")")

    local isReplay = false
    pcall(function() isReplay = UI_IsReplay() end)
    Debug_Print("  Is Replay: " .. tostring(isReplay))

    local isRTM = false
    pcall(function() isRTM = Game_IsRTM() end)
    Debug_Print("  Is RTM: " .. tostring(isRTM))

    Debug_Print("")
    Debug_Print("-------------------------------------------------------------------")
end

function Debug_EventRunning()
    local running = false
    pcall(function() running = Event_IsAnyRunning() end)
    if running then
        Debug_Print("[!] Event/Cinematic IS running")
    else
        Debug_Print("[OK] No event running")
    end
    return running
end

function Debug_HasUpgrade(upgradeName)
    local ok, p = pcall(Game_GetLocalPlayer)
    if not ok or not p then
        Debug_Print("[X] Can't get local player")
        return false
    end

    local hasIt = false
    local ok2, bp = pcall(BP_GetUpgradeBlueprint, upgradeName)
    if not ok2 or not bp then
        Debug_Print("[X] Upgrade not found: " .. SafeToString(upgradeName))
        return false
    end

    pcall(function() hasIt = Player_HasUpgrade(p, bp) end)
    if hasIt then
        Debug_Print("[OK] Has upgrade: " .. SafeToString(upgradeName))
    else
        Debug_Print("[X] Missing upgrade: " .. SafeToString(upgradeName))
    end
    return hasIt
end

function Debug_GroupCount(groupName)
    local g = _G[groupName]
    if g == nil then
        Debug_Print("[X] Group not found: " .. SafeToString(groupName))
        return
    end

    local st = scartype(g)
    if ST_SGROUP and st == ST_SGROUP then
        local count = 0
        pcall(function() count = SGroup_Count(g) end)
        local spawned = 0
        pcall(function() spawned = SGroup_CountSpawned(g) end)
        Debug_Print("[SG] " .. SafeToString(groupName) .. ": " .. count .. " total, " .. spawned .. " spawned")
    elseif ST_EGROUP and st == ST_EGROUP then
        local count = 0
        pcall(function() count = EGroup_Count(g) end)
        local spawned = 0
        pcall(function() spawned = EGroup_CountSpawned(g) end)
        Debug_Print("[EG] " .. SafeToString(groupName) .. ": " .. count .. " total, " .. spawned .. " spawned")
    else
        Debug_Print("[?] " .. SafeToString(groupName) .. " is not SGroup or EGroup")
    end
end

function Debug_CmdLine(arg)
    local isSet = false
    pcall(function() isSet = Misc_IsCommandLineOptionSet(arg) end)
    if isSet then
        Debug_Print("[OK] CmdLine '" .. SafeToString(arg) .. "' is SET")
    else
        Debug_Print("[X] CmdLine '" .. SafeToString(arg) .. "' not set")
    end
    return isSet
end

-- Aliases
DebugShow = ShowDebugHUD
DebugHide = HideDebugHUD
DS = Debug_Search
DSA = Debug_SearchAdd
DE = Debug_Exists
DP = Debug_Print
DC = Debug_Clear
DFE = Debug_FuncExists
DBP = Debug_BPCheck
DSQ = Debug_SquadType
DTC = Debug_TryCall
DTB = Debug_TestBP
DT = Debug_Test
DLC = Debug_ListCivs
DSBP = Debug_SBPCiv
DST = Debug_SearchTable
DSBPS = Debug_SBPSearch
DSCT = Debug_ScarType
DLST = Debug_ListScarTypes
DLP = Debug_ListPlayers
DFOW = Debug_FOWReveal
DFOWH = Debug_FOWHide
DCAM = Debug_CameraPos
DPI = Debug_PlayerInfo
DRES = Debug_Resources
DGI = Debug_GameInfo
DER = Debug_EventRunning
DHU = Debug_HasUpgrade
DGC = Debug_GroupCount
DCL = Debug_CmdLine