-- =========================================================================
-- FILE: Roster_DetailsPanel.lua (TBC Port)
-- =========================================================================
local addonName, NS = ...
local GR = _G["GRS_MainFrame"]

-- Constants for Social Popup
local MONTHS = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}

-- =========================================================================
-- FACTION LOGIC: STRICT MAPS & DETERMINATION (CENTRALIZED)
-- TBC: Removed Dracthyr, Earthen, Vulpera, Allied Races (Retail-only)
-- =========================================================================

local RACE_MAP = {
    -- ALLIANCE (IDs)
    [1]="Alliance", [3]="Alliance", [4]="Alliance", [7]="Alliance", [11]="Alliance",
    
    -- ALLIANCE (Names - Spaced)
    ["Human"]="Alliance", ["Dwarf"]="Alliance", ["Night Elf"]="Alliance", ["Gnome"]="Alliance", 
    ["Draenei"]="Alliance",
    
    -- ALLIANCE (Names - API Strict/NoSpaces)
    ["NightElf"]="Alliance",

    -- HORDE (IDs)
    [2]="Horde", [5]="Horde", [6]="Horde", [8]="Horde", [10]="Horde",
    
    -- HORDE (Names - Spaced)
    ["Orc"]="Horde", ["Undead"]="Horde", ["Tauren"]="Horde", ["Troll"]="Horde", 
    ["Blood Elf"]="Horde",

    -- HORDE (Names - API Strict/NoSpaces)
    ["BloodElf"]="Horde", ["Scourge"]="Horde"
}

local AMBIGUOUS_RACES = {}

function GR:DetermineFaction(raceInput, raceID)
    -- 1. Check ID Map
    if raceID and RACE_MAP[raceID] then return RACE_MAP[raceID] end
    
    -- 2. Check Name Map (Cleaned)
    local cleanName = nil
    if raceInput and raceInput ~= "" and raceInput ~= "N/A" then
        if RACE_MAP[raceInput] then return RACE_MAP[raceInput] end
        cleanName = raceInput:gsub("^%s*(.-)%s*$", "%1")
        if RACE_MAP[cleanName] then return RACE_MAP[cleanName] end
    end
    
    -- 3. Check Ambiguous (Neutral Races)
    local isAmbiguous = false
    if raceID and AMBIGUOUS_RACES[raceID] then isAmbiguous = true end
    if cleanName and AMBIGUOUS_RACES[cleanName] then isAmbiguous = true end
    
    if isAmbiguous then
        return "Neutral"
    end

    return "Neutral"
end

-- TBC Safe Class Color Helper
local function GetClassColorSafe(classFile)
    if C_ClassColor and C_ClassColor.GetClassColor then
        return C_ClassColor.GetClassColor(classFile or "PRIEST")
    elseif RAID_CLASS_COLORS and RAID_CLASS_COLORS[classFile] then
        local c = RAID_CLASS_COLORS[classFile]
        if c and not c.WrapTextInColorCode then
            c.WrapTextInColorCode = function(self, text)
                return string.format("|cff%02x%02x%02x%s|r", self.r*255, self.g*255, self.b*255, text)
            end
        end
        return c
    end
    return { r = 1, g = 1, b = 1, WrapTextInColorCode = function(self, t) return "|cffffffff"..t.."|r" end }
end

-- =========================================================================
-- 1. VISUAL HELPERS (ANNOUNCEMENTS & TOASTS)
-- =========================================================================

function GR:ShowAnnouncement(msg)
    if not GR.AnnounceFrame then
        local f = CreateFrame("Frame", nil, UIParent); f:SetSize(800, 50); f:SetPoint("TOP", 0, -100); f:SetFrameStrata("FULLSCREEN_DIALOG")
        f.text = f:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge"); f.text:SetPoint("CENTER"); f.text:SetTextColor(1, 0.82, 0)
        f.ag = f:CreateAnimationGroup()
        local a1 = f.ag:CreateAnimation("Alpha"); a1:SetFromAlpha(0); a1:SetToAlpha(1); a1:SetDuration(0.3); a1:SetOrder(1)
        local a2 = f.ag:CreateAnimation("Alpha"); a2:SetFromAlpha(1); a2:SetToAlpha(1); a2:SetDuration(2.5); a2:SetOrder(2)
        local a3 = f.ag:CreateAnimation("Alpha"); a3:SetFromAlpha(1); a3:SetToAlpha(0); a3:SetDuration(0.5); a3:SetOrder(3)
        a3:SetScript("OnFinished", function() f:Hide() end); GR.AnnounceFrame = f
    end
    GR.AnnounceFrame.text:SetText(msg); GR.AnnounceFrame:Show(); GR.AnnounceFrame.ag:Stop(); GR.AnnounceFrame.ag:Play()
