-- =========================================================================
-- FILE: RecruitmentRequirements.lua
-- =========================================================================
local addonName, NS = ...

-- [FIX]: Do not attempt to index _G["GRS_MainFrame"] immediately.
-- The core frame may not exist yet if this file loads first.
local GR = nil 

-- =========================================================================
-- 1. DATABASE & CONSTANTS
-- =========================================================================

local REQ_DEFAULTS = {
    classes = {}, 
    races = {},   
    progressionN = {}, -- Normal
    progressionH = {}, -- Heroic
    progressionM = {}, -- Mythic
    servers = {},      -- New: Server Assignments [Realm] = { recruiter="", type="Social"|"Raid" }
    history = {}  
}

local PROGRESSION_STEPS = { "0/8", "1/8", "2/8", "3/8", "4/8", "5/8", "6/8", "7/8", "8/8" }

local CLASS_LIST = {
    "Death Knight", "Demon Hunter", "Druid", "Evoker", "Hunter", 
    "Mage", "Monk", "Paladin", "Priest", "Rogue", 
    "Shaman", "Warlock", "Warrior"
}

local RACE_LIST = {
    "Blood Elf", "Dark Iron Dwarf", "Dracthyr", "Draenei", "Dwarf", "Earthen", 
    "Gnome", "Goblin", "Highmountain Tauren", "Human", "Kul Tiran", 
    "Lightforged Draenei", "Mag'har Orc", "Mechagnome", "Night Elf", 
    "Nightborne", "Orc", "Pandaren", "Tauren", "Troll", "Undead", 
    "Void Elf", "Vulpera", "Worgen", "Zandalari Troll"
}
table.sort(RACE_LIST)

