-- =========================================================================
-- GRS RECRUITMENT HISTORY v10.4 (ICON FIX: TEXTURE SWAP)
-- =========================================================================

local addonName, NS = ...
local GR_Funcs = {}

-- =========================================================================
-- 1. CONFIG & ASSETS
-- =========================================================================

local CLASS_ICON_TCOORDS = {
    ["WARRIOR"] = {0, 0.25, 0, 0.25}, ["MAGE"] = {0.25, 0.5, 0, 0.25},
    ["ROGUE"] = {0.5, 0.75, 0, 0.25}, ["DRUID"] = {0.75, 1, 0, 0.25},
    ["HUNTER"] = {0, 0.25, 0.25, 0.5}, ["SHAMAN"] = {0.25, 0.5, 0.25, 0.5},
    ["PRIEST"] = {0.5, 0.75, 0.25, 0.5}, ["WARLOCK"] = {0.75, 1, 0.25, 0.5},
    ["PALADIN"] = {0, 0.25, 0.5, 0.75}, ["DEATHKNIGHT"] = {0.25, 0.5, 0.5, 0.75},
    ["MONK"] = {0.5, 0.75, 0.5, 0.75}, ["DEMONHUNTER"] = {0.75, 1, 0.5, 0.75},
    ["EVOKER"] = {0, 0.25, 0.75, 1},
}

local function ColorText(text, r, g, b)
    if not text then return "" end
    if not r then r, g, b = 1, 1, 1 end
    return string.format("|cff%02x%02x%02x%s|r", r*255, g*255, b*255, text)
end

local function FormatTimestamp(m, d, h, min)
    if m == 0 or m == nil then 
        return "|cff808080N/A|r" 
    end
    return string.format("%02d/%02d %02d:%02d", m, d, h, min)
end

-- =========================================================================
-- 2. DATA PERSISTENCE ENGINE
-- =========================================================================

local RosterCache = {}

local function GetGuildKey()
    local gName = GetGuildInfo("player")
    if not gName then return nil end
    local realm = GetRealmName()
    return gName .. "-" .. (realm or "")
end

local function UpdateRosterCache()
    table.wipe(RosterCache)
    if not IsInGuild() then return end
    for i = 1, GetNumGuildMembers() do
        local name, _, _, _, _, _, _, _, _, _, classFileName = GetGuildRosterInfo(i)
        if name and classFileName then
            RosterCache[name] = classFileName
            local short = string.match(name, "^([^%-]+)")
            if short then RosterCache[short] = classFileName end
        end
    end
end

local function ResolveClass(name, dbClass)
    if dbClass then return dbClass end
    if not name then return nil end
    if RosterCache[name] then return RosterCache[name] end
    local short = string.match(name, "^([^%-]+)")
    if short and RosterCache[short] then return RosterCache[short] end
    return nil
end

local function GenerateDNA(y, m, d, h, min, type, p1, p2)
    return string.format("%d:%d:%d:%d:%d|%s|%s|%s", y, m, d, h, min, type, p1 or "nil", p2 or "nil")
end

-- =========================================================================
-- 3. THE VULTURE (UI SCRAPER HOOK)
-- =========================================================================

local function ScrapeLogIndex(index)
    if not index then return end
    
    local eventType, player1, player2, rank, year, month, day, weekday, hour, minute = GetGuildEventInfo(index)
    
    if not eventType then return end
    
    local gKey = GetGuildKey()
    if not gKey then return end
    
    if not GRS_HistoryDB then GRS_HistoryDB = {} end
    if not GRS_HistoryDB[gKey] then GRS_HistoryDB[gKey] = {} end
    local activeDB = GRS_HistoryDB[gKey]
    
    local y, m, d, h, min = year or 0, month or 0, day or 0, hour or 0, minute or 0
    local dna = GenerateDNA(y, m, d, h, min, eventType, player1, player2)
    
    local isDuplicate = false
    for _, stored in ipairs(activeDB) do
        if stored.dna == dna then isDuplicate = true; break end
    end
    
    if not isDuplicate then
        local c1 = ResolveClass(player1)
        local c2 = ResolveClass(player2)
        
        table.insert(activeDB, {
            dna = dna, type = eventType, p1 = player1, p2 = player2, 
            cP1 = c1, cP2 = c2, rank = rank,
            y = y, m = m, d = d, h = h, min = min,
            source = "VULTURE"
        })
    end