end

function GR:ShowToast(text, isWarning)
    if not GR.ToastFrame then
        local f = CreateFrame("Frame", "GRS_Toast", UIParent); f:SetSize(420, 80); f:SetPoint("TOP", 0, -100); f:SetFrameStrata("DIALOG")
        f.text = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); f.text:SetPoint("CENTER", 0, 0); f.text:SetWidth(380); f.text:SetJustifyH("CENTER"); f.text:SetWordWrap(true)
        f.ag = f:CreateAnimationGroup(); f.fade = f.ag:CreateAnimation("Alpha"); f.fade:SetFromAlpha(1); f.fade:SetToAlpha(0); f.fade:SetDuration(1.0); f.fade:SetStartDelay(4.0)
        f.ag:SetScript("OnFinished", function() f:Hide() end); GR.ToastFrame = f
    end
    -- TBC: SOUNDKIT may not exist
    if isWarning then 
        GR.ToastFrame.text:SetTextColor(1, 0.2, 0.2)
        if PlaySound and SOUNDKIT and SOUNDKIT.RAID_WARNING then
            PlaySound(SOUNDKIT.RAID_WARNING)
        elseif PlaySound then
            PlaySound(8959) -- Raid Warning sound ID
        end
    else 
        GR.ToastFrame.text:SetTextColor(1, 1, 1) 
    end
    GR.ToastFrame.text:SetText(text); GR.ToastFrame:Show(); GR.ToastFrame:SetAlpha(1); GR.ToastFrame.ag:Stop(); GR.ToastFrame.ag:Play()
end

-- =========================================================================
-- 2. RIGHT SIDE PANES (TOP & BOTTOM)
-- =========================================================================