-- HUGE LIST OF REALMS (Truncated for common major realms per region for brevity/performance, expandable)
-- Region IDs: 1=US, 2=KR, 3=EU, 4=TW, 5=CN
local REALM_LISTS = {
    [1] = { -- US / NA / OCE
        "Aegwynn", "Aerie Peak", "Aggramar", "Alleria", "Altas", "Area 52", "Argent Dawn", "Arthas", "Azralon", "Azshara", 
        "Barthilas", "Black Dragonflight", "Blackhand", "Blackrock", "Bloodhoof", "Bonechewer", "Boulderfist", "Bronzebeard", "Burning Blade", 
        "Caelestrasz", "Cairne", "Cenarion Circle", "Cho'gall", "Dalaran", "Darkspear", "Darrowmere", "Dawnbringer", "Deathwing", "Demon Soul", 
        "Destromath", "Dethecus", "Draenor", "Dragonblight", "Drak'thul", "Durotan", "Eitrigg", "Emerald Dream", "Eonar", "Eredar", "Exodar", 
        "Farstriders", "Feathermoon", "Frostmane", "Frostmourne", "Frostwolf", "Galakrond", "Garithos", "Garona", "Garrosh", "Ghostlands", 
        "Gilneas", "Gnomeregan", "Gorefiend", "Gorgonnash", "Greymane", "Grizzly Hills", "Gul'dan", "Gurubashi", "Hakkar", "Haomarush", 
        "Hellscream", "Hydraxis", "Hyjal", "Icecrown", "Illidan", "Jaedenar", "Jubei'Thos", "Kael'thas", "Kalecgos", "Kargath", "Kel'Thuzad", 
        "Khadgar", "Khaz Modan", "Khaz'goroth", "Kil'jaeden", "Kilrogg", "Kirin Tor", "Korgath", "Kul Tiras", "Laughing Skull", "Lethon", 
        "Lightbringer", "Lightning's Blade", "Llane", "Lothar", "Madoran", "Maelstrom", "Magtheridon", "Maiev", "Mal'Ganis", "Malfurion", 
        "Malorne", "Malygos", "Mannoroth", "Medivh", "Misha", "Mok'Nathal", "MoonGuard", "Moonrunner", "Mug'thol", "Muradin", "Nagrand", 
        "Nazgrel", "Nazjatar", "Ner'zhul", "Nesingwary", "Nordrassil", "Norgannon", "Onyxia", "Perenolde", "Proudmoore", "Quel'Thalas", 
        "Ragnaros", "Ravencrest", "Ravenholdt", "Rexxar", "Runetotem", "Sargeras", "Saurfang", "Scarlet Crusade", "Scilla", "Sen'jin", 
        "Sentinels", "Shadow Council", "Shadowmoon", "Shadowsong", "Shandris", "Shattered Hand", "Shattered Halls", "Silver Hand", "Silvermoon", 
        "Sisters of Elune", "Skullcrusher", "Skywall", "Smolderthorn", "Spirestone", "Staghelm", "Steamwheedle Cartel", "Stormrage", "Stormreaver", 
        "Stormscale", "Suramar", "Tanaris", "Terenas", "Terokkar", "Thaurissan", "The Forgotten Coast", "The Scryers", "The Underbog", "The Venture Co", 
        "Thorium Brotherhood", "Thrall", "Thunderhorn", "Thunderlord", "Tichondrius", "Tortheldrin", "Trollbane", "Turalyon", "Twisting Nether", 
        "Uldaman", "Uldum", "Undermine", "Ursin", "Uther", "Vashj", "Vek'nilash", "Velen", "Warsong", "Whisperwind", "Wildhammer", "Windrunner", 
        "Winterhoof", "Wyrmrest Accord", "Ysera", "Ysondre", "Zangarmarsh", "Zul'jin", "Zuluhed"
    },
    [3] = { -- EU
        "Aegwynn", "Aerie Peak", "Agamaggan", "Aggramar", "Aahn'Qiraj", "Al'Akir", "Alexstrasza", "Alleria", "Alonsus", "Aman'Thul", "Ambossar", 
        "Anachronos", "Antonidas", "Arathor", "Archimonde", "Area 52", "Argent Dawn", "Arthas", "Arygos", "Aszune", "Auchindoun", "Azjol-Nerub", 
        "Azuremyst", "Baelgun", "Balnazzar", "Blackhand", "Blackmoore", "Blackrock", "Blackscar", "Blade's Edge", "Bladefist", "Bloodfeather", 
        "Bloodhoof", "Bloodscalp", "Blutkessel", "Boulderfist", "Bronzebeard", "Bronze Dragonflight", "Burning Blade", "Burning Legion", 
        "Burning Steppes", "C'Thun", "Chamber of Aspects", "Chogall", "Chromaggus", "Coliseum", "Confrérie du Thorium", "Conseil des Ombres", 
        "Crushridge", "Culte de la Rive Noire", "Daggerspine", "Dalaran", "Dalvengyr", "Darkmoon Faire", "Darksorrow", "Darkspear", "Das Konsortium", 
        "Das Syndikat", "Deathguard", "Deathweaver", "Deathwing", "Deepholm", "Defias Brotherhood", "Dentarg", "Der Mithrilorden", "Der Rat von Dalaran", 
        "Der abyssische Rat", "Destromath", "Dethecus", "Die Aldor", "Die Arguswacht", "Die Ewige Wacht", "Die Nachtwache", "Die Silberne Hand", 
        "Die Todeskrallen", "Doomhammer", "Draenor", "Dragonblight", "Dragonmaw", "Drak'thul", "Drek'Thar", "Dun Modr", "Dun Morogh", "Dunemaul", 
        "Durotan", "Earthen Ring", "Echsenkessel", "Eitrigg", "Eldre'Thalas", "Elune", "Emerald Dream", "Emeriss", "Eonar", "Eredar", "Eversong", 
        "Executus", "Exodar", "Festung der Stürme", "Fordragon", "Forscherliga", "Frostmane", "Frostmourne", "Frostwolf", "Galakrond", "Garona", 
        "Garrosh", "Genjuros", "Ghostlands", "Gilneas", "Goldrinn", "Gorgonnash", "Greymane", "Grim Batol", "Gul'dan", "Hakkar", "Haomarush", 
        "Hellfire", "Hellscream", "Howling Fjord", "Hyjal", "Illidan", "Jaedenar", "Kael'thas", "Karazhan", "Kargath", "Kazzak", "Kel'Thuzad", 
        "Khadgar", "Khaz Modan", "Khaz'goroth", "Kil'jaeden", "Kilrogg", "Kirin Tor", "Kor'gall", "Krag'jin", "Krasus", "Kul Tiras", "Kult der Verdammten", 
        "La Croisade écarte", "Laughing Skull", "Les Clairvoyants", "Les Sentinelles", "Lichtking", "Lightbringer", "Lightning's Blade", "Lordaeron", 
        "Los Errantes", "Lothar", "Madmortem", "Magtheridon", "Maiev", "Malfurion", "Mal'Ganis", "Malorne", "Malygos", "Mannoroth", "Marécage de Zangar", 
        "Mazrigos", "Medivh", "Minahonda", "Moonglade", "Mug'thol", "Nagrand", "Nathrezim", "Naxxramas", "Nazjatar", "Nefarian", "Nemesis", 
        "Neptulon", "Ner'zhul", "Nera'thor", "Nethersturm", "Nordrassil", "Norgannon", "Nozdormu", "Onyxia", "Outland", "Perenolde", "Pozzo dell'Eternità", 
        "Proudmoore", "Quel'Thalas", "Ragnaros", "Rajaxx", "Rashgarroth", "Ravencrest", "Ravenholdt", "Rexxar", "Runetotem", "Sanguino", "Sargeras", 
        "Saurfang", "Scarshield Legion", "Sen'jin", "Shadowsong", "Shattered Hand", "Shattered Halls", "Shattrath", "Shen'dralar", "Silvermoon", 
        "Sinstralis", "Skullcrusher", "Soulflayer", "Spinebreaker", "Spirestone", "Staghelm", "Steamwheedle Cartel", "Stormrage", "Stormreaver", 
        "Stormscale", "Sunstrider", "Suramar", "Sylvanas", "Taerar", "Talnivarr", "Tarren Mill", "Teldrassil", "Temple noir", "Terenas", "Terokkar", 
        "Terrordar", "The Maelstrom", "The Sha'tar", "The Venture Co", "Theradras", "Thrall", "Throk'Feroth", "Thunderhorn", "Tichondrius", 
        "Tirion", "Todeswache", "Trollbane", "Turalyon", "Twilight's Hammer", "Twisting Nether", "Tyrande", "Uldaman", "Ulduar", "Uldum", "Un'Goro", 
        "Varimathras", "Vashj", "Vek'nilash", "Velen", "Vol'jin", "Wildhammer", "Wrathbringer", "Xavius", "Ysera", "Ysondre", "Zenedar", "Zirkel des Cenarius", 
        "Zul'jin", "Zuluhed"
    },
    [2] = { "Azshara", "Borean Tundra", "Cenarius", "Dalaran", "Durotan", "Garona", "Gul'dan", "Hellas", "Hyjal", "Malfurion", "Norgannon", "Rexxar", "Stormrage", "Wildhammer", "Windrunner", "Zul'jin" },
    [4] = { "Arthas", "Bleeding Hollow", "Chillwind Point", "Crystalpine Stinger", "Demon Fall Canyon", "Dragonmaw", "Duskwood", "Frostmane", "Hellscream", "Icecrown", "Light's Hope", "Menethil", "Midnight", "Nightsong", "Order of the Cloud Serpent", "Quel'Dorei", "Shadowmoon", "Silverwing Hold", "Skywall", "Spirestone", "Stormscale", "Sundown Marsh", "Thorium Brotherhood", "Thunderlord", "Whisperwind", "World Tree", "Zealot Blade" },
    [5] = { "CN_Servers_Placeholder" } -- CN structure varies
}

