local addonName, NS = ...

-- =========================================================================
-- Blacklist Module (Split View: Normal & Permanent)
-- =========================================================================

NS.Blacklist = NS.Blacklist or {}
local M = NS.Blacklist

-- =========================================================================
-- Local Helpers
-- =========================================================================

local function CreateBg(f, r, g, b, a)
    local t = f:CreateTexture(nil, "BACKGROUND")
    t:SetAllPoints()
    t:SetColorTexture(r, g, b, a)
    f.bg = t
end

local function CreateBorder(f, r, g, b, a)
    if f.border then f.border:Hide() end

    local border = f:CreateTexture(nil, "BORDER")
    border:SetPoint("TOPLEFT", -1, 1)
    border:SetPoint("BOTTOMRIGHT", 1, -1)
    border:SetColorTexture(r, g, b, a)
    f.border = border
end

local function SkinButton(btn)
    if not btn then return end

    btn:SetNormalTexture("")
    btn:SetHighlightTexture("")
    btn:SetPushedTexture("")
    btn:SetDisabledTexture("")

    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
    if btn.Top then btn.Top:SetAlpha(0) end
    if btn.Bottom then btn.Bottom:SetAlpha(0) end

    CreateBg(btn, 0.2, 0.2, 0.2, 1)
    CreateBorder(btn, 0, 0, 0, 1)

    btn:HookScript("OnEnter", function(s)
        if s.bg then s.bg:SetColorTexture(0.3, 0.3, 0.3, 1) end
    end)
    btn:HookScript("OnLeave", function(s)
        if s.bg then s.bg:SetColorTexture(0.2, 0.2, 0.2, 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.3, 0.3, 0.3, 1) end
    end)

    local fs = btn:GetFontString()
    if fs then fs:SetTextColor(1, 1, 1) end
end

local function GetTableSize(t)
    local count = 0
    if t then
        for _ in pairs(t) do count = count + 1 end
    end
    return count
end

-- =========================================================================
-- Attach API
-- =========================================================================