end

local vultureHooked = false
local function ActivateVulture()
    if vultureHooked then return end
    
    if CommunitiesGuildLogFrame and CommunitiesGuildLogFrame.Container and CommunitiesGuildLogFrame.Container.ScrollBox then
        
        CommunitiesGuildLogFrame.Container.ScrollBox:RegisterCallback("OnScroll", function(scrollBox)
            if not IsInGuild() then return end
            
            local dataProvider = scrollBox:GetDataProvider()
            if not dataProvider then return end
            
            local count = dataProvider:GetSize()
            local limit = math.min(count, 50) 
            
            for i = 1, limit do ScrapeLogIndex(i) end
        end)
        
        CommunitiesGuildLogFrame:HookScript("OnShow", function()
             for i = 1, 20 do ScrapeLogIndex(i) end
        end)
        
        vultureHooked = true
        print("|cff00ff00GRS:|r Vulture Protocol Active. Monitoring Default Guild Log.")
    end
end

-- =========================================================================
-- 4. UI BUILDERS
-- =========================================================================

local function CreateLogFrame(parent, title)
    local f = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    local t = f:CreateTexture(nil, "BACKGROUND"); t:SetAllPoints(); t:SetColorTexture(0,0,0,0.5)
    f.bg = t
    
    local lbl = f:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    lbl:SetPoint("TOP", 0, -15); lbl:SetText(title)
    
    local sf = CreateFrame("ScrollFrame", nil, f, "UIPanelScrollFrameTemplate")
    sf:SetPoint("TOPLEFT", 10, -45); sf:SetPoint("BOTTOMRIGHT", -30, 10)
    
    local content = CreateFrame("Frame", nil, sf)
    content:SetSize(sf:GetWidth(), 500); sf:SetScrollChild(content)
    
    f.scroll = sf; f.content = content; f.rows = {}
    return f
end

local function CreateRow(parent)
    local r = CreateFrame("Frame", nil, parent)
    r:SetSize(300, 45)
    
    -- Icon setup: Default texture set here, but will be overridden in FillLogFrame
    r.icon = r:CreateTexture(nil, "ARTWORK"); r.icon:SetSize(24, 24); r.icon:SetPoint("LEFT", 5, 0)
    r.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark") 
    
    r.date = r:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
    r.date:SetPoint("TOPLEFT", r.icon, "TOPRIGHT", 5, 2)
    
    r.name = r:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    r.name:SetPoint("BOTTOMLEFT", r.icon, "BOTTOMRIGHT", 5, -2)
    
    r.details = r:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    r.details:SetPoint("RIGHT", -5, 0); r.details:SetJustifyH("RIGHT")
    
    r.line = r:CreateTexture(nil, "ARTWORK"); r.line:SetHeight(1)
    r.line:SetColorTexture(0.2, 0.2, 0.2, 0.5)
    r.line:SetPoint("BOTTOMLEFT", 0, 0); r.line:SetPoint("BOTTOMRIGHT", 0, 0)
    
    return r
end

-- =========================================================================
-- 5. MAIN LOGIC
-- =========================================================================