function GR:BuildRightSide(topPane, bottomPane)
    local function Skin(b)
        if NS.SkinButton then NS.SkinButton(b) else
            b:SetNormalTexture(""); b:SetHighlightTexture(""); b:SetPushedTexture(""); b:SetDisabledTexture("")
            local t = b:CreateTexture(nil, "BACKGROUND"); t:SetAllPoints(); t:SetColorTexture(0.2, 0.2, 0.2, 1); b.bg = t
            local border = b:CreateTexture(nil, "BORDER"); border:SetAllPoints(); border:SetColorTexture(0, 0, 0, 1); border:SetDrawLayer("BORDER", -1)
            local fs = b:GetFontString(); if fs then fs:SetTextColor(1, 1, 1) end
        end
    end

    local refBtn = CreateFrame("Button", nil, topPane, "UIPanelButtonTemplate")
    refBtn:SetSize(60, 20); refBtn:SetPoint("TOPRIGHT", -5, -5); refBtn:SetText(NS.L and NS.L["REFRESH"] or "Refresh")
    Skin(refBtn); refBtn:SetScript("OnClick", function() GR:PerformSync() end)
    
    local togBtn = CreateFrame("Button", nil, topPane, "UIPanelButtonTemplate")
    togBtn:SetSize(180, 20); togBtn:SetPoint("RIGHT", refBtn, "LEFT", -5, 0); togBtn:SetText(NS.L and NS.L["TOGGLE_OFFLINE_MEMBERS"] or "Toggle Offline Members")
    Skin(togBtn); togBtn:SetScript("OnClick", function(s) GR.ShowOffline = not GR.ShowOffline; s:GetFontString():SetTextColor(1, GR.ShowOffline and 1 or 0.5, GR.ShowOffline and 1 or 0); if #GR.RosterData > 0 then GR:BuildViewList() else GR:FetchGuildData() end end)

    local title = topPane:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    title:SetPoint("TOPLEFT", 10, -5); title:SetText(NS.L and NS.L["MEMBER_DETAILS"] or "Member Details")
    
    local detailContent = CreateFrame("Frame", nil, topPane)
    detailContent:SetPoint("TOPLEFT", 0, -30); detailContent:SetPoint("BOTTOMRIGHT", 0, 0); detailContent:Hide(); GR.DetailContent = detailContent
    
    local dpTitle = detailContent:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); dpTitle:SetPoint("TOPLEFT", 10, 0); GR.DetailName = dpTitle
    local dpRank = detailContent:CreateFontString(nil, "OVERLAY", "GameFontHighlightMedium"); dpRank:SetPoint("TOPLEFT", 10, -25); GR.DetailRank = dpRank
    local dpClass = detailContent:CreateFontString(nil, "OVERLAY", "GameFontHighlightMedium"); dpClass:SetPoint("TOPLEFT", 10, -45); GR.DetailClass = dpClass
    
    local function CreateLabelEdit(labelTxt, y, maxChars)
        local lbl = detailContent:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall"); lbl:SetPoint("TOPLEFT", 10, y); lbl:SetText(labelTxt)
        local eb = CreateFrame("EditBox", nil, detailContent, "InputBoxTemplate"); eb:SetPoint("LEFT", lbl, "RIGHT", 10, 0); eb:SetSize(250, 20); eb:SetAutoFocus(false); eb:SetMaxLetters(maxChars)
        return eb
    end
    GR.PublicNoteEdit = CreateLabelEdit(NS.L and NS.L["PUBLIC_NOTE"] or "Public Note:", -75, 20)
    GR.OfficerNoteEdit = CreateLabelEdit(NS.L and NS.L["OFFICER_NOTE"] or "Officer Note:", -100, 40)
    
    local btnSave = CreateFrame("Button", nil, detailContent, "UIPanelButtonTemplate")
    btnSave:SetSize(80, 22); btnSave:SetPoint("BOTTOMLEFT", 10, 10); btnSave:SetText(NS.L and NS.L["SAVE"] or "Save"); Skin(btnSave)
    btnSave:SetScript("OnClick", function() if GR.SelectedMember then local idx = GR:GetGuildMemberIndex(GR.SelectedMember.fullName); if idx then GuildRosterSetPublicNote(idx, GR.PublicNoteEdit:GetText()); GuildRosterSetOfficerNote(idx, GR.OfficerNoteEdit:GetText()); GR:ShowToast("Notes Updated.") end end end)
    
    local btnSocial = CreateFrame("Button", nil, detailContent, "UIPanelButtonTemplate")
    btnSocial:SetSize(110, 22); btnSocial:SetPoint("LEFT", btnSave, "RIGHT", 10, 0); btnSocial:SetText(NS.L and NS.L["SOCIAL_ACTIVITY"] or "Social Activity"); Skin(btnSocial)
    btnSocial:SetScript("OnClick", function() if GR.SelectedMember then GR:OpenSocialPopup(GR.SelectedMember) end end)
    GR.DetailSocialBtn = btnSocial

    local btnCancel = CreateFrame("Button", nil, detailContent, "UIPanelButtonTemplate")
    btnCancel:SetSize(80, 22); btnCancel:SetPoint("LEFT", btnSocial, "RIGHT", 10, 0); btnCancel:SetText(NS.L and NS.L["CANCEL"] or "Cancel"); Skin(btnCancel)
    btnCancel:SetScript("OnClick", function() GR:DeselectMember() end)

    local bg = bottomPane:CreateTexture(nil, "ARTWORK"); bg:SetAllPoints()
    local useCustom = false
    if GR.db and GR.db.customBackgrounds and GR.db.customBackgrounds.enabled then
        local file = GR.db.customBackgrounds.files and GR.db.customBackgrounds.files["GuildChat"]
        if file and file ~= "" then
            local dir = GR.db.customBackgrounds.directory
            if string.sub(dir, -1) ~= "\\" then dir = dir .. "\\" end
            bg:SetTexture(dir .. file); bg:SetAlpha(1); useCustom = true
        end
    end
    if not useCustom then bg:SetTexture("Interface\\AddOns\\" .. addonName .. "\\Media\\Background_G-chat.tga"); bg:SetAlpha(0.25) end
    GR:InitGuildChat(bottomPane)
end

-- =========================================================================
-- 3. SOCIAL POPUP & TOOLTIP LOGIC
-- =========================================================================