-- [[ ISOLATION UPDATE ]]
-- Helper to get the correct DB bucket for the current guild
local function GetDB()
    -- [FIX]: Guard against GR being nil during early load
    if not GR then return nil end
    if not IsInGuild() then return nil end
    if not GR.GetGuildKey then return nil end
    
    local key = GR:GetGuildKey()
    
    -- Ensure root structure
    if not _G.GRS_DB.requirements then 
        _G.GRS_DB.requirements = {} 
    end
    
    -- Check for old flat structure (Migration/Wipe)
    if _G.GRS_DB.requirements.classes then
        _G.GRS_DB.requirements = {} -- Wipe old flat structure to enforce isolation
    end

    -- Create Guild Bucket if missing
    if not _G.GRS_DB.requirements[key] then
        _G.GRS_DB.requirements[key] = CopyTable(REQ_DEFAULTS)
    end
    
    local db = _G.GRS_DB.requirements[key]
    
    -- Ensure sub-tables exist (in case of schema updates)
    if not db.classes then db.classes = {} end
    if not db.races then db.races = {} end
    if not db.history then db.history = {} end
    if not db.servers then db.servers = {} end
    if type(db.progressionN) ~= "table" then db.progressionN = {} end
    if type(db.progressionH) ~= "table" then db.progressionH = {} end
    if type(db.progressionM) ~= "table" then db.progressionM = {} end
    
    return db
end

local function GetGuildNameStr()
    local guildName = GetGuildInfo("player")
    return guildName or "THE EXILES" 
end

-- =========================================================================
-- 2. LOCAL HELPERS (Visuals)
-- =========================================================================

local function CreateBlackBg(f)
    -- 1. Background: Black @ 75% opacity
    if NS.CreateBg then
        NS.CreateBg(f, 0, 0, 0, 0.75)
    else
        local t = f:CreateTexture(nil, "BACKGROUND")
        t:SetAllPoints()
        t:SetColorTexture(0, 0, 0, 0.75)
        f.bg = t
    end
    
    -- 2. Border: Thin 1px Black (Consistent with UI_Shared)
    if NS.CreateBorder then
        NS.CreateBorder(f, 0, 0, 0, 1)
    else
        if f.border and not f.border.SetBackdrop then f.border:Hide(); f.border = nil end
        
        if not f.border then
            local border = CreateFrame("Frame", nil, f, "BackdropTemplate")
            border:SetAllPoints()
            border:SetBackdrop({
                bgFile = nil,
                edgeFile = "Interface\\Buttons\\WHITE8x8",
                edgeSize = 1,
            })
            f.border = border
        end
        f.border:SetBackdropBorderColor(0, 0, 0, 1)
    end
end

-- [[ NEW: BLACK RECTANGULAR BUTTON STYLE ]]
local function StyleActionButton(btn)
    -- Strip Standard Textures
    btn:SetNormalTexture("")
    btn:SetHighlightTexture("")
    btn:SetPushedTexture("")
    btn:SetDisabledTexture("")
    
    -- Cleanup standard template regions if they exist
    if btn.Left then btn.Left:SetAlpha(0) end
    if btn.Middle then btn.Middle:SetAlpha(0) end
    if btn.Right then btn.Right:SetAlpha(0) end
    
    -- Background: Solid Black (100% Opacity)
    if NS.CreateBg then 
        NS.CreateBg(btn, 0, 0, 0, 1) 
    else
        local t = btn:CreateTexture(nil, "BACKGROUND")
        t:SetAllPoints()
        t:SetColorTexture(0, 0, 0, 1)
        btn.bg = t
    end
    
    -- Border: Dark Grey (to define the rectangle against other black elements)
    if NS.CreateBorder then 
        NS.CreateBorder(btn, 0.3, 0.3, 0.3, 1) 
    end
    
    -- Text: White
    local fs = btn:GetFontString()
    if fs then fs:SetTextColor(1, 1, 1) end
    
    -- Interactivity
    btn:HookScript("OnEnter", function(s) 
        if s.bg then s.bg:SetColorTexture(0.2, 0.2, 0.2, 1) end 
    end)
    btn:HookScript("OnLeave", function(s) 
        if s.bg then s.bg:SetColorTexture(0, 0, 0, 1) end 
    end)
    btn:HookScript("OnMouseDown", function(s) 
        if s.bg then s.bg:SetColorTexture(0.1, 0.1, 0.1, 1) end 
    end)
    btn:HookScript("OnMouseUp", function(s) 
        if s.bg then s.bg:SetColorTexture(0.2, 0.2, 0.2, 1) end 
    end)
end

local function CreateColoredCheckbox(parent, colorType, onClick)
    local cb = CreateFrame("CheckButton", nil, parent, "UICheckButtonTemplate")
    cb:SetSize(20, 20)
    
    local r, g, b = 1, 1, 1
    if colorType == "L" then r,g,b = 0, 1, 0         -- Green
    elseif colorType == "M" then r,g,b = 1, 0.5, 0   -- Orange
    elseif colorType == "H" then r,g,b = 1, 0, 0     -- Red
    end
    
    cb:GetCheckedTexture():SetVertexColor(r, g, b)
    
    local bg = cb:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints(cb)
    bg:SetColorTexture(0, 0, 0, 1)
    
    cb:SetScript("OnClick", function(self) onClick(self:GetChecked()) end)
    return cb
end

-- =========================================================================
-- 3. SYNC ENGINE
-- =========================================================================

local function AddHistoryEntry(author, description)
    local db = GetDB()
    if not db then return end
    
    local h = { ts = GetServerTime(), author = author, desc = description }
    table.insert(db.history, 1, h)
    if #db.history > 50 then
        table.remove(db.history)
    end
    if GR and GR.ReqHistoryFrame and GR.ReqHistoryFrame:IsShown() and GR.UpdateHistoryList then
        GR:UpdateHistoryList()
    end
end

-- Sends a single update immediately
local function SendSyncAction(category, key, value)
    if not IsInGuild() then return end
    if not GR then return end -- Safety
    local msg = string.format("%s:%s:%s", category, key, tostring(value))
    GR:SafeSendAddonMessage("GRS_REQ", msg, "GUILD")