function GR_Funcs.PopulateHistory(self)
    if not IsInGuild() then return end
    
    ActivateVulture()
    UpdateRosterCache()
    
    local gKey = GetGuildKey()
    if not gKey then return end 
    
    if not GRS_HistoryDB then GRS_HistoryDB = {} end
    if not GRS_HistoryDB[gKey] then GRS_HistoryDB[gKey] = {} end
    local activeDB = GRS_HistoryDB[gKey]
    
    local viewList = { joins = {}, ranks = {}, leaves = {} }
    
    -- API Poll
    local numEvents = GetNumGuildEvents()
    for i = 1, math.min(numEvents, 50) do 
        ScrapeLogIndex(i) 
    end
    
    -- READ DB
    for _, entry in ipairs(activeDB) do
        local sortVal = (entry.m * 1000000) + (entry.d * 10000) + (entry.h * 100) + entry.min
        if entry.y > 0 then sortVal = sortVal + (entry.y * 100000000) end
        
        -- Force N/A timestamps to top
        if entry.m == 0 and entry.d == 0 then sortVal = 99999999999 end
        
        local tsStr = FormatTimestamp(entry.m, entry.d, entry.h, entry.min)
        
        local rowData = { 
            ts = tsStr, type = entry.type, p1 = entry.p1, p2 = entry.p2, 
            cP1 = entry.cP1, cP2 = entry.cP2, rank = entry.rank, val = sortVal 
        }
        
        if entry.type == "invite" or entry.type == "join" then table.insert(viewList.joins, rowData)
        elseif entry.type == "promote" or entry.type == "demote" then table.insert(viewList.ranks, rowData)
        elseif entry.type == "remove" or entry.type == "quit" then table.insert(viewList.leaves, rowData)
        end
    end
    
    local function SortNewest(a, b) return a.val > b.val end
    table.sort(viewList.joins, SortNewest)
    table.sort(viewList.ranks, SortNewest)
    table.sort(viewList.leaves, SortNewest)
    
    self:FillLogFrame(self.histJoinFrame, viewList.joins)
    self:FillLogFrame(self.histRankFrame, viewList.ranks)
    self:FillLogFrame(self.histLeaveFrame, viewList.leaves)
end

function GR_Funcs.FillLogFrame(self, frame, data)
    if not frame then return end
    for _, r in ipairs(frame.rows) do r:Hide() end
    
    local y = 0
    for i, entry in ipairs(data) do
        local r = frame.rows[i]
        if not r then r = CreateRow(frame.content); frame.rows[i] = r end
        
        r:SetWidth(frame.content:GetWidth())
        r:SetPoint("TOPLEFT", 0, y)
        r:Show()
        
        r.date:SetText(entry.ts)
        
        local sName, details, rC, gC, bC = "Unknown", "", 1, 1, 1
        local classFile = nil
        
        if entry.type == "invite" then 
            sName = entry.p2; classFile = entry.cP2
            details = "Invited by\n"..(entry.p1 or "?"); rC,gC,bC = 0,1,0
        elseif entry.type == "join" then 
            sName = entry.p1; classFile = entry.cP1
            details = "Joined"; rC,gC,bC = 0,1,0
        elseif entry.type == "promote" then 
            sName = entry.p2; classFile = entry.cP2
            details = "Promoted to "..(entry.rank or "?").."\nby "..(entry.p1 or "?"); rC,gC,bC = 0.2,1,0.2
        elseif entry.type == "demote" then 
            sName = entry.p2; classFile = entry.cP2
            details = "Demoted to "..(entry.rank or "?").."\nby "..(entry.p1 or "?"); rC,gC,bC = 1,0.5,0
        elseif entry.type == "remove" then 
            sName = entry.p2; classFile = entry.cP2
            details = "Kicked by\n"..(entry.p1 or "?"); rC,gC,bC = 1,0,0
        elseif entry.type == "quit" then 
            sName = entry.p1; classFile = entry.cP1
            details = "Left Guild"; rC,gC,bC = 1,0.5,0
        end
        
        if not sName then sName = "Unknown" end
        if not classFile then classFile = ResolveClass(sName) end

        -- ** ICON RENDER LOGIC v10.4 **
        -- Explicitly swap texture based on knowledge state
        
        if classFile and CLASS_ICON_TCOORDS[classFile] then
            -- Known Class: Use Class Atlas
            r.icon:SetTexture("Interface\\Glues\\CharacterCreate\\UI-CharacterCreate-Classes")
            r.icon:SetTexCoord(unpack(CLASS_ICON_TCOORDS[classFile]))
            
            local cObj = C_ClassColor.GetClassColor(classFile)
            if cObj then 
                r.icon:SetVertexColor(1, 1, 1) -- Ensure full brightness
                r.name:SetText(ColorText(sName, cObj.r, cObj.g, cObj.b))
            else
                r.name:SetText(ColorText(sName, 0.6, 0.6, 0.6))
            end
        else
            -- Unknown: Force Standard Question Mark
            r.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
            r.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92) -- Zoom slightly to remove borders
            r.icon:SetVertexColor(1, 1, 1) -- Keep it standard color
            r.name:SetText(ColorText(sName, 0.6, 0.6, 0.6))
        end
        
        r.details:SetText(details)
        r.details:SetTextColor(rC, gC, bC)
        
        y = y - 45
    end
    frame.content:SetHeight(math.abs(y) + 20)