function GR:OpenSocialPopup(data)
    if not self.SocialPopup then self:CreateSocialPopup() end
    local f = self.SocialPopup
    local dbKey = data.dbKey
    f.targetKey = dbKey
    local s = GRS_SocialDB[dbKey] or {}

    f.raceSexDD:SetText(s.raceSex or "Male")
    f.joinMonthDD:SetText(s.joinMonth or "January"); f.joinDayDD:SetText(s.joinDay or "1")
    f.promMonthDD:SetText(s.promMonth or "January"); f.promDayDD:SetText(s.promDay or "1")
    f.birthMonthDD:SetText(s.birthMonth or "January"); f.birthDayDD:SetText(s.birthDay or "1")
    f.pubNote:SetText(s.pubNote or ""); f.offNote:SetText(s.offNote or ""); f.customNote:SetText(s.customNote or "")
    
    local guidToDisplay = data.guid
    if not guidToDisplay or guidToDisplay == "" then
        local db = GR:GetDB()
        if db.guids then
            guidToDisplay = db.guids[dbKey]
        end
    end
    if not guidToDisplay or guidToDisplay == "" then
        guidToDisplay = UnitGUID(Ambiguate(data.fullName, "none"))
    end
    
    f.guidLabel:SetText(guidToDisplay or "N/A")
    
    f:Show()
end