end

-- Handles incoming messages
local function OnCommReceived(prefix, text, channel, sender)
    if prefix ~= "GRS_REQ" then return end
    if sender == UnitName("player") then return end
    
    -- ISOLATION: Get current guild bucket
    local db = GetDB()
    if not db then return end
    
    -- Split by pipe to handle bulk messages
    local entries = { strsplit("|", text) }
    local updates = 0

    for _, rawMsg in ipairs(entries) do
        local cat, key, val = strsplit(":", rawMsg)
        
        if cat and key then
            local desc = ""
            
            if cat == "CLASS" then
                local pVal = (val == "nil") and nil or val
                db.classes[key] = pVal
                desc = pVal and string.format("Set Class %s to Priority %s", key, pVal) or string.format("Closed recruitment for %s", key)
                
            elseif cat == "RACE" then
                local bVal = (val == "true")
                db.races[key] = bVal
                desc = string.format("%s Race %s", bVal and "Enabled" or "Disabled", key)
                
            elseif cat == "PROG_N" then
                local bVal = (val == "true")
                db.progressionN[key] = bVal
                desc = string.format("Normal Raid: %s %s", key, bVal and "Selected" or "Deselected")
            elseif cat == "PROG_H" then
                local bVal = (val == "true")
                db.progressionH[key] = bVal
                desc = string.format("Heroic Raid: %s %s", key, bVal and "Selected" or "Deselected")
            elseif cat == "PROG_M" then
                local bVal = (val == "true")
                db.progressionM[key] = bVal
                desc = string.format("Mythic Raid: %s %s", key, bVal and "Selected" or "Deselected")
                
            elseif cat == "SERVER" then
                -- Value format: "RecruiterName|Type" or "nil"
                if val == "nil" then
                    db.servers[key] = nil
                    desc = string.format("Removed recruiter from server: %s", key)
                else
                    local rec, rType = strsplit("~", val) -- Using ~ as sub-delimiter for safety, though pipe | is used for batching
                     -- Fallback for older sync logic if any
                    if not rType then rec, rType = strsplit("%", val) end 
                    
                    db.servers[key] = { recruiter = rec, type = rType }
                    desc = string.format("Assigned %s to %s (%s)", rec, key, rType)
                end
            end
            
            if desc ~= "" then
                AddHistoryEntry(sender, desc)
                updates = updates + 1
            end
        end
    end

    if updates > 0 and GR and GR.RefreshReqUI then 
        GR:RefreshReqUI() 
    end
end

local eqFrame = CreateFrame("Frame")
eqFrame:RegisterEvent("CHAT_MSG_ADDON")
eqFrame:SetScript("OnEvent", function(self, event, ...)
    local prefix = ...
    if prefix == "GRS_REQ" then OnCommReceived(...) end
end)
C_ChatInfo.RegisterAddonMessagePrefix("GRS_REQ")

-- =========================================================================
-- 4. HISTORY WINDOW
-- =========================================================================

-- [FIX]: Converted to local function to allow delayed injection
local function BuildHistoryWindow(self)
    if GR.ReqHistoryFrame then return end

    local f = CreateFrame("Frame", "GRS_HistoryFrame", UIParent, "BackdropTemplate")
    f:SetSize(400, 500)
    f:SetPoint("CENTER")
    f:SetFrameStrata("FULLSCREEN_DIALOG") 
    f:EnableMouse(true)
    f:SetMovable(true)
    f:RegisterForDrag("LeftButton")
    f:SetScript("OnDragStart", f.StartMoving)
    f:SetScript("OnDragStop", f.StopMovingOrSizing)
    
    f:SetBackdrop({
        bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
        edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
        tile = true, tileSize = 32, edgeSize = 32,
        insets = { left = 11, right = 12, top = 12, bottom = 11 }
    })
    f:SetBackdropColor(0, 0, 0, 1)
    f:Hide()
    
    local title = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("TOP", 0, -15); title:SetText(NS.L["REQUIREMENT_AUDIT_LOG"] or "Requirement Audit Log")
    
    local close = CreateFrame("Button", nil, f, "UIPanelCloseButton")
    close:SetPoint("TOPRIGHT", -5, -5)
    
    local sf = CreateFrame("ScrollFrame", "GRS_HistScroll", f, "UIPanelScrollFrameTemplate")
    sf:SetPoint("TOPLEFT", 15, -50); sf:SetPoint("BOTTOMRIGHT", -30, 15)
    if NS.StyleScrollBar then NS.StyleScrollBar(sf) end
    
    local content = CreateFrame("Frame", nil, sf)
    content:SetSize(355, 400)
    sf:SetScrollChild(content)
    
    f.lines = {}
    
    GR.UpdateHistoryList = function()
        local db = GetDB()
        if not db then return end
        
        local h = db.history
        local y = 0
        for _, line in ipairs(f.lines) do line:Hide() end
        
        for i, entry in ipairs(h) do
            local frame = f.lines[i]
            if not frame then
                frame = CreateFrame("Frame", nil, content)
                frame:SetSize(350, 40)
                
                frame.ts = frame:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
                frame.ts:SetPoint("TOPLEFT", 0, 0)
                
                frame.txt = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
                frame.txt:SetPoint("TOPLEFT", 0, -12)
                frame.txt:SetWidth(350); frame.txt:SetJustifyH("LEFT")
                
                local div = frame:CreateTexture(nil, "ARTWORK")
                div:SetColorTexture(0.2, 0.2, 0.2, 1); div:SetHeight(1)
                div:SetPoint("BOTTOMLEFT"); div:SetPoint("BOTTOMRIGHT")
                
                f.lines[i] = frame
            end
            frame:SetPoint("TOPLEFT", 0, y)
            frame:Show()
            local dateStr = date("%Y-%m-%d %H:%M", entry.ts)
            frame.ts:SetText(dateStr .. " - " .. (entry.author or "Unknown"))
            frame.txt:SetText(entry.desc)
            y = y - 45
        end
        content:SetHeight(math.abs(y))
    end
    
    GR.ReqHistoryFrame = f