end

function GR_Funcs.BuildHistoryView(self, parent)
    if not parent then return end
    
    for _, region in ipairs({parent:GetRegions()}) do
        if region:GetObjectType() == "FontString" then region:Hide() end
    end
    
    local fJoin = self.histJoinFrame or CreateLogFrame(parent, "Invites")
    self.histJoinFrame = fJoin
    
    local fRank = self.histRankFrame or CreateLogFrame(parent, "Promotions")
    self.histRankFrame = fRank
    
    local fLeave = self.histLeaveFrame or CreateLogFrame(parent, "Departures")
    self.histLeaveFrame = fLeave
    
    local function UpdateLayout()
        local w = parent:GetWidth(); if not w or w < 10 then w = 800 end
        local colWidth = (w - 40) / 3
        
        fJoin:SetSize(colWidth, parent:GetHeight()-80)
        fJoin:ClearAllPoints(); fJoin:SetPoint("TOPLEFT", 10, -50)
        
        fRank:SetSize(colWidth, parent:GetHeight()-80)
        fRank:ClearAllPoints(); fRank:SetPoint("TOPLEFT", fJoin, "TOPRIGHT", 10, 0)
        
        fLeave:SetSize(colWidth, parent:GetHeight()-80)
        fLeave:ClearAllPoints(); fLeave:SetPoint("TOPLEFT", fRank, "TOPRIGHT", 10, 0)
        
        fJoin.content:SetWidth(colWidth-40)
        fRank.content:SetWidth(colWidth-40)
        fLeave.content:SetWidth(colWidth-40)
    end
    
    parent:SetScript("OnSizeChanged", UpdateLayout)
    parent:SetScript("OnShow", function()
        UpdateLayout()
        if IsInGuild() then
            ActivateVulture()
            C_Timer.After(0.5, function() self:PopulateHistory() end)
        end
    end)
    
    if not parent.refreshBtn then
        local btn = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
        btn:SetSize(100, 25); btn:SetPoint("TOPRIGHT", -10, -10); btn:SetText("Force Refresh")
        btn:SetScript("OnClick", function() 
            self:PopulateHistory() 
        end)
        parent.refreshBtn = btn
    end
    
    if not self.histEventFrame then
        self.histEventFrame = CreateFrame("Frame")
        self.histEventFrame:RegisterEvent("GUILD_EVENT_LOG_UPDATE")
        self.histEventFrame:SetScript("OnEvent", function() 
            if parent:IsVisible() then self:PopulateHistory() end 
        end)
    end
    
    UpdateLayout()
end

if _G["GRS_MainFrame"] then
    local GR = _G["GRS_MainFrame"]
    GR.PopulateHistory = GR_Funcs.PopulateHistory
    GR.FillLogFrame = GR_Funcs.FillLogFrame
    GR.BuildHistoryView = GR_Funcs.BuildHistoryView
    
    hooksecurefunc(GR, "Initialize", function(self)
        if self.views and self.views[4] then self:BuildHistoryView(self.views[4]) end
    end)
    
    if GR.isInitialized and GR.views and GR.views[4] then
        GR:BuildHistoryView(GR.views[4])
    end
    
    print("|cff00ff00GRS:|r Vulture Protocol Active. Monitoring Communities Log.")
end