function GR:CreateSocialPopup()
    local f = CreateFrame("Frame", "GRS_SocialPopup", UIParent, "BackdropTemplate")
    f:SetSize(450, 600); 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)
    
    if NS.CreateBg then NS.CreateBg(f, 0, 0, 0, 0.95) end
    if NS.CreateBorder then NS.CreateBorder(f, 0.3, 0.3, 0.3, 1) end

    local hdr = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    hdr:SetPoint("TOP", 0, -15)
    hdr:SetText("A.X.I.O.M. | Social")
    hdr:SetTextColor(0.4, 0.8, 1, 1)

    local desc = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    desc:SetPoint("TOPLEFT", 20, -45); desc:SetWidth(410); desc:SetJustifyH("LEFT")
    desc:SetText("Here you can add a member's birthday, the date they joined the guild, and any other notes that matter to you and the rest of the guild.\nIf your guild does RP, turn on the RP features.\nHave fun!")

    local INPUT_X = 140

    local function CreateBaseDropdown(parent, w)
        local dd = CreateFrame("Button", nil, parent)
        dd:SetSize(w, 24)
        if NS.CreateBg then NS.CreateBg(dd, 0.1, 0.1, 0.1, 1) end
        if NS.CreateBorder then NS.CreateBorder(dd, 0.5, 0.5, 0.5, 1) end
        
        local txt = dd:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        txt:SetPoint("LEFT", 5, 0)
        dd.text = txt
        
        dd.SetText = function(self, t) self.text:SetText(t) end
        dd.GetText = function(self) return self.text:GetText() end
        return dd
    end

    local function CreateSocialDropdown(y, label, items)
        local lbl = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall"); lbl:SetPoint("TOPLEFT", 20, y); lbl:SetText(label)
        
        local dd = CreateBaseDropdown(f, 150)
        dd:SetPoint("TOPLEFT", f, "TOPLEFT", INPUT_X, y + 2) 
        
        local list = CreateFrame("Frame", nil, dd); list:SetSize(150, 200); list:SetPoint("TOPLEFT", dd, "BOTTOMLEFT", 0, -2); list:Hide(); list:SetFrameStrata("TOOLTIP")
        if NS.CreateBg then NS.CreateBg(list, 0, 0, 0, 1) end
        local scroll = CreateFrame("ScrollFrame", nil, list, "UIPanelScrollFrameTemplate"); scroll:SetAllPoints()
        if NS.StyleScrollBar then NS.StyleScrollBar(scroll) end
        local content = CreateFrame("Frame", nil, scroll); content:SetSize(130, 10); scroll:SetScrollChild(content)
        
        dd:SetScript("OnClick", function() 
            if list:IsShown() then list:Hide() else
                local ySub = 0
                for i, v in ipairs(items) do
                    local b = CreateFrame("Button", nil, content); b:SetSize(130, 20); b:SetPoint("TOPLEFT", 0, ySub)
                    local bt = b:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); bt:SetPoint("LEFT", 5, 0); bt:SetText(v)
                    b:SetScript("OnClick", function() dd:SetText(v); list:Hide() end)
                    ySub = ySub - 20
                end
                content:SetHeight(math.abs(ySub)); list:Show()
            end
        end)
        return dd
    end

    f.raceSexDD = CreateSocialDropdown(-120, "Race Sex:", {"Male", "Female"})
    
    local function CreateDoubleDropdown(y, label, items1, items2)
        local lbl = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall"); lbl:SetPoint("TOPLEFT", 20, y); lbl:SetText(label)
        
        local dd1 = CreateBaseDropdown(f, 100)
        dd1:SetPoint("TOPLEFT", f, "TOPLEFT", INPUT_X, y + 2) 
        
        local dd2 = CreateBaseDropdown(f, 50)
        dd2:SetPoint("TOPLEFT", f, "TOPLEFT", INPUT_X + 105, y + 2) 
        
        local list1 = CreateFrame("Frame", nil, dd1); list1:SetSize(100, 200); list1:SetPoint("TOPLEFT", dd1, "BOTTOMLEFT", 0, -2); list1:Hide(); list1:SetFrameStrata("TOOLTIP")
        if NS.CreateBg then NS.CreateBg(list1, 0, 0, 0, 1) end
        local scroll1 = CreateFrame("ScrollFrame", nil, list1, "UIPanelScrollFrameTemplate"); scroll1:SetAllPoints()
        if NS.StyleScrollBar then NS.StyleScrollBar(scroll1) end
        local content1 = CreateFrame("Frame", nil, scroll1); content1:SetSize(80, 10); scroll1:SetScrollChild(content1)
        dd1:SetScript("OnClick", function()
             if list1:IsShown() then list1:Hide() else
                local ySub = 0
                for i, v in ipairs(items1) do
                    local b = CreateFrame("Button", nil, content1); b:SetSize(80, 20); b:SetPoint("TOPLEFT", 0, ySub)
                    local bt = b:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); bt:SetPoint("LEFT", 5, 0); bt:SetText(v)
                    b:SetScript("OnClick", function() dd1:SetText(v); list1:Hide() end)
                    ySub = ySub - 20
                end
                content1:SetHeight(math.abs(ySub)); list1:Show()
             end
        end)

        local list2 = CreateFrame("Frame", nil, dd2); list2:SetSize(50, 200); list2:SetPoint("TOPLEFT", dd2, "BOTTOMLEFT", 0, -2); list2:Hide(); list2:SetFrameStrata("TOOLTIP")
        if NS.CreateBg then NS.CreateBg(list2, 0, 0, 0, 1) end
        local scroll2 = CreateFrame("ScrollFrame", nil, list2, "UIPanelScrollFrameTemplate"); scroll2:SetAllPoints()
        if NS.StyleScrollBar then NS.StyleScrollBar(scroll2) end
        local content2 = CreateFrame("Frame", nil, scroll2); content2:SetSize(30, 10); scroll2:SetScrollChild(content2)
        dd2:SetScript("OnClick", function()
             if list2:IsShown() then list2:Hide() else
                local ySub = 0
                for i, v in ipairs(items2) do
                    local b = CreateFrame("Button", nil, content2); b:SetSize(30, 20); b:SetPoint("TOPLEFT", 0, ySub)
                    local bt = b:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); bt:SetPoint("LEFT", 5, 0); bt:SetText(v)
                    b:SetScript("OnClick", function() dd2:SetText(v); list2:Hide() end)
                    ySub = ySub - 20
                end
                content2:SetHeight(math.abs(ySub)); list2:Show()
             end
        end)

        return dd1, dd2
    end

    local days = {}; for i=1,31 do table.insert(days, tostring(i)) end
    f.joinMonthDD, f.joinDayDD = CreateDoubleDropdown(-150, "Join Date:", MONTHS, days)
    f.promMonthDD, f.promDayDD = CreateDoubleDropdown(-180, "Promotion Date:", MONTHS, days)
    f.birthMonthDD, f.birthDayDD = CreateDoubleDropdown(-210, "Birthday:", MONTHS, days)

    local function CreateSocialInput(y, label, max)
        local lbl = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall"); lbl:SetPoint("TOPLEFT", 20, y); lbl:SetText(label)
        local eb = CreateFrame("EditBox", nil, f, "InputBoxTemplate")
        eb:SetSize(280, 20)
        eb:SetPoint("TOPLEFT", f, "TOPLEFT", INPUT_X, y + 2) 
        eb:SetAutoFocus(false); eb:SetMaxLetters(max)
        return eb
    end

    f.pubNote = CreateSocialInput(-240, "Public Note:", 31)
    f.offNote = CreateSocialInput(-270, "Officer Note:", 31)
    f.customNote = CreateSocialInput(-300, "Custom Note:", 255)

    local guidLbl = f:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall"); guidLbl:SetPoint("TOPLEFT", 20, -340); guidLbl:SetText("Player GUID:")
    f.guidLabel = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); f.guidLabel:SetPoint("LEFT", guidLbl, "RIGHT", 10, 0)

    local btnSave = CreateFrame("Button", nil, f)
    btnSave:SetSize(120, 30); btnSave:SetPoint("BOTTOMLEFT", 20, 20); btnSave:SetText("Save")
    if NS.CreateBg then NS.CreateBg(btnSave, 0, 0, 0, 1) end
    if NS.CreateBorder then NS.CreateBorder(btnSave, 1, 1, 1, 1) end
    local fsS = btnSave:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); fsS:SetPoint("CENTER"); fsS:SetText("Save"); btnSave:SetFontString(fsS)
    
    btnSave:SetScript("OnClick", function()
        local key = f.targetKey
        if key then
            GRS_SocialDB[key] = {
                raceSex = f.raceSexDD:GetText(),
                joinMonth = f.joinMonthDD:GetText(), joinDay = f.joinDayDD:GetText(),
                promMonth = f.promMonthDD:GetText(), promDay = f.promDayDD:GetText(),
                birthMonth = f.birthMonthDD:GetText(), birthDay = f.birthDayDD:GetText(),
                pubNote = f.pubNote:GetText(), offNote = f.offNote:GetText(), customNote = f.customNote:GetText()
            }
            GR:ShowToast("Social data saved.")
            f:Hide()
        end
    end)

    local btnCancel = CreateFrame("Button", nil, f)
    btnCancel:SetSize(120, 30); btnCancel:SetPoint("BOTTOMRIGHT", -20, 20); btnCancel:SetText("Cancel")
    if NS.CreateBg then NS.CreateBg(btnCancel, 0, 0, 0, 1) end
    if NS.CreateBorder then NS.CreateBorder(btnCancel, 1, 1, 1, 1) end
    local fsC = btnCancel:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); fsC:SetPoint("CENTER"); fsC:SetText("Cancel"); btnCancel:SetFontString(fsC)
    btnCancel:SetScript("OnClick", function() f:Hide() end)

    self.SocialPopup = f