function M.Attach(GR)
    if not GR or GR.__BlacklistAttached then return end
    GR.__BlacklistAttached = true

    -- =========================================================================
    -- View 2: Blacklist UI
    -- =========================================================================

    function GR:BuildBlacklistView()
        local GR = self -- capture for closures

        local parent = CreateFrame("Frame", "GRS_BlacklistView", self.ViewContainer)
        parent:SetPoint("TOPLEFT", 0, -30)
        parent:SetPoint("BOTTOMRIGHT", 0, 0)
        parent:Hide()
        self.views[2] = parent

        -- [[ LAYOUT RE-CALCULATION ]]
        -- Total Available Width (approx): 1240px
        -- Controls: 220px
        -- Gap: 50px
        -- Remaining: 970px
        -- Lists: 475px each
        
        local controls = CreateFrame("Frame", nil, parent)
        controls:SetWidth(220)
        controls:SetPoint("TOPLEFT")
        controls:SetPoint("BOTTOMLEFT")
        CreateBg(controls, 0.1, 0.1, 0.1, 0.5)
        CreateBorder(controls, 0.2, 0.2, 0.2, 1)

        -- Normal Blacklist Container
        local normalFrame = CreateFrame("Frame", nil, parent)
        normalFrame:SetWidth(475) -- [[ FIXED WIDTH ]]
        normalFrame:SetPoint("TOPLEFT", controls, "TOPRIGHT", 0, 0)
        normalFrame:SetPoint("BOTTOMLEFT", controls, "BOTTOMRIGHT", 0, 0)
        CreateBg(normalFrame, 0, 0, 0, 1) -- [[ PURE SOLID BLACK (1.0) ]]
        CreateBorder(normalFrame, 0, 0, 0, 1)

        -- Permanent Blacklist Container
        local permaFrame = CreateFrame("Frame", nil, parent)
        permaFrame:SetWidth(475) -- [[ FIXED WIDTH ]]
        permaFrame:SetPoint("TOPLEFT", normalFrame, "TOPRIGHT", 50, 0) -- [[ 50 PIXEL GAP ]]
        permaFrame:SetPoint("BOTTOMLEFT", normalFrame, "BOTTOMRIGHT", 50, 0)
        CreateBg(permaFrame, 0, 0, 0, 1) -- [[ PURE SOLID BLACK (1.0) ]]
        CreateBorder(permaFrame, 0, 0, 0, 1)

        -- [[ CONTROLS (Left Pane) ]]
        local y = -20
        local function AddLbl(txt, container, yVal)
            local t = container:CreateFontString(nil, "OVERLAY", "GameFontNormal")
            t:SetPoint("TOPLEFT", 15, yVal)
            t:SetText(txt)
            return t
        end

        AddLbl("MANAGE BLACKLIST", controls, y)

        local btnReset = CreateFrame("Button", nil, controls, "UIPanelButtonTemplate")
        btnReset:SetSize(190, 24)
        btnReset:SetPoint("TOPLEFT", 15, y - 25)
        btnReset:SetText("Reset Entire Normal List")
        SkinButton(btnReset)
        btnReset:SetScript("OnClick", function()
            GR:ResetBlacklist() -- Clears Normal Only
        end)

        local btnDelSel = CreateFrame("Button", nil, controls, "UIPanelButtonTemplate")
        btnDelSel:SetSize(190, 24)
        btnDelSel:SetPoint("TOPLEFT", btnReset, "BOTTOMLEFT", 0, -5)
        btnDelSel:SetText("Reset Selection (Both)")
        SkinButton(btnDelSel)
        btnDelSel:SetScript("OnClick", function()
            GR:RemoveSelectedFromBlacklist()
        end)

        y = y - 85
        AddLbl("MANUAL ADD", controls, y)

        local inputAdd = CreateFrame("EditBox", nil, controls, "InputBoxTemplate")
        inputAdd:SetSize(190, 24)
        inputAdd:SetPoint("TOPLEFT", 15, y - 25)
        inputAdd:SetAutoFocus(false)
        inputAdd:SetScript("OnEscapePressed", function(s) s:ClearFocus() end)
        
        local btnAdd = CreateFrame("Button", nil, controls, "UIPanelButtonTemplate")
        btnAdd:SetSize(190, 24)
        btnAdd:SetPoint("TOPLEFT", inputAdd, "BOTTOMLEFT", 0, -5)
        btnAdd:SetText("Add to Normal")
        SkinButton(btnAdd)
        btnAdd:SetScript("OnClick", function()
            local n = inputAdd:GetText()
            if n and n ~= "" then
                GR:AddToBlacklist(n)
                inputAdd:SetText("")
                print("Added " .. n .. " to Blacklist.")
            end
        end)

        -- [[ AUTOMATION CONTROLS ]]
        y = y - 85
        AddLbl("AUTOMATE RESET", controls, y)
        
        local autoCheck = CreateFrame("CheckButton", nil, controls, "UICheckButtonTemplate")
        autoCheck:SetSize(24, 24)
        autoCheck:SetPoint("TOPLEFT", 15, y - 25)
        autoCheck:SetChecked(GR.db.automateReset)
        autoCheck.text = autoCheck:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        autoCheck.text:SetPoint("LEFT", autoCheck, "RIGHT", 2, 0)
        autoCheck.text:SetText("Automate reset:")
        
        autoCheck:SetScript("OnClick", function(self)
            GR.db.automateReset = self:GetChecked()
            if GR.db.automateReset then GR:PruneExpiredBlacklist() end
        end)

        -- Dropdown Helper
        local function CreateDurationDropdown(parent, width)
            local btn = CreateFrame("Button", nil, parent)
            CreateBg(btn, 0.2, 0.2, 0.2, 1)
            btn:SetSize(width, 24)
            local txt = btn:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
            txt:SetPoint("LEFT", 5, 0)
            
            -- Map seconds to Label
            local function GetLabel(sec)
                if sec == 86400 then return "1 Day"
                elseif sec == 604800 then return "1 Week"
                elseif sec == 1209600 then return "2 Weeks"
                elseif sec == 2592000 then return "1 Month"
                elseif sec == 5184000 then return "2 Months"
                else return "1 Week" end
            end
            
            txt:SetText(GetLabel(GR.db.resetDuration or 604800))
            
            local list = CreateFrame("Frame", nil, parent)
            CreateBg(list, 0.1, 0.1, 0.1, 1)
            CreateBorder(list, 0.5, 0.5, 0.5, 1)
            list:SetSize(width, 110)
            list:SetPoint("TOPLEFT", btn, "BOTTOMLEFT", 0, -2)
            list:SetFrameStrata("FULLSCREEN_DIALOG")
            list:Hide()
            
            local opts = {
                {l="1 Day", v=86400},
                {l="1 Week", v=604800},
                {l="2 Weeks", v=1209600},
                {l="1 Month", v=2592000},
                {l="2 Months", v=5184000}
            }
            
            local dy = -5
            for _, opt in ipairs(opts) do
                local b = CreateFrame("Button", nil, list)
                b:SetSize(width - 10, 20)
                b:SetPoint("TOPLEFT", 5, dy)
                local t = b:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                t:SetPoint("LEFT")
                t:SetText(opt.l)
                b:SetScript("OnClick", function()
                    GR.db.resetDuration = opt.v
                    txt:SetText(opt.l)
                    list:Hide()
                    if GR.db.automateReset then GR:PruneExpiredBlacklist() end
                end)
                dy = dy - 20
            end
            
            btn:SetScript("OnClick", function() list:SetShown(not list:IsShown()) end)
            return btn
        end

        local ddReset = CreateDurationDropdown(controls, 190)
        ddReset:SetPoint("TOPLEFT", autoCheck, "BOTTOMLEFT", 0, -5)


        y = y - 100
        AddLbl("GUILD SYNC", controls, y)

        local btnSync = CreateFrame("Button", nil, controls, "UIPanelButtonTemplate")
        btnSync:SetSize(190, 30)
        btnSync:SetPoint("TOPLEFT", 15, y - 25)
        btnSync:SetText("Sync with Guild")
        SkinButton(btnSync)
        btnSync:SetScript("OnClick", function()
            GR:SyncBlacklist()
        end)

        -- [[ LIST HEADERS & SCROLLS ]]
        
        -- Titles (Centered relative to their fixed-width frames)
        local titleNormal = normalFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        titleNormal:SetPoint("TOP", 0, -10); titleNormal:SetText("Temporarily Blacklisted")
        titleNormal:SetTextColor(1, 0.82, 0) -- Gold Title
        
        local titlePerma = permaFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        titlePerma:SetPoint("TOP", 0, -10); titlePerma:SetText("PERMANENT Blacklist")
        titlePerma:SetTextColor(1, 0.2, 0.2) -- Red Text

        -- Shared Header Config (Widths matched to 475px frame)
        -- Name(120), Race(80), Class(80), Score(55), H(50), M(50) = 435px + Padding
        local headers = {
            {text="Name", width=120},
            {text="Race", width=80},
            {text="Class", width=80},
            {text="Score", width=55},
            {text="Heroic", width=50},
            {text="Mythic", width=50}
        }

        local function BuildList(frame, prefix)
            local headF = CreateFrame("Frame", nil, frame)
            headF:SetSize(20, 20)
            headF:SetPoint("TOPLEFT", 0, -35)
            headF:SetPoint("TOPRIGHT", 0, -35)

            local lh = nil
            for i, h in ipairs(headers) do
                local b = CreateFrame("Button", nil, headF)
                b:SetSize(h.width, 20)
                if i == 1 then
                    b:SetPoint("LEFT", 10, 0) -- 10px Padding Left
                else
                    b:SetPoint("LEFT", lh, "RIGHT", 0, 0)
                end
                local t = b:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
                t:SetPoint("LEFT")
                t:SetText(h.text)
                lh = b
            end

            local scroll = CreateFrame("ScrollFrame", prefix.."Scroll", frame, "FauxScrollFrameTemplate")
            scroll:SetPoint("TOPLEFT", headF, "BOTTOMLEFT", 0, -5)
            scroll:SetPoint("BOTTOMRIGHT", -25, 5)
            CreateBg(scroll, 0, 0, 0, 1) -- [[ UPDATED: PURE SOLID BLACK (1.0) ]]

            local rows = {}
            for i = 1, 25 do
                local r = CreateFrame("Button", nil, frame)
                r:SetHeight(20)
                r:SetPoint("LEFT", 5, 0)
                r:SetPoint("RIGHT", -5, 0)

                if i == 1 then r:SetPoint("TOP", scroll, "TOP")
                else r:SetPoint("TOP", rows[i-1], "BOTTOM") end

                r.c = CreateFrame("CheckButton", nil, r, "UICheckButtonTemplate")
                r.c:SetSize(20, 20)
                r.c:SetPoint("LEFT", 0, 0)
                r.c:SetScript("OnClick", function(b)
                    if r.data then r.data.selected = b:GetChecked() end
                end)
                
                r.n = r:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                r.n:SetPoint("LEFT", 20, 0); r.n:SetWidth(120); r.n:SetJustifyH("LEFT")

                r.ra = r:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                r.ra:SetPoint("LEFT", r.n, "RIGHT"); r.ra:SetWidth(80); r.ra:SetJustifyH("LEFT")

                r.cl = r:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                r.cl:SetPoint("LEFT", r.ra, "RIGHT"); r.cl:SetWidth(80); r.cl:SetJustifyH("LEFT")

                r.s = r:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                r.s:SetPoint("LEFT", r.cl, "RIGHT"); r.s:SetWidth(55); r.s:SetJustifyH("LEFT")

                r.h = r:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                r.h:SetPoint("LEFT", r.s, "RIGHT"); r.h:SetWidth(50); r.h:SetJustifyH("LEFT")

                r.m = r:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
                r.m:SetPoint("LEFT", r.h, "RIGHT"); r.m:SetWidth(50); r.m:SetJustifyH("LEFT")

                rows[i] = r
            end
            
            return scroll, rows
        end

        self.blScroll, self.blRows = BuildList(normalFrame, "GRS_NormalBL")
        self.pblScroll, self.pblRows = BuildList(permaFrame, "GRS_PermaBL")

        self.blScroll:SetScript("OnVerticalScroll", function(s, offset)
            FauxScrollFrame_OnVerticalScroll(s, offset, 20, function() self:UpdateBlacklistScroll() end)
        end)
        
        self.pblScroll:SetScript("OnVerticalScroll", function(s, offset)
            FauxScrollFrame_OnVerticalScroll(s, offset, 20, function() self:UpdateBlacklistScroll() end)
        end)

        parent:SetScript("OnShow", function()
            if GR.PruneExpiredBlacklist then GR:PruneExpiredBlacklist() end
            self:UpdateBlacklistScroll()
        end)
    end

    -- =========================================================================
    -- Blacklist Logic & Sync
    -- =========================================================================

    function GR:GetBlacklistAsArray(dbTable)
        local arr = {}
        for k, v in pairs(dbTable) do
            if type(v) == "table" then
                table.insert(arr, v)
            else
                table.insert(arr, {name = k, rio = 0, heroic = "-", mythic = "-", fullClass = "Unknown"})
            end
        end
        table.sort(arr, function(a, b) return a.name < b.name end)
        return arr
    end

    function GR:UpdateBlacklistScroll()
        -- Update Normal List
        local list = self:GetBlacklistAsArray(self.db.blacklist)
        FauxScrollFrame_Update(self.blScroll, #list, #self.blRows, 20)
        local offset = FauxScrollFrame_GetOffset(self.blScroll)
        
        for i, r in ipairs(self.blRows) do
            local idx = offset + i
            if idx <= #list then
                local d = list[idx]
                r.data = d; r:Show()
                r.n:SetText(d.name); r.ra:SetText(d.race or "-"); r.cl:SetText(d.fullClass or "-")
                r.s:SetText(d.rio or 0); r.h:SetText(d.heroic or "-"); r.m:SetText(d.mythic or "-")
                r.c:SetChecked(d.selected or false)
            else r:Hide() end
        end

        -- Update Permanent List
        local pList = self:GetBlacklistAsArray(self.db.permaBlacklist)
        FauxScrollFrame_Update(self.pblScroll, #pList, #self.pblRows, 20)
        local pOffset = FauxScrollFrame_GetOffset(self.pblScroll)

        for i, r in ipairs(self.pblRows) do
            local idx = pOffset + i
            if idx <= #pList then
                local d = pList[idx]
                r.data = d; r:Show()
                r.n:SetText(d.name); r.ra:SetText(d.race or "-"); r.cl:SetText(d.fullClass or "-")
                r.s:SetText(d.rio or 0); r.h:SetText(d.heroic or "-"); r.m:SetText(d.mythic or "-")
                r.c:SetChecked(d.selected or false)
            else r:Hide() end
        end
    end

    function GR:PruneExpiredBlacklist()
        if not self.db.automateReset then return end
        local limit = self.db.resetDuration or 604800
        local now = time()
        local pruned = 0
        
        -- ONLY prune normal blacklist, never permaBlacklist
        for k, v in pairs(self.db.blacklist) do
            if v.addedAt and (now - v.addedAt > limit) then
                self.db.blacklist[k] = nil
                pruned = pruned + 1
            end
        end
        
        if pruned > 0 then
            print("GRS: Auto-Pruned " .. pruned .. " expired blacklist entries.")
            if self.views and self.views[2] and self.views[2].IsShown and self.views[2]:IsShown() then
                self:UpdateBlacklistScroll()
            end
        end
    end

    function GR:NormalizeName(name)
        if not string.find(name, "-") then
            return name .. "-" .. GetRealmName()
        end
        return name
    end

    function GR:AddToBlacklist(name)
        if not name then return end
        name = self:NormalizeName(name)
        
        -- Check if in Perma list first - if so, do nothing or notify?
        if self.db.permaBlacklist[name] then
            print("GRS: " .. name .. " is already PERMANENTLY blacklisted.")
            return
        end

        local data = self:FindPlayerData(name) or self:CreateBlankData(name)
        data.addedAt = time()
        
        self.db.blacklist[name] = data
        
        self:CleanUpScanResults(name)
        if self.AddToRecent then self:AddToRecent(name, "Blacklisted") end
        if self:IsViewVisible(2) then self:UpdateBlacklistScroll() end
    end

    function GR:AddToPermaBlacklist(name)
        if not name then return end
        name = self:NormalizeName(name)

        local data = self.db.blacklist[name] -- Check if upgrading from normal
        if not data then
             data = self:FindPlayerData(name) or self:CreateBlankData(name)
        end
        
        -- Move/Add to Perma
        self.db.permaBlacklist[name] = data
        self.db.blacklist[name] = nil -- Remove from normal
        
        self:CleanUpScanResults(name)
        print("GRS: " .. name .. " added to PERMANENT Blacklist.")
        
        if self.AddToRecent then self:AddToRecent(name, "PERMA-BANNED") end
        if self:IsViewVisible(2) then self:UpdateBlacklistScroll() end
    end

    function GR:FindPlayerData(name)
        for _, p in ipairs(self.foundPlayers or {}) do
            local pName = p.name
            if not string.find(pName, "-") then pName = pName .. "-" .. GetRealmName() end
            if pName == name then return p end
        end
        return nil
    end

    function GR:CreateBlankData(name)
        return {
            name = name,
            race = "Unknown",
            fullClass = "Unknown",
            rio = 0,
            heroic = "-",
            mythic = "-",
            level = 0,
            zone = "Unknown",
            addedAt = time()
        }
    end

    function GR:CleanUpScanResults(name)
        if self.RemovePlayer then self:RemovePlayer(name) end
        local shortName = string.match(name, "^(.-)-")
        if shortName and self.RemovePlayer then self:RemovePlayer(shortName) end
    end
    
    function GR:IsViewVisible(id)
        return self.views and self.views[id] and self.views[id].IsShown and self.views[id]:IsShown()
    end

    function GR:RemoveSelectedFromBlacklist()
        -- Check Normal List
        local list = self:GetBlacklistAsArray(self.db.blacklist)
        for _, d in ipairs(list) do
            if d.selected then
                self.db.blacklist[d.name] = nil
                if not string.find(d.name, "-") then
                    self.db.blacklist[d.name .. "-" .. GetRealmName()] = nil
                end
            end
        end
        
        -- Check Perma List
        local pList = self:GetBlacklistAsArray(self.db.permaBlacklist)
        for _, d in ipairs(pList) do
            if d.selected then
                self.db.permaBlacklist[d.name] = nil
                if not string.find(d.name, "-") then
                    self.db.permaBlacklist[d.name .. "-" .. GetRealmName()] = nil
                end
            end
        end
        
        self:UpdateBlacklistScroll()
    end

    function GR:ScanGuildForBlacklistMatches()
        if not IsInGuild() then return end
        
        -- Logic: If a guild member is in Normal Blacklist, move to Perma Blacklist.
        local totalMembers = GetNumGuildMembers()
        local moves = 0
        
        for i = 1, totalMembers do
            local fullName, _, _, _, _, _, _, _, online, _, classFileName = GetGuildRosterInfo(i)
            if fullName then
                fullName = self:NormalizeName(fullName)
                
                if self.db.blacklist[fullName] then
                    -- Match found in Normal list. Move to Perma.
                    self:AddToPermaBlacklist(fullName)
                    moves = moves + 1
                end
            end
        end
        
        if moves > 0 then
            print("GRS: Moved " .. moves .. " guild members from Normal to Permanent blacklist.")
        end
    end

    function GR:SyncBlacklist()
        if not IsInGuild() then
            print("GRS: You must be in a guild to sync.")
            return
        end
        print("GRS: Sending Normal blacklist to guild members...")
        
        -- NOTE: We only sync NORMAL blacklist, per standard behavior, unless requested otherwise.
        -- If user wants to sync Perma, we would need a different prefix or flag. 
        -- Sticking to standard blacklist for now as requested by functionality context implied.
        
        local str = ""
        local count = 0
        for name, d in pairs(self.db.blacklist) do
            local entry = string.format("%s:%s:%s:%s", name, d.rio or 0, d.heroic or "-", d.mythic or "-")
            if #str + #entry + 1 > 240 then
                C_ChatInfo.SendAddonMessage("GRS_SYNC", str, "GUILD")
                str = entry
            else
                if str == "" then str = entry else str = str .. "|" .. entry end
            end
            count = count + 1
        end
        if str ~= "" then C_ChatInfo.SendAddonMessage("GRS_SYNC", str, "GUILD") end
        print("GRS: Sent " .. count .. " entries.")
    end

    function GR:ManualBlacklist()
        local toBlacklist = {}
        for _, p in ipairs(self.foundPlayers) do
            if p.selected then table.insert(toBlacklist, p.name) end
        end
        if #toBlacklist == 0 then print("No players selected to blacklist."); return end
        for _, name in ipairs(toBlacklist) do self:AddToBlacklist(name) end
        print(string.format("Added %d players to blacklist.", #toBlacklist))
    end

    function GR:ResetBlacklist()
        self.db.blacklist = {}
        -- Do not wipe Perma list here
        if self:IsViewVisible(2) then self:UpdateBlacklistScroll() end
        print("GRS: Normal Blacklist wiped. Permanent list remains.")
    end
end