end

-- =========================================================================
-- 5. POPUP DIALOG (SERVER ASSIGNMENT)
-- =========================================================================

local function CreateServerAssignmentPopup()
    local f = CreateFrame("Frame", "GRS_ServerPopup", UIParent, "BackdropTemplate")
    f:SetSize(300, 200)
    f:SetPoint("CENTER")
    f:SetFrameStrata("FULLSCREEN_DIALOG")
    f:EnableMouse(true)
    f:Hide()
    
    f:SetBackdrop({
        bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
        edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
        tile = true, tileSize = 32, edgeSize = 32,
        insets = { left = 11, right = 12, top = 12, bottom = 11 }
    })
    f:SetBackdropColor(0, 0, 0, 1)

    f.title = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    f.title:SetPoint("TOP", 0, -15)
    f.title:SetText(NS.L["RECRUITER_ASSIGNED"] or "Recruiter Assigned")

    -- Server Name Label
    f.serverLbl = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightMedium")
    f.serverLbl:SetPoint("TOP", 0, -40)
    
    -- Recruiter Input
    local edit = CreateFrame("EditBox", nil, f, "InputBoxTemplate")
    edit:SetSize(180, 30)
    edit:SetPoint("TOP", 0, -70)
    edit:SetAutoFocus(false)
    f.editRecruiter = edit

    local lblRec = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    lblRec:SetPoint("BOTTOMLEFT", edit, "TOPLEFT", 0, 2)
    lblRec:SetText(NS.L["RECRUITER_NAME"] or "Recruiter Name:")

    -- Radio Buttons (Raid vs Social)
    local cbRaid = CreateFrame("CheckButton", nil, f, "UIRadioButtonTemplate")
    cbRaid:SetPoint("TOPLEFT", edit, "BOTTOMLEFT", 0, -15)
    cbRaid.text = cbRaid:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    cbRaid.text:SetPoint("LEFT", cbRaid, "RIGHT", 5, 0)
    cbRaid.text:SetText(NS.L["RAID"] or "Raid")

    local cbSocial = CreateFrame("CheckButton", nil, f, "UIRadioButtonTemplate")
    cbSocial:SetPoint("LEFT", cbRaid, "RIGHT", 70, 0)
    cbSocial.text = cbSocial:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    cbSocial.text:SetPoint("LEFT", cbSocial, "RIGHT", 5, 0)
    cbSocial.text:SetText(NS.L["SOCIAL"] or "Social")

    -- Mutually Exclusive Logic
    cbRaid:SetScript("OnClick", function()
        cbSocial:SetChecked(false)
        cbRaid:SetChecked(true)
    end)
    cbSocial:SetScript("OnClick", function()
        cbRaid:SetChecked(false)
        cbSocial:SetChecked(true)
    end)
    
    f.cbRaid = cbRaid
    f.cbSocial = cbSocial

    -- Buttons
    local btnOK = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    btnOK:SetSize(80, 25)
    btnOK:SetPoint("BOTTOMLEFT", 40, 20)
    btnOK:SetText(NS.L["OK"] or "OK")
    
    local btnCancel = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    btnCancel:SetSize(80, 25)
    btnCancel:SetPoint("BOTTOMRIGHT", -40, 20)
    btnCancel:SetText(NS.L["CANCEL"] or "Cancel")
    btnCancel:SetScript("OnClick", function() f:Hide() end)

    f.targetRealm = nil

    btnOK:SetScript("OnClick", function()
        local realm = f.targetRealm
        local name = edit:GetText()
        local rType = cbRaid:GetChecked() and "Raid" or "Social"
        
        local db = GetDB()
        if not db then return end

        if name and name ~= "" then
            -- Save
            local val = { recruiter = name, type = rType }
            db.servers[realm] = val
            
            -- Sync format uses ~ as internal delimiter for the value
            local syncVal = name .. "~" .. rType
            SendSyncAction("SERVER", realm, syncVal)
        else
            -- Clear if empty
            db.servers[realm] = nil
            SendSyncAction("SERVER", realm, "nil")
        end
        
        if GR and GR.RefreshReqUI then GR:RefreshReqUI() end
        f:Hide()
    end)
    
    return f
end

-- =========================================================================
-- 6. MAIN TAB CONSTRUCTION
-- =========================================================================