end

function GR:ShowSocialTooltip(data)
    if not self.db or not self.db.socialEnabled then return end
    if not self.SocialTooltip then self:CreateSocialTooltip() end
    local t = self.SocialTooltip
    local s = GRS_SocialDB[data.dbKey] or {}

    t.name:SetText(data.name)
    
    local factionDisplay = data.faction
    if (not factionDisplay or factionDisplay == "Neutral") then
        local db = GR:GetDB()
        if db.factions and db.factions[data.dbKey] then
             factionDisplay = db.factions[data.dbKey]
        end
    end
    t.faction:SetText("Faction: " .. (factionDisplay or "Unknown"))
    
    t.class:SetText("Class: " .. (data.class or "Unknown"))
    
    local rDisp = s.raceSex
    if not rDisp or rDisp == "" or rDisp == "N/A" then rDisp = data.race end
    t.raceSex:SetText("Race/Sex: " .. (rDisp or "N/A"))
    
    local function IsAnniversary(mStr, dStr)
        if not mStr or not dStr then return false end
        local monthIdx = 0; for i,v in ipairs(MONTHS) do if v == mStr then monthIdx = i break end end
        local today = date("*t")
        local target = {month = monthIdx, day = tonumber(dStr), year = today.year}
        local targetTime = time(target); local nowTime = time(today)
        local diff = math.abs(difftime(targetTime, nowTime)) / 86400
        return diff <= 10
    end

    local isJoinAnni = IsAnniversary(s.joinMonth, s.joinDay)
    t.join:SetText("Join Date: " .. (s.joinMonth or "N/A") .. " " .. (s.joinDay or ""))
    t.join.isAnniversary = isJoinAnni

    t.prom:SetText("Promotion: " .. (s.promMonth or "N/A") .. " " .. (s.promDay or ""))
    t.birth:SetText("Birthday: " .. (s.birthMonth or "N/A") .. " " .. (s.birthDay or ""))
    t.pub:SetText("Public Note: " .. (s.pubNote or "N/A"))
    t.off:SetText("Officer Note: " .. (s.offNote or "N/A"))
    t.custom:SetText("Custom Note: " .. (s.customNote or "N/A"))

    t:ClearAllPoints()
    t:SetPoint("TOPRIGHT", GR, "TOPLEFT", -10, 0)
    t:Show()
