local rndx = include("lib/rndx.lua")
local logo = Material("nocode/announcement/logo.png")

BladW = BladW or {}
BladW.Announcement = BladW.Announcement or {}

-- mêmes couleurs que les annonces
local COL_BG         = Color(0, 0, 0, 200)
local COL_PANEL      = Color(0, 0, 0, 160)
local COL_ACCENT     = Color(76, 119, 200)
local COL_ACCENT_DIM = Color(60, 90, 150)
local COL_TEXT       = Color(255, 255, 255)
local COL_RED        = Color(255, 80, 80)
local COL_GRAY       = Color(54, 54, 54, 255)
local COL_MUTED      = Color(160, 160, 160)
local COL_WARN       = Color(255, 200, 50)
local COL_LINE       = Color(255, 255, 255, 60)

-- couleur des contours extérieurs selon la config ("blue" ou "white")
local function OuterCol()
    return (BladW.Announcement.Conf or {}).announcement_theme == "white" and COL_TEXT or COL_ACCENT
end

-- nb de caractères d'un champ (UTF-8, un accent = 1)
local function EntryLen(entry)
    local v = entry:GetValue()
    return utf8.len(v) or #v
end

-- petit triangle warning dessiné à la main (comme ça pas besoin de font emoji)
local function DrawWarning(x, y, size)
    draw.NoTexture()
    surface.SetDrawColor(COL_WARN)
    surface.DrawPoly({
        { x = x + size * 0.5, y = y },
        { x = x + size,       y = y + size },
        { x = x,              y = y + size },
    })
    draw.SimpleText("!", "DermaDefaultBold", x + size * 0.5, y + size * 0.62, Color(30, 30, 30), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end

-- mon style pour les champs de texte
local function StyleEntry(entry, placeholder, default)
    entry:SetFont("bladw_text_Medium")
    entry:SetText(default or "")
    entry:SetPlaceholderText(placeholder or "")
    entry:SetTextColor(COL_TEXT)
    entry:SetPaintBackground(false)
    entry.Paint = function(self, w, h)
        rndx.Draw(10, 0, 0, w, h, COL_PANEL, rndx.SHAPE_FIGMA)
        local outline = self:IsEditing() and COL_ACCENT or COL_LINE
        rndx.DrawOutlined(10, 0, 0, w, h, outline, 2, rndx.SHAPE_FIGMA)
        self:DrawTextEntryText(COL_TEXT, COL_ACCENT, COL_TEXT)
    end
end

-- petite flèche bas
local function DrawArrow(w, h)
    draw.NoTexture()
    surface.SetDrawColor(COL_MUTED)
    local ax = w - 24
    surface.DrawPoly({
        { x = ax,      y = h * 0.5 - 2 },
        { x = ax + 10, y = h * 0.5 - 2 },
        { x = ax + 5,  y = h * 0.5 + 4 },
    })
end

local LIST_H = 130 -- hauteur du panneau de cases une fois ouvert
local LIST_Y = 440 -- haut du panneau

local function OpenAAdminMenu()

    -- si le menu est déjà ouvert je le vire
    if IsValid(BladW_AdminMenu) then BladW_AdminMenu:Remove() end

    local selectedPreset = ""
    local maxLen = (BladW.Announcement.Conf or {}).announcement_max_length or 120

    -- destinataires : scope + sélection multiple
    local scope, scopeLabel = "all", "Tout le monde"
    local selGroups, selPlayers = {}, {}
    local expand = 0 -- 0 = replié, 1 = ouvert (animé)

    local frame = vgui.Create("DFrame")
    BladW_AdminMenu = frame
    frame:SetSize(500, 640) -- taille max -> sert au centrage, on démarre replié
    frame:Center()
    frame:SetTall(498)
    frame:SetTitle("")
    frame:ShowCloseButton(false)
    frame:MakePopup()

    frame.Paint = function(self, w, h)
        rndx.Draw(20, 0, 0, w, h, nil, rndx.SHAPE_FIGMA + rndx.BLUR)
        rndx.Draw(20, 0, 0, w, h, COL_BG, rndx.SHAPE_FIGMA)
        rndx.DrawOutlined(20, 0, 0, w, h, OuterCol(), 3, rndx.SHAPE_FIGMA)

        rndx.DrawMaterial(0, w * 0.5 - 30, 20, 60, 60, COL_TEXT, logo)
        draw.SimpleText("Envoyer une annonce", "bladw_text", w * 0.5, 94, COL_TEXT, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
        draw.SimpleText("Presets", "bladw_text_Medium", 40, 118, COL_TEXT, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
        draw.SimpleText("Destinataires", "bladw_text_Medium", 40, 372, COL_TEXT, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
    end

    -- bouton fermer
    local close = vgui.Create("DButton", frame)
    close:SetSize(30, 30)
    close:SetPos(frame:GetWide() - 42, 14)
    close:SetText("")
    close.Paint = function(self, w, h)
        rndx.Draw(8, 0, 0, w, h, self:IsHovered() and COL_RED or COL_GRAY, rndx.SHAPE_FIGMA)
        draw.SimpleText("X", "bladw_text_Medium", w * 0.5, h * 0.5, COL_TEXT, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
    end
    close.DoClick = function() frame:Remove() end

    -- champs
    local titleEntry = vgui.Create("DTextEntry", frame)
    titleEntry:SetPos(40, 240)
    titleEntry:SetSize(420, 40)
    StyleEntry(titleEntry, "Titre de l'annonce", "Annonce")

    local msgEntry = vgui.Create("DTextEntry", frame)
    msgEntry:SetPos(40, 288)
    msgEntry:SetSize(420, 40)
    StyleEntry(msgEntry, "Message de l'annonce")
    msgEntry.Paint = function(self, w, h)
        local over = EntryLen(self) > maxLen
        rndx.Draw(10, 0, 0, w, h, COL_PANEL, rndx.SHAPE_FIGMA)
        local outline = over and COL_RED or (self:IsEditing() and COL_ACCENT or COL_LINE)
        rndx.DrawOutlined(10, 0, 0, w, h, outline, over and 3 or 2, rndx.SHAPE_FIGMA)
        self:DrawTextEntryText(COL_TEXT, COL_ACCENT, COL_TEXT)
    end

    -- ligne du bas : warning à gauche, compteur à droite
    local status = vgui.Create("DPanel", frame)
    status:SetPos(40, 332)
    status:SetSize(420, 26)
    status:SetPaintBackground(false)
    status.Paint = function(self, w, h)
        local len  = EntryLen(msgEntry)
        local over = len > maxLen

        if frame.sendFeedback and (frame.sendFeedbackUntil or 0) > SysTime() then
            DrawWarning(0, h * 0.5 - 8, 16)
            draw.SimpleText(frame.sendFeedback, "bladw_text_Medium", 24, h * 0.5, COL_WARN, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
        elseif over then
            DrawWarning(0, h * 0.5 - 8, 16)
            draw.SimpleText("Trop de caractères", "bladw_text_Medium", 24, h * 0.5, COL_RED, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
        end

        draw.SimpleText(len .. " / " .. maxLen, "bladw_text_Medium", w, h * 0.5,
            over and COL_RED or COL_MUTED, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER)
    end

    -- panneau de cases (groupes ou joueurs), hauteur animée
    local list = vgui.Create("DScrollPanel", frame)
    list:SetPos(40, LIST_Y)
    list:SetSize(420, 1)
    list.Paint = function(self, w, h)
        rndx.Draw(8, 0, 0, w, h, Color(0, 0, 0, 90), rndx.SHAPE_FIGMA)
    end
    local vbar = list:GetVBar()
    vbar:SetWide(8)
    vbar.Paint = function() end
    vbar.btnUp.Paint = function() end
    vbar.btnDown.Paint = function() end
    vbar.btnGrip.Paint = function(self, w, h)
        rndx.Draw(4, 0, 0, w, h, COL_LINE, rndx.SHAPE_FIGMA)
    end

    local function AddRow(label, isChecked, onToggle)
        local row = list:Add("DButton")
        row:Dock(TOP)
        row:DockMargin(4, 4, 8, 0)
        row:SetTall(28)
        row:SetText("")
        row.Paint = function(self, w, h)
            rndx.Draw(6, 0, 0, w, h, COL_PANEL, rndx.SHAPE_FIGMA)
            local bs, bx = 18, 8
            local by = (h - bs) * 0.5
            rndx.DrawOutlined(4, bx, by, bs, bs, isChecked() and COL_ACCENT or COL_LINE, 2, rndx.SHAPE_FIGMA)
            if isChecked() then
                rndx.Draw(3, bx + 4, by + 4, bs - 8, bs - 8, COL_ACCENT, rndx.SHAPE_FIGMA)
            end
            draw.SimpleText(label, "bladw_text_Medium", bx + bs + 10, h * 0.5, COL_TEXT, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
        end
        row.DoClick = function() onToggle() end
    end

    local function RebuildList()
        list:Clear()

        if scope == "group" then
            local seen = {}
            for _, p in ipairs(player.GetAll()) do
                local g = p:GetUserGroup()
                if g and g ~= "" and not seen[g] then
                    seen[g] = true
                    AddRow(g, function() return selGroups[g] end, function()
                        selGroups[g] = (not selGroups[g]) or nil
                    end)
                end
            end
        elseif scope == "players" then
            for _, p in ipairs(player.GetAll()) do
                AddRow(p:Nick(), function() return selPlayers[p] end, function()
                    selPlayers[p] = (not selPlayers[p]) or nil
                end)
            end
        end
    end

    -- dropdown du scope
    local scopeBtn = vgui.Create("DButton", frame)
    scopeBtn:SetPos(40, 392)
    scopeBtn:SetSize(420, 40)
    scopeBtn:SetText("")
    scopeBtn.Paint = function(self, w, h)
        rndx.Draw(10, 0, 0, w, h, COL_PANEL, rndx.SHAPE_FIGMA)
        rndx.DrawOutlined(10, 0, 0, w, h, self:IsHovered() and COL_ACCENT or COL_LINE, 2, rndx.SHAPE_FIGMA)
        draw.SimpleText(scopeLabel, "bladw_text_Medium", 12, h * 0.5, COL_TEXT, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
        DrawArrow(w, h)
    end
    scopeBtn.DoClick = function(self)
        local menu = DermaMenu()
        menu:SetMinimumWidth(self:GetWide())
        menu.Paint = function(s, w, h)
            rndx.Draw(8, 0, 0, w, h, Color(18, 18, 18, 252), rndx.SHAPE_FIGMA)
            rndx.DrawOutlined(8, 0, 0, w, h, COL_LINE, 1, rndx.SHAPE_FIGMA)
        end

        local function opt(label, id)
            local o = menu:AddOption(label, function()
                scope, scopeLabel = id, label
                RebuildList()
            end)
            o:SetTall(30)
            o:SetText("")
            o.Paint = function(s, w, h)
                if s:IsHovered() then rndx.Draw(6, 3, 1, w - 6, h - 2, COL_ACCENT, rndx.SHAPE_FIGMA) end
                draw.SimpleText(label, "bladw_text_Medium", 12, h * 0.5, COL_TEXT, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
            end
        end

        opt("Tout le monde", "all")
        opt("Groupe", "group")
        opt("Joueurs", "players")

        local mx, my = self:LocalToScreen(0, self:GetTall() + 2)
        menu:Open(mx, my)
    end

    -- bouton envoyer (position gérée par le Think selon l'ouverture)
    local send = vgui.Create("DButton", frame)
    send:SetPos(40, LIST_Y)
    send:SetSize(420, 44)
    send:SetText("")
    send.Paint = function(self, w, h)
        local over = EntryLen(msgEntry) > maxLen
        local col  = over and COL_GRAY or (self:IsHovered() and COL_ACCENT or COL_ACCENT_DIM)
        rndx.Draw(12, 0, 0, w, h, col, rndx.SHAPE_FIGMA)
        draw.SimpleText("Envoyer", "bladw_text", w * 0.5, h * 0.5, over and COL_MUTED or COL_TEXT, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
    end
    send.DoClick = function()
        local function fail(msg)
            frame.sendFeedback = msg
            frame.sendFeedbackUntil = SysTime() + 4
            surface.PlaySound("buttons/button10.wav")
        end

        if EntryLen(msgEntry) > maxLen then return fail("Trop de caractères") end
        if msgEntry:GetValue() == "" and selectedPreset == "" then return fail("Message vide") end

        local groups, players = {}, {}
        if scope == "group" then
            for g in pairs(selGroups) do groups[#groups + 1] = g end
            if #groups == 0 then return fail("Choisis au moins un groupe") end
        elseif scope == "players" then
            for p in pairs(selPlayers) do if IsValid(p) then players[#players + 1] = p end end
            if #players == 0 then return fail("Choisis au moins un joueur") end
        end

        net.Start("bladWSendAnnouncement")
            net.WriteString(selectedPreset)
            net.WriteString(titleEntry:GetValue())
            net.WriteString(msgEntry:GetValue())
            net.WriteString(scope)
            if scope == "group" then
                net.WriteUInt(#groups, 8)
                for _, g in ipairs(groups) do net.WriteString(g) end
            elseif scope == "players" then
                net.WriteUInt(#players, 8)
                for _, p in ipairs(players) do net.WriteEntity(p) end
            end
        net.SendToServer()
    end

    -- ESC ferme le menu (sans menu pause) + animation d'ouverture du panneau
    frame.Think = function(self)
        if gui.IsGameUIVisible() then
            gui.HideGameUI()
            self:Remove()
            return
        end

        local target = (scope == "all") and 0 or 1
        expand = Lerp(FrameTime() * 12, expand, target)
        if math.abs(expand - target) < 0.002 then expand = target end

        local lh = math.Round(expand * LIST_H)
        list:SetVisible(lh > 2)
        list:SetTall(math.max(lh, 1))

        local sy = LIST_Y + lh + (lh > 0 and 12 or 0)
        send:SetPos(40, sy)
        self:SetTall(sy + send:GetTall() + 14)
    end

    -- boutons preset : remplissent les champs, retiennent le preset et règlent les destinataires
    local presets = vgui.Create("DIconLayout", frame)
    presets:SetPos(40, 134)
    presets:SetSize(420, 90)
    presets:SetSpaceX(8)
    presets:SetSpaceY(8)

    for key, preset in SortedPairs(BladW.Announcement.Presets or {}) do
        local b = presets:Add("DButton")
        b:SetSize(134, 34)
        b:SetText("")
        b.Paint = function(self, w, h)
            local on = (selectedPreset == key) or self:IsHovered()
            rndx.Draw(8, 0, 0, w, h, on and COL_ACCENT or COL_GRAY, rndx.SHAPE_FIGMA)
            draw.SimpleText(preset.title or key, "bladw_text_Medium", w * 0.5, h * 0.5, COL_TEXT, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
        end
        b.DoClick = function()
            selectedPreset = key
            titleEntry:SetText(preset.title or "")
            msgEntry:SetText(preset.text or "")

            for k in pairs(selGroups)  do selGroups[k]  = nil end
            for k in pairs(selPlayers) do selPlayers[k] = nil end
            local t = preset.target
            if not t or t == "" or t == "all" then
                scope, scopeLabel = "all", "Tout le monde"
            else
                scope, scopeLabel = "group", "Groupe"
                selGroups[t] = true
            end
            RebuildList()
        end
    end

    RebuildList()

end

-- réponse du serveur après un envoi : publié -> on ferme, refusé -> on garde le menu + on dit pourquoi
net.Receive("bladWAnnouncementResult", function()
    local ok   = net.ReadBool()
    local left = net.ReadUInt(8)

    if not IsValid(BladW_AdminMenu) then return end

    if ok then
        BladW_AdminMenu:Remove()
    else
        BladW_AdminMenu.sendFeedback      = left > 0 and ("Annonce déjà en cours (" .. left .. "s)") or "Envoi impossible"
        BladW_AdminMenu.sendFeedbackUntil = SysTime() + 5
    end
end)

return OpenAAdminMenu