-- [FIX]: Converted to local function for delayed injection
local function BuildRequirementsView(self, parent)
    -- Init Check
    if not GetDB() then return end
    
    for _, region in ipairs({parent:GetRegions()}) do
        if region:GetObjectType() == "FontString" then region:Hide() end
    end
    if parent.container then parent.container:Hide() end
    
    local container = CreateFrame("Frame", nil, parent)
    container:SetAllPoints()
    -- [[ CLIPPING ENABLED: "SLIDER DOOR" EFFECT ]]
    container:SetClipsChildren(true)
    parent.container = container
    
    -- ===========================
    -- COLUMN 1: CLASS PRIORITY
    -- ===========================
    local col1 = CreateFrame("Frame", nil, container)
    col1:SetPoint("TOPLEFT", 10, -60)
    col1:SetPoint("BOTTOMLEFT", 10, 90) 
    col1:SetWidth(300) -- Shrunk slightly to fit 6th pane
    CreateBlackBg(col1)
    
    local h1 = col1:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    h1:SetPoint("TOPLEFT", 10, -10); h1:SetText(NS.L["CLASS_PRIORITY"] or "Class Priority")
    
    local lblClass = col1:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    lblClass:SetPoint("TOPLEFT", 10, -40); lblClass:SetText(NS.L["CLASS"] or "Class")
    
    local lblL = col1:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    lblL:SetPoint("TOPRIGHT", -90, -40); lblL:SetText(NS.L["LOW"] or "Low"); lblL:SetTextColor(0, 1, 0)
    
    local lblM = col1:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    lblM:SetPoint("TOPRIGHT", -50, -40); lblM:SetText(NS.L["MED"] or "Med"); lblM:SetTextColor(1, 0.5, 0)
    
    local lblH = col1:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    lblH:SetPoint("TOPRIGHT", -10, -40); lblH:SetText(NS.L["HIGH"] or "High"); lblH:SetTextColor(1, 0, 0)
    
    GR.reqClassRows = {}
    local cy = -65
    
    for _, cls in ipairs(CLASS_LIST) do
        local row = CreateFrame("Frame", nil, col1)
        row:SetSize(280, 24)
        row:SetPoint("TOPLEFT", 10, cy)
        
        row.name = row:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
        row.name:SetPoint("LEFT", 0, 0); row.name:SetText(cls)
        
        local function UpdateClassDB(priority)
            local db = GetDB()
            if not db then return end
            if db.classes[cls] == priority then db.classes[cls] = nil else db.classes[cls] = priority end
            SendSyncAction("CLASS", cls, tostring(db.classes[cls]))
            if GR.RefreshReqUI then GR:RefreshReqUI() end
        end
        
        row.cbL = CreateColoredCheckbox(row, "L", function() UpdateClassDB("L") end)
        row.cbL:SetPoint("RIGHT", -90, 0)
        
        row.cbM = CreateColoredCheckbox(row, "M", function() UpdateClassDB("M") end)
        row.cbM:SetPoint("RIGHT", -50, 0)
        
        row.cbH = CreateColoredCheckbox(row, "H", function() UpdateClassDB("H") end)
        row.cbH:SetPoint("RIGHT", -10, 0)
        
        GR.reqClassRows[cls] = row
        cy = cy - 28
    end
    
    -- ===========================
    -- COLUMN 2: RACE PRIORITY
    -- ===========================
    local col2 = CreateFrame("Frame", nil, container)
    col2:SetPoint("TOPLEFT", col1, "TOPRIGHT", 10, 0)
    col2:SetPoint("BOTTOMLEFT", col1, "BOTTOMRIGHT", 10, 0)
    col2:SetWidth(150)
    CreateBlackBg(col2)
    
    local h2 = col2:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    h2:SetPoint("TOPLEFT", 10, -10); h2:SetText(NS.L["RACE_SELECT"] or "Race Select")
    
    local scrollR = CreateFrame("ScrollFrame", "GRS_ReqRaceScroll", col2, "UIPanelScrollFrameTemplate")
    scrollR:SetPoint("TOPLEFT", 5, -40); scrollR:SetPoint("BOTTOMRIGHT", -25, 5)
    if NS.StyleScrollBar then NS.StyleScrollBar(scrollR) end
    
    local contentR = CreateFrame("Frame", nil, scrollR)
    contentR:SetSize(120, #RACE_LIST * 25)
    scrollR:SetScrollChild(contentR)
    
    GR.reqRaceRows = {}
    local ry = 0
    for _, race in ipairs(RACE_LIST) do
        local cb = CreateFrame("CheckButton", nil, contentR, "UICheckButtonTemplate")
        cb:SetSize(20, 20); cb:SetPoint("TOPLEFT", 5, ry)
        
        cb.text = cb:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
        cb.text:SetPoint("LEFT", cb, "RIGHT", 5, 0); cb.text:SetText(race)
        
        cb:SetScript("OnClick", function(self)
            local checked = self:GetChecked()
            local db = GetDB()
            if db then
                db.races[race] = checked
                SendSyncAction("RACE", race, tostring(checked))
            end
        end)
        
        GR.reqRaceRows[race] = cb
        ry = ry - 25
    end
    
    -- ===========================
    -- COLUMNS 3-5: RAID PROGRESSION (N/H/M)
    -- ===========================
    
    GR.reqProgRows = { N = {}, H = {}, M = {} }
    
    -- Helper to build columns
    local function BuildProgressionColumn(anchorFrame, title, dbKey, syncTag, color)
        local frame = CreateFrame("Frame", nil, container)
        frame:SetPoint("TOPLEFT", anchorFrame, "TOPRIGHT", 10, 0)
        frame:SetPoint("BOTTOM", anchorFrame, "BOTTOM", 0, 0)
        frame:SetWidth(110)
        CreateBlackBg(frame)
        
        local h = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        h:SetPoint("TOPLEFT", 10, -10)
        h:SetText(title)
        if color then h:SetTextColor(unpack(color)) end
        
        local py = -40
        for _, step in ipairs(PROGRESSION_STEPS) do
            local cb = CreateFrame("CheckButton", nil, frame, "UICheckButtonTemplate")
            cb:SetSize(20, 20); cb:SetPoint("TOPLEFT", 10, py)
            
            cb.text = cb:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
            cb.text:SetPoint("LEFT", cb, "RIGHT", 5, 0); cb.text:SetText(step)
            
            cb:SetScript("OnClick", function(self)
                local checked = self:GetChecked()
                local db = GetDB()
                if db then
                    if dbKey == "N" then db.progressionN[step] = checked end
                    if dbKey == "H" then db.progressionH[step] = checked end
                    if dbKey == "M" then db.progressionM[step] = checked end
                    SendSyncAction(syncTag, step, tostring(checked))
                end
            end)
            
            GR.reqProgRows[dbKey][step] = cb
            py = py - 25
        end
        return frame
    end
    
    local colN = BuildProgressionColumn(col2, NS.L["NORMAL"] or "Normal", "N", "PROG_N", {0, 1, 0})
    local colH = BuildProgressionColumn(colN, NS.L["HEROIC"] or "Heroic", "H", "PROG_H", {0, 0.7, 1})
    local colM = BuildProgressionColumn(colH, NS.L["MYTHIC"] or "Mythic", "M", "PROG_M", {1, 0.5, 0})
    
    -- ===========================
    -- COLUMN 6: SERVER MANAGEMENT (NEW)
    -- ===========================
    local colS = CreateFrame("Frame", nil, container)
    colS:SetPoint("TOPLEFT", colM, "TOPRIGHT", 10, 0)
    colS:SetPoint("BOTTOM", colM, "BOTTOM", 0, 0)
    colS:SetWidth(260) -- INCREASED from 200 to 260
    CreateBlackBg(colS)

    local regionID = GetCurrentRegion()
    local regionName = "Unknown"
    if regionID == 1 then regionName = NS.L["US_SERVERS"] or "US Servers"
    elseif regionID == 2 then regionName = NS.L["KR_SERVERS"] or "KR Servers"
    elseif regionID == 3 then regionName = NS.L["EU_SERVERS"] or "EU Servers"
    elseif regionID == 4 then regionName = NS.L["TW_SERVERS"] or "TW Servers"
    elseif regionID == 5 then regionName = NS.L["CN_SERVERS"] or "CN Servers" end

    local hS = colS:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    hS:SetPoint("TOPLEFT", 10, -10); hS:SetText(regionName)
    hS:SetTextColor(1, 0.82, 0) -- Gold Title

    local scrollS = CreateFrame("ScrollFrame", "GRS_ServerScroll", colS, "UIPanelScrollFrameTemplate")
    scrollS:SetPoint("TOPLEFT", 5, -40); scrollS:SetPoint("BOTTOMRIGHT", -25, 5)
    if NS.StyleScrollBar then NS.StyleScrollBar(scrollS) end

    local serverList = REALM_LISTS[regionID] or REALM_LISTS[3] -- Fallback to EU if unknown
    table.sort(serverList)

    local contentS = CreateFrame("Frame", nil, scrollS)
    contentS:SetSize(230, #serverList * 20) -- INCREASED Width to match colS
    scrollS:SetScrollChild(contentS)

    GR.serverRows = {}
    
    -- Popup Init
    local serverPopup = CreateServerAssignmentPopup()

    local sy = 0
    for _, realm in ipairs(serverList) do
        local btn = CreateFrame("Button", nil, contentS)
        btn:SetSize(235, 20) -- INCREASED Width to fill
        btn:SetPoint("TOPLEFT", 0, sy)
        
        -- Background for hover
        local bg = btn:CreateTexture(nil, "BACKGROUND")
        bg:SetAllPoints()
        bg:SetColorTexture(1, 0.82, 0, 0.3) -- Gold 30% alpha
        bg:Hide()
        btn.bg = bg

        local text = btn:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        text:SetPoint("LEFT", 5, 0)
        text:SetText(realm)
        btn.text = text

        btn:SetScript("OnEnter", function(self)
            self.bg:Show()
        end)
        btn:SetScript("OnLeave", function(self)
            self.bg:Hide()
        end)
        
        btn:SetScript("OnClick", function(self)
            local db = GetDB()
            if not db then return end
            
            -- Open Popup
            serverPopup.targetRealm = realm
            serverPopup.serverLbl:SetText(realm)
            
            local sData = db.servers[realm]
            if sData then
                serverPopup.editRecruiter:SetText(sData.recruiter or "")
                serverPopup.cbRaid:SetChecked(sData.type == "Raid")
                serverPopup.cbSocial:SetChecked(sData.type == "Social")
            else
                serverPopup.editRecruiter:SetText("")
                serverPopup.cbRaid:SetChecked(true)
                serverPopup.cbSocial:SetChecked(false)
            end
            
            serverPopup:Show()
        end)

        GR.serverRows[realm] = btn
        sy = sy - 20
    end
    
    -- ===========================
    -- FOOTER & AUDIT
    -- ===========================
    
    local btnAudit = CreateFrame("Button", nil, container, "UIPanelButtonTemplate")
    btnAudit:SetSize(150, 30)
    btnAudit:SetPoint("TOPLEFT", col1, "BOTTOMLEFT", 0, -5)
    btnAudit:SetText(NS.L["VIEW_AUDIT_LOG"] or "View Audit Log")
    StyleActionButton(btnAudit) -- Apply Black Rectangular Style
    
    btnAudit:SetScript("OnClick", function()
        if not GR.ReqHistoryFrame then 
            GR:BuildHistoryWindow() 
        end
        
        if GR.ReqHistoryFrame then
            GR:UpdateHistoryList()
            GR.ReqHistoryFrame:Show()
        end
    end)
    
    local btnSync = CreateFrame("Button", nil, container, "UIPanelButtonTemplate")
    btnSync:SetSize(150, 30)
    btnSync:SetPoint("LEFT", btnAudit, "RIGHT", 10, 0)
    btnSync:SetText(NS.L["SYNC_WITH_GUILD"] or "Sync with Guild")
    StyleActionButton(btnSync) -- Apply Black Rectangular Style
    
    btnSync:SetScript("OnClick", function()
        GR:SyncRequirements()
    end)
    
    -- [[ FIXED ANCHOR: Guild Name MOVED TO TOP LEFT ]]
    local gName = container:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
    gName:SetPoint("TOPLEFT", 10, -35) -- Above Class Priority Panel
    gName:SetText(string.upper(GetGuildNameStr()))
    gName:SetTextColor(1, 0.82, 0, 1) -- Golden
    
    GR.RefreshReqUI = function()
        local db = GetDB()
        if not db then return end
        
        -- Classes
        for cls, row in pairs(GR.reqClassRows) do
            local val = db.classes[cls]
            row.cbL:SetChecked(val == "L")
            row.cbM:SetChecked(val == "M")
            row.cbH:SetChecked(val == "H")
        end
        
        -- Races
        for race, cb in pairs(GR.reqRaceRows) do
            cb:SetChecked(db.races[race] == true)
        end
        
        -- Progression
        for step, cb in pairs(GR.reqProgRows.N) do cb:SetChecked(db.progressionN[step] == true) end
        for step, cb in pairs(GR.reqProgRows.H) do cb:SetChecked(db.progressionH[step] == true) end
        for step, cb in pairs(GR.reqProgRows.M) do cb:SetChecked(db.progressionM[step] == true) end
        
        -- Servers (Pane 6 Update)
        for realm, btn in pairs(GR.serverRows) do
            local sData = db.servers[realm]
            if sData and sData.recruiter then
                btn.text:SetText(realm .. " |cff00ff00[" .. sData.recruiter .. "]|r")
            else
                btn.text:SetText(realm)
            end
        end
        
        gName:SetText(string.upper(GetGuildNameStr()))
    end
    
    GR:RefreshReqUI()
end

-- =========================================================================
-- 7. LOGIC & INITIALIZATION HOOK
-- =========================================================================

-- [FIX]: Converted to local function for delayed injection
local function AutoRegisterServer(self)
    if not IsInGuild() then return end
    
    -- Check for Officer permissions (CanEditOfficerNote is the standard check)
    if not C_GuildInfo.CanEditOfficerNote() then return end
    
    local realm = GetRealmName()
    local myself, myRealm = UnitFullName("player")
    local myCanonical = myself .. "-" .. (myRealm or "")
    local recruiterName = myself -- Default fallback
    
    -- Attempt to resolve Main Identity from GRS_IdentityDB
    if _G.GRS_IdentityDB then
        if _G.GRS_IdentityDB.alts and _G.GRS_IdentityDB.alts[myCanonical] then
            -- I am an alt, get my parent
            local parent = _G.GRS_IdentityDB.alts[myCanonical]
            recruiterName = strsplit("-", parent) -- Strip realm
        elseif _G.GRS_IdentityDB.accountMain then
            -- Use locally stored account main if available
            recruiterName = strsplit("-", _G.GRS_IdentityDB.accountMain)
        end
        -- If I am a main (in .mains) or unknown, recruiterName remains 'myself'
    end

    local db = GetDB()
    if not db then return end
    local entry = db.servers[realm]
    
    if not entry then
        -- New Entry for this realm
        db.servers[realm] = { recruiter = recruiterName, type = "Social" }
        SendSyncAction("SERVER", realm, recruiterName .. "~Social")
        print("GRS: Auto-assigned " .. recruiterName .. " to " .. realm)
    else
        -- Entry exists, check if name is present
        local current = entry.recruiter or ""
        local found = false
        
        -- Split by '&' and trim whitespace to check exact name match
        for part in string.gmatch(current, "[^&]+") do
            if strtrim(part) == recruiterName then 
                found = true 
                break 
            end
        end
        
        if not found then
            -- Append name
            local newVal = current .. " & " .. recruiterName
            entry.recruiter = newVal
            local rType = entry.type or "Social"
            SendSyncAction("SERVER", realm, newVal .. "~" .. rType)
            print("GRS: Added " .. recruiterName .. " to recruiter list for " .. realm)
        end
    end
end

-- [FIX]: Converted to local function for delayed injection
local function SyncRequirements(self)
    if not IsInGuild() then
        print("GRS: You must be in a guild to sync.")
        return
    end
    print("GRS: Sending recruitment requirements to guild...")

    local db = GetDB()
    if not db then return end
    
    local batch = ""
    local count = 0

    local function Append(cat, k, v)
         -- format: CAT:KEY:VAL
         local str = string.format("%s:%s:%s", cat, k, tostring(v))
         
         -- Check if adding this entry exceeds 240 chars (safe limit for addons)
         if #batch + #str + 1 > 240 then
             GR:SafeSendAddonMessage("GRS_REQ", batch, "GUILD")
             batch = str
         else
             if batch == "" then batch = str else batch = batch .. "|" .. str end
         end
         count = count + 1
    end

    -- 1. Sync Classes
    for cls, p in pairs(db.classes) do 
        if p then Append("CLASS", cls, p) end
    end
    
    -- 2. Sync Races
    for race, b in pairs(db.races) do 
        if b then Append("RACE", race, b) end 
    end
    
    -- 3. Sync Progression
    for step, b in pairs(db.progressionN) do if b then Append("PROG_N", step, b) end end
    for step, b in pairs(db.progressionH) do if b then Append("PROG_H", step, b) end end
    for step, b in pairs(db.progressionM) do if b then Append("PROG_M", step, b) end end
    
    -- 4. Sync Servers (New)
    for realm, sData in pairs(db.servers) do
        if sData and sData.recruiter then
            local val = sData.recruiter .. "~" .. (sData.type or "Social")
            Append("SERVER", realm, val)
        end
    end

    -- Send remaining buffer
    if batch ~= "" then 
        GR:SafeSendAddonMessage("GRS_REQ", batch, "GUILD") 
    end
    
    print("GRS: Sent " .. count .. " requirement settings.")
end

-- =========================================================================
-- 8. EVENT-DRIVEN INITIALIZATION (The "Cold Boot" Fix)
-- =========================================================================

local initFrame = CreateFrame("Frame")
initFrame:RegisterEvent("PLAYER_LOGIN")
initFrame:SetScript("OnEvent", function(self, event)
    -- Now that the player has logged in, we can safely assume the Core has loaded
    -- (if it exists) and GRS_MainFrame is available in the global scope.
    GR = _G["GRS_MainFrame"]

    if GR then
        -- Inject the local functions into the main object
        GR.BuildHistoryWindow = BuildHistoryWindow
        GR.BuildRequirementsView = BuildRequirementsView
        GR.AutoRegisterServer = AutoRegisterServer
        GR.SyncRequirements = SyncRequirements
        
        -- Define the setup logic
        local function RunSetup()
            if GR.views and GR.views[3] then
                GR:BuildRequirementsView(GR.views[3])
                -- Trigger Auto-Fill Logic
                C_Timer.After(2, function() 
                    if GR.AutoRegisterServer then GR:AutoRegisterServer() end
                end)
            end
        end

        -- Execute immediately if already initialized, otherwise hook
        if GR.isInitialized then
            RunSetup()
        else
            hooksecurefunc(GR, "Initialize", function()
                RunSetup()
            end)
        end
    else
        -- If GR is still nil here, the Core Addon is missing or failed to load entirely.
        -- Failing silently is safer than crashing.
    end
end)