end

function GR:CreateSocialTooltip()
    local t = CreateFrame("Frame", "GRS_SocialTooltip", UIParent, "BackdropTemplate")
    t:SetSize(250, 320); t:SetFrameStrata("TOOLTIP")
    if NS.CreateBg then NS.CreateBg(t, 0, 0, 0, 0.9) end
    if NS.CreateBorder then NS.CreateBorder(t, 0.5, 0.5, 0.5, 1) end

    t.name = t:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge"); t.name:SetPoint("TOPLEFT", 15, -15)
    t.faction = t:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); t.faction:SetPoint("TOPLEFT", 15, -45)
    t.class = t:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); t.class:SetPoint("TOPLEFT", 15, -60)
    t.raceSex = t:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); t.raceSex:SetPoint("TOPLEFT", 15, -75)
    t.join = t:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); t.join:SetPoint("TOPLEFT", 15, -95)
    t.prom = t:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); t.prom:SetPoint("TOPLEFT", 15, -110)
    t.birth = t:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); t.birth:SetPoint("TOPLEFT", 15, -125)
    t.pub = t:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); t.pub:SetPoint("TOPLEFT", 15, -145); t.pub:SetWidth(220); t.pub:SetJustifyH("LEFT")
    t.off = t:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); t.off:SetPoint("TOPLEFT", 15, -175); t.off:SetWidth(220); t.off:SetJustifyH("LEFT")
    t.custom = t:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); t.custom:SetPoint("TOPLEFT", 15, -205); t.custom:SetWidth(220); t.custom:SetJustifyH("LEFT")

    t:SetScript("OnUpdate", function(self, elapsed)
        if self.join.isAnniversary then
            local cycle = (GetTime() % 2) / 2
            if cycle < 0.5 then self.join:SetTextColor(0, 1, 0) 
            else self.join:SetTextColor(1, 0.82, 0) end 
        else self.join:SetTextColor(1, 1, 1) end
    end)

    self.SocialTooltip = t
end

-- =========================================================================
-- 4. INSPECTION & GUILD CHAT
-- =========================================================================

function GR:SelectMember(data)
    GR.SelectedMember = data
    if not GR.DetailContent then return end
    local namePart, realmPart = strsplit("-", data.fullName or "")
    if not realmPart or realmPart == "" then realmPart = GetRealmName() end
    GR.DetailName:SetText(namePart .. " - " .. (realmPart or ""))
    GR.DetailRank:SetText("Rank: " .. (data.rank or "Unknown"))
    local cColor = GetClassColorSafe((data.class or "PRIEST"):upper())
    GR.DetailClass:SetText(cColor:WrapTextInColorCode(data.class) .. " " .. (data.race or ""))
    
    local myName, myRealm = UnitFullName("player"); local myCanonical = myName .. "-" .. (myRealm or GetRealmName())
    local isMe = (data.dbKey == myCanonical); local isOfficer = GR:IsOfficer() or GR.devOfficerMode
    
    GR.PublicNoteEdit:SetText(data.publicNote or ""); GR.OfficerNoteEdit:SetText(data.officerNote or "")
    if isMe or isOfficer then GR.PublicNoteEdit:Enable() else GR.PublicNoteEdit:Disable() end
    if isOfficer then GR.OfficerNoteEdit:Enable(); GR.OfficerNoteEdit:Show(); GR.DetailSocialBtn:Show() else GR.OfficerNoteEdit:Disable(); GR.OfficerNoteEdit:Hide(); GR.DetailSocialBtn:Hide() end
    
    if not GR.db or not GR.db.socialEnabled then GR.DetailSocialBtn:Hide() end

    GR.DetailContent:Show()
