local _, ns = ...

------------------------------------------------------------
-- Raid addon scanner: pings the raid via addon comm, waits
-- for responses, and shows a modal listing who has the addon
-- installed and who doesn't.
------------------------------------------------------------

local COMM_PREFIX = "YYH_SCAN"
C_ChatInfo.RegisterAddonMessagePrefix(COMM_PREFIX)

ns.AddonScanner = ns.AddonScanner or {}
local AS = ns.AddonScanner

local SCAN_DURATION = 3.0  -- seconds to wait for replies

local scanInProgress = false
local responders = {}  -- [shortName] = true

------------------------------------------------------------
-- Modal UI
------------------------------------------------------------

local win

local function styleBox(f, bgA)
    f:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8x8",
        edgeFile = "Interface\\Buttons\\WHITE8x8",
        edgeSize = 1,
        insets = { left = 0, right = 0, top = 0, bottom = 0 },
    })
    f:SetBackdropColor(0.04, 0.04, 0.04, bgA or 0.95)
    f:SetBackdropBorderColor(0.35, 0.35, 0.35, 1)
end

local function build()
    if win then return win end
    win = CreateFrame("Frame", "YippYappAddonScan", UIParent, "BackdropTemplate")
    win:SetSize(320, 360)
    win:SetPoint("CENTER")
    win:SetMovable(true)
    win:EnableMouse(true)
    win:RegisterForDrag("LeftButton")
    win:SetScript("OnDragStart", win.StartMoving)
    win:SetScript("OnDragStop", win.StopMovingOrSizing)
    win:SetFrameStrata("DIALOG")
    styleBox(win)
    win:Hide()

    local title = win:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    title:SetPoint("TOP", 0, -10)
    title:SetText("Raid Addon Scan")

    local close = CreateFrame("Button", nil, win, "BackdropTemplate")
    close:SetSize(20, 20)
    close:SetPoint("TOPRIGHT", -6, -6)
    styleBox(close, 0.9)
    local cLabel = close:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    cLabel:SetPoint("CENTER"); cLabel:SetText("x")
    close:SetScript("OnClick", function() win:Hide() end)

    local status = win:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    status:SetPoint("TOP", title, "BOTTOM", 0, -4)
    win.status = status

    local scroll = CreateFrame("ScrollFrame", nil, win, "UIPanelScrollFrameTemplate")
    scroll:SetPoint("TOPLEFT", 12, -50)
    scroll:SetPoint("BOTTOMRIGHT", -28, 40)
    local content = CreateFrame("Frame", nil, scroll)
    content:SetSize(280, 1)
    scroll:SetScrollChild(content)
    win.content = content

    -- Rescan button
    local rescan = CreateFrame("Button", nil, win, "BackdropTemplate")
    rescan:SetSize(100, 22)
    rescan:SetPoint("BOTTOM", 0, 10)
    styleBox(rescan, 0.9)
    local rLabel = rescan:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    rLabel:SetPoint("CENTER"); rLabel:SetText("Rescan")
    rescan:SetScript("OnEnter", function(self) self:SetBackdropBorderColor(0, 0.8, 1, 1) end)
    rescan:SetScript("OnLeave", function(self) self:SetBackdropBorderColor(0.35, 0.35, 0.35, 1) end)
    rescan:SetScript("OnClick", function() AS:Start() end)

    return win
end

local function renderResults()
    local w = build()
    for _, c in ipairs({ w.content:GetChildren() }) do c:Hide(); c:SetParent(nil) end
    for _, fs in ipairs(w.content.__fs or {}) do fs:Hide() end
    w.content.__fs = {}

    local hasCount, missCount = 0, 0
    local y = 0

    local function addRow(name, class, hasAddon)
        local row = CreateFrame("Frame", nil, w.content)
        row:SetSize(w.content:GetWidth(), 18)
        row:SetPoint("TOPLEFT", 0, -y)
        local bg = row:CreateTexture(nil, "BACKGROUND")
        bg:SetAllPoints()
        bg:SetColorTexture(0.08, 0.08, 0.08, 0.5)

        local c = class and RAID_CLASS_COLORS and RAID_CLASS_COLORS[class]
        local nameText = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        nameText:SetPoint("LEFT", 6, 0)
        if c then nameText:SetTextColor(c.r, c.g, c.b) end
        nameText:SetText(name)

        local statusText = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        statusText:SetPoint("RIGHT", -6, 0)
        if hasAddon then
            statusText:SetText("|cff33ff33yes|r")
        else
            statusText:SetText("|cffff5555no|r")
        end
        y = y + 20
    end

    if IsInRaid() then
        for i = 1, GetNumGroupMembers() do
            local name, _, _, _, _, class = GetRaidRosterInfo(i)
            if name then
                local short = Ambiguate(name, "short")
                local hasAddon = responders[short] or short == UnitName("player")
                if hasAddon then hasCount = hasCount + 1 else missCount = missCount + 1 end
                addRow(name, class, hasAddon)
            end
        end
    else
        addRow(UnitName("player"), select(2, UnitClass("player")), true)
        hasCount = 1
        for i = 1, GetNumGroupMembers() - 1 do
            local unit = "party" .. i
            if UnitExists(unit) then
                local name = UnitName(unit)
                local _, class = UnitClass(unit)
                local short = name and Ambiguate(name, "short")
                local hasAddon = short and responders[short]
                if hasAddon then hasCount = hasCount + 1 else missCount = missCount + 1 end
                addRow(name or "?", class, hasAddon)
            end
        end
    end

    w.content:SetHeight(y + 10)
    w.status:SetText(string.format("|cff33ff33%d with|r / |cffff5555%d without|r", hasCount, missCount))
end

------------------------------------------------------------
-- Scan lifecycle
------------------------------------------------------------

function AS:Start()
    if scanInProgress then return end
    scanInProgress = true
    wipe(responders)

    local channel = IsInRaid() and "RAID" or IsInGroup() and "PARTY" or nil
    if not channel then
        build().status:SetText("|cffffff00Not in a group|r")
        renderResults()
        build():Show()
        scanInProgress = false
        return
    end

    C_ChatInfo.SendAddonMessage(COMM_PREFIX, "PING", channel)
    -- Our own client answers its own PING automatically, but include us.
    responders[UnitName("player")] = true

    build():Show()
    build().status:SetText("Scanning...")

    C_Timer.After(SCAN_DURATION, function()
        scanInProgress = false
        renderResults()
    end)
end

function AS:Open()
    build():Show()
    if next(responders) == nil then
        AS:Start()
    else
        renderResults()
    end
end

------------------------------------------------------------
-- Event plumbing
------------------------------------------------------------

local f = CreateFrame("Frame")
f:RegisterEvent("CHAT_MSG_ADDON")
f:SetScript("OnEvent", function(_, _, prefix, msg, _, sender)
    if prefix ~= COMM_PREFIX or not sender then return end
    local short = Ambiguate(sender, "short")
    if msg == "PING" then
        -- Respond so the sender knows we have the addon.
        local channel = IsInRaid() and "RAID" or IsInGroup() and "PARTY" or nil
        if channel then
            C_ChatInfo.SendAddonMessage(COMM_PREFIX, "PONG", channel)
        end
    elseif msg == "PONG" or msg == "PING" then
        responders[short] = true
    end
end)

SLASH_YYHSCAN1 = "/yyhscan"
SlashCmdList.YYHSCAN = function() AS:Open() end