end

function GR:DeselectMember()
    GR.SelectedMember = nil
    if GR.DetailContent then GR.DetailContent:Hide() end
end

function GR:InitGuildChat(parent)
    local gc = CreateFrame("ScrollingMessageFrame", nil, parent)
    gc:SetPoint("TOPLEFT", 5, -5); gc:SetPoint("BOTTOMRIGHT", -25, 25)
    gc:SetFontObject("ChatFontNormal"); gc:SetJustifyH("LEFT"); gc:SetFading(false); gc:SetMaxLines(GR.MAX_HISTORY_LINES)
    gc:SetHyperlinksEnabled(true)
    gc:SetScript("OnHyperlinkClick", function(_, link) SetItemRef(link, link, "LeftButton") end)
    GR.GuildChatFrame = gc
    
    local sb = GR:CreateRobustVerticalScrollbar(parent, gc)
    sb:SetPoint("TOPRIGHT", -2, -2); sb:SetPoint("BOTTOMRIGHT", -2, 28)

    local eb = CreateFrame("EditBox", nil, parent, "InputBoxTemplate")
    eb:SetHeight(20); eb:SetPoint("BOTTOMLEFT", 5, 5); eb:SetPoint("BOTTOMRIGHT", -5, 5); eb:SetAutoFocus(false)
    eb:SetScript("OnEnterPressed", function(self)
        local msg = self:GetText()
        if msg and msg ~= "" then
            if IsInGuild() then SendChatMessage(msg, "GUILD") end
            self:SetText("")
        end
        self:ClearFocus()
    end)
    GR.GuildChatEditBox = eb

    if not GR.chatHooked then
        ChatFrame_AddMessageEventFilter("CHAT_MSG_GUILD", function(self, event, msg, sender, ...)
            if GR.GuildChatFrame then
                local _, chatDB = GR:GetDB()
                local name = Ambiguate(sender, "none")
                local timestamp = date("%H:%M")
                local r, g, b = 0.25, 1, 0.25 
                GR.GuildChatFrame:AddMessage("|cff888888["..timestamp.."]|r |cff00ff00["..name.."]:|r " .. msg, r, g, b)
                if chatDB then
                    table.insert(chatDB, {ts=time(), sender=name, msg=msg})
                    if #chatDB > GR.MAX_HISTORY_LINES then table.remove(chatDB, 1) end
                end
            end
            return false
        end)
        ChatFrame_AddMessageEventFilter("CHAT_MSG_GUILD_ACHIEVEMENT", function(self, event, msg, sender, ...)
            if GR.GuildChatFrame then GR.GuildChatFrame:AddMessage("|cffffff00" .. msg) end
            return false
        end)
        GR.chatHooked = true
    end
    GR:LoadChatHistory()
end

function GR:LoadChatHistory()
    local _, chatDB = GR:GetDB()
    if not GR.GuildChatFrame or not chatDB then return end
    GR.GuildChatFrame:Clear()
    for _, entry in ipairs(chatDB) do
        local d = date("*t", entry.ts); local tsStr = string.format("%02d:%02d", d.hour, d.min)
        GR.GuildChatFrame:AddMessage("|cff888888["..tsStr.."]|r |cff00ff00["..entry.sender.."]:|r " .. entry.msg)
    end
end

-- =========================================================================
-- 5. UNIFIED INSPECTION ROUTER (TBC Simplified)
-- =========================================================================

function GR:OpenInspectWindow(dbKey)
    if not dbKey then return end
    
    local myName, myRealm = UnitFullName("player")
    if not myRealm or myRealm == "" then myRealm = GetRealmName() end
    local myCanonical = myName .. "-" .. myRealm

    if dbKey == myCanonical then
        -- TBC: Use ToggleCharacter for self-inspection
        ToggleCharacter("PaperDollFrame")
        return
    end

    -- TBC: Simplified - no AXIOM inspection system
    local data = GRS_InspectionDB[dbKey]
    if not data then 
        GR:ShowToast("No inspection data available for " .. Ambiguate(dbKey, "none"), true)
        return 
    end

    -- TBC: Just show a toast with basic info since we don't have the full inspect system
    GR:ShowToast("Inspection data available for " .. Ambiguate(dbKey, "none") .. " (Level " .. (data.ilvl or "?") .. ")")
end
