-- EbonholdHub: modules/ui/ActivityFeed.lua
-- Compact horizontal activity feed for Auto Pick.
-- Echo icons enter from the right edge and crawl to the left edge (conveyor belt).
-- Replaces the large automation Toast window.

EbonholdHub.ActivityFeed = {}
local AF = EbonholdHub.ActivityFeed

local ST   = EbonholdHub.SiteTheme
local SW   = EbonholdHub.SiteWidgets
local SC   = ST.C
local FLAT = ST.FLAT

-- ── Layout ────────────────────────────────────────────────────────────────────

local ICON_SIZE     = 32
local ICONS_AREA_W  = 296                 -- full width of the icon conveyor
local H_PAD         = 6                   -- horizontal outer padding
local TITLE_H       = 16                  -- "AUTO PICK" top bar
local CHARGES_H     = 16                  -- charges bottom bar
local ICON_ROW_H    = ICON_SIZE + 8       -- icon row (top+bottom padding)
local STRIP_H       = TITLE_H + ICON_ROW_H + CHARGES_H   -- 64px total
local STRIP_W       = ICONS_AREA_W + H_PAD * 2

-- ── Timing & animation ────────────────────────────────────────────────────────

local ICON_SPEED     = 38     -- pixels per second (crosses full width in ~8s)
local ENTRY_LIFETIME = 10.0   -- seconds an icon lives (hard cap)
local FADE_ZONE      = 56     -- pixels from LEFT edge where fade begins
local LINGER_SECS    = 1.5    -- strip lingers N sec after last icon fades
local POOL_SIZE      = 16     -- max simultaneous icons in pool

-- ── Action styles ─────────────────────────────────────────────────────────────

local ACTION_STYLE = {
    Select              = { r = 0.20, g = 0.90, b = 0.35 },  -- green  — picked
    ["Select (Locked)"] = { r = 1.00, g = 0.80, b = 0.00 },  -- gold   — locked echo
    ["Select (Repeat)"] = { r = 0.50, g = 0.90, b = 0.50 },  -- pale green
    Banish              = { r = 0.95, g = 0.28, b = 0.28 },  -- red
    Reroll              = { r = 0.27, g = 0.67, b = 1.00 },  -- blue
    Freeze              = { r = 0.40, g = 0.88, b = 1.00 },  -- cyan
}

local QUALITY_COLORS = {
    [0] = { 1.00, 1.00, 1.00, 1 },
    [1] = { 0.12, 1.00, 0.00, 1 },
    [2] = { 0.00, 0.44, 0.87, 1 },
    [3] = { 0.64, 0.21, 0.93, 1 },
    [4] = { 1.00, 0.50, 0.00, 1 },
}

local ACTION_LABEL = {
    Select              = "Picked",
    ["Select (Locked)"] = "Locked pick",
    ["Select (Repeat)"] = "Repeat pick",
    Banish              = "Banished",
    Reroll              = "Rerolled",
    Freeze              = "Frozen",
}

local function GetStyle(action)
    if not action then return ACTION_STYLE.Select end
    return ACTION_STYLE[action]
        or ACTION_STYLE[action:match("^%a+")]
        or ACTION_STYLE.Select
end

-- ── State ─────────────────────────────────────────────────────────────────────

local frame        -- root strip frame (UIParent child)
local iconsArea    -- Frame hosting icon frames
local chargesText  -- FontString "Banish N  Reroll N  Freeze N"
local topBarGrad   -- 3px left stripe texture — repainted with class color
local topBarTitle  -- FontString "AUTO PICK" — repainted with class color
local pool    = {} -- pre-allocated icon frames
local entries = {} -- { frame, xActual, age }
local lingerTimer = 0
local chargesRefresh = 0

-- ── Charges ───────────────────────────────────────────────────────────────────

local function GetCharges()
    local rd = EbonholdPlayerRunData
    if not rd and ProjectEbonhold and ProjectEbonhold.PlayerRunService then
        local fn = ProjectEbonhold.PlayerRunService.GetCurrentData
        if fn then rd = fn() end
    end
    local ban    = (rd and rd.remainingBanishes)                                    or 0
    local reroll = rd and math.max(0, (rd.totalRerolls or 0) - (rd.usedRerolls  or 0)) or 0
    local freeze = rd and math.max(0, (rd.totalFreezes or 0) - (rd.usedFreezes  or 0)) or 0
    return ban, reroll, freeze
end

local function RefreshCharges()
    if not chargesText then return end
    local ban, re, fr = GetCharges()
    chargesText:SetText(string.format(
        "|cffff6666Banish %d|r   |cff66aaffReroll %d|r   |cff66ccffFreeze %d|r",
        ban, re, fr))
end

local function RefreshClassColor()
    if not topBarGrad then return end
    local build = EbonholdHub.Build and EbonholdHub.Build.GetActive and EbonholdHub.Build.GetActive()
    local classToken = build and build.class
    local cc = (classToken and ST.CLASS_COLORS and ST.CLASS_COLORS[classToken]) or SC.accent
    topBarGrad:SetVertexColor(cc[1], cc[2], cc[3], 1)
    if topBarTitle then topBarTitle:SetTextColor(cc[1], cc[2], cc[3]) end
end

-- ── Icon frame pool ───────────────────────────────────────────────────────────

-- POOL_SIZE defined in layout section

local function MakeIconFrame(parent)
    local f = CreateFrame("Frame", nil, parent)
    f:SetSize(ICON_SIZE, ICON_SIZE)
    f._inUse     = false
    f._echoName  = nil
    f._action    = nil

    -- Dark background
    local bg = f:CreateTexture(nil, "BACKGROUND")
    bg:SetTexture(FLAT)
    bg:SetVertexColor(0.08, 0.08, 0.10, 1)
    bg:SetAllPoints()

    -- Spell icon (inset 1px so the quality border shows)
    local ico = f:CreateTexture(nil, "ARTWORK")
    ico:SetPoint("TOPLEFT",     f, "TOPLEFT",     1, -1)
    ico:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -1, 1)
    f.icon = ico

    -- Quality border (1px, color set per entry)
    f.qBorder = SW.ThinBorder(f, { 1, 1, 1, 1 }, 1)

    -- Action dot: small square at bottom-right, color = action type
    local BADGE = 10
    local dotF = CreateFrame("Frame", nil, f)
    dotF:SetSize(BADGE, BADGE)
    dotF:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 3, -3)
    dotF:SetFrameLevel(f:GetFrameLevel() + 6)

    local dotBg = dotF:CreateTexture(nil, "BACKGROUND")
    dotBg:SetTexture(FLAT)
    dotBg:SetAllPoints()
    dotBg:SetVertexColor(0, 0, 0, 0.9)

    local dotColor = dotF:CreateTexture(nil, "ARTWORK")
    dotColor:SetTexture(FLAT)
    dotColor:SetPoint("TOPLEFT",     dotF, "TOPLEFT",     1, -1)
    dotColor:SetPoint("BOTTOMRIGHT", dotF, "BOTTOMRIGHT", -1, 1)
    f.actionDot = dotColor

    -- Hover: show tooltip
    f:EnableMouse(true)
    f:SetScript("OnEnter", function(self)
        if not self._echoName then return end
        GameTooltip:SetOwner(self, "ANCHOR_TOP")
        local actionLabel = ACTION_LABEL[self._action] or (self._action or "?")
        GameTooltip:AddLine("|cff" .. "ffffff" .. self._echoName .. "|r")
        local style = GetStyle(self._action)
        GameTooltip:AddLine(
            string.format("|cff%02x%02x%02x%s|r",
                math.floor(style.r * 255),
                math.floor(style.g * 255),
                math.floor(style.b * 255),
                actionLabel),
            1, 1, 1)
        GameTooltip:SetFrameStrata("TOOLTIP")
        GameTooltip:Show()
    end)
    f:SetScript("OnLeave", function() GameTooltip:Hide() end)

    f:Hide()
    return f
end

local function AcquireFrame()
    for _, f in ipairs(pool) do
        if not f._inUse then
            f._inUse = true
            return f
        end
    end
end

local function ReleaseFrame(f)
    f._inUse    = false
    f._echoName = nil
    f._action   = nil
    f:ClearAllPoints()
    f:Hide()
end

-- ── OnUpdate (conveyor belt) ──────────────────────────────────────────────────
-- Each icon moves at constant ICON_SPEED px/sec from right edge to left edge.
-- Icons are independent — no slot system, no lerp.

local iconY = -math.floor((ICON_ROW_H - ICON_SIZE) / 2)  -- vertical center in row

local function Tick(self, dt)
    if #entries == 0 then
        lingerTimer = lingerTimer + dt
        if lingerTimer >= LINGER_SECS then self:Hide() end
        return
    end
    lingerTimer = 0

    chargesRefresh = chargesRefresh + dt
    if chargesRefresh >= 1.5 then
        chargesRefresh = 0
        RefreshCharges()
    end

    local dead = {}
    for i, e in ipairs(entries) do
        e.xActual = e.xActual - ICON_SPEED * dt

        local px = math.floor(e.xActual)
        e.frame:ClearAllPoints()
        e.frame:SetPoint("TOPLEFT", iconsArea, "TOPLEFT", px, iconY)

        if px + ICON_SIZE <= 0 then
            e.frame:Hide()
        else
            e.frame:Show()
        end

        -- Fade by position: fully visible in middle, fades near left edge
        if px < FADE_ZONE and px + ICON_SIZE > 0 then
            e.frame:SetAlpha(math.max(0, px / FADE_ZONE))
        else
            e.frame:SetAlpha(1)
        end

        e.age = e.age + dt
        if e.age >= ENTRY_LIFETIME then dead[#dead + 1] = i end
    end

    for i = #dead, 1, -1 do
        ReleaseFrame(entries[dead[i]].frame)
        table.remove(entries, dead[i])
    end
end

-- ── Strip frame ───────────────────────────────────────────────────────────────

local function BuildFrame()
    local f = CreateFrame("Frame", "EbonholdHubActivityFeed", UIParent)
    f:SetSize(STRIP_W, STRIP_H)
    f:SetPoint("TOP", UIParent, "TOP", 0, -40)
    f:SetFrameStrata("HIGH")
    f:SetMovable(true)
    f:EnableMouse(true)
    f:SetClampedToScreen(true)
    f:SetScript("OnMouseDown", function(self, btn)
        if btn == "LeftButton" then self:StartMoving() end
    end)
    f:SetScript("OnMouseUp", function(self)
        self:StopMovingOrSizing()
    end)
    f:Hide()

    -- Main background + border
    SW.Fill(f, SC.bg)
    SW.ThinBorder(f, SC.border, 1)

    -- ── Top bar: "AUTO PICK" with class color stripe + tinted text ───────────
    local topBar = CreateFrame("Frame", nil, f)
    topBar:SetPoint("TOPLEFT",  f, "TOPLEFT",  1, -1)
    topBar:SetPoint("TOPRIGHT", f, "TOPRIGHT", -1, -1)
    topBar:SetHeight(TITLE_H)
    SW.Fill(topBar, SC.bgHeader)

    -- 3px left stripe — color updated by RefreshClassColor()
    topBarGrad = topBar:CreateTexture(nil, "ARTWORK")
    topBarGrad:SetWidth(3)
    topBarGrad:SetPoint("TOPLEFT",    topBar, "TOPLEFT",    0, 0)
    topBarGrad:SetPoint("BOTTOMLEFT", topBar, "BOTTOMLEFT", 0, 0)
    topBarGrad:SetTexture(FLAT)
    topBarGrad:SetVertexColor(SC.accent[1], SC.accent[2], SC.accent[3], 1)

    -- title text — color updated by RefreshClassColor() via titleLabel ref
    local title = topBar:CreateFontString(nil, "OVERLAY")
    SW.SetFont(title, 8, "semibold")
    title:SetTextColor(unpack(SC.accent))
    title:SetText("AUTO PICK")
    title:SetPoint("LEFT", topBar, "LEFT", 8, 0)
    topBarTitle = title

    -- Thin separator line below top bar
    local sepTop = f:CreateTexture(nil, "ARTWORK")
    sepTop:SetTexture(FLAT)
    sepTop:SetVertexColor(0.3, 0.3, 0.3, 0.5)
    sepTop:SetHeight(1)
    sepTop:SetPoint("TOPLEFT",  f, "TOPLEFT",  1, -(TITLE_H + 1))
    sepTop:SetPoint("TOPRIGHT", f, "TOPRIGHT", -1, -(TITLE_H + 1))

    -- ── Icons area (middle row) ───────────────────────────────────────────────
    iconsArea = CreateFrame("Frame", nil, f)
    iconsArea:SetPoint("TOPLEFT",     f, "TOPLEFT",     H_PAD, -TITLE_H)
    iconsArea:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -H_PAD, CHARGES_H)
    iconsArea:SetFrameLevel(f:GetFrameLevel() + 2)

    -- ── Bottom bar: charges ───────────────────────────────────────────────────
    -- Thin separator line above bottom bar
    local sepBot = f:CreateTexture(nil, "ARTWORK")
    sepBot:SetTexture(FLAT)
    sepBot:SetVertexColor(unpack(SC.border))
    sepBot:SetHeight(1)
    sepBot:SetPoint("BOTTOMLEFT",  f, "BOTTOMLEFT",  1, CHARGES_H)
    sepBot:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -1, CHARGES_H)

    local botBar = CreateFrame("Frame", nil, f)
    botBar:SetPoint("BOTTOMLEFT",  f, "BOTTOMLEFT",  1, 1)
    botBar:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -1, 1)
    botBar:SetHeight(CHARGES_H)
    SW.Fill(botBar, { SC.bgHeader[1], SC.bgHeader[2], SC.bgHeader[3], 0.8 })

    chargesText = botBar:CreateFontString(nil, "OVERLAY")
    SW.SetFont(chargesText, 9)
    chargesText:SetPoint("CENTER", botBar, "CENTER", 0, 0)
    chargesText:SetJustifyH("CENTER")
    chargesText:SetText("|cffff6666Banish 0|r   |cff66aaffReroll 0|r   |cff66ccffFreeze 0|r")

    for i = 1, POOL_SIZE do
        pool[i] = MakeIconFrame(iconsArea)
    end

    RefreshClassColor()
    f:SetScript("OnUpdate", Tick)
    return f
end

-- ── Public API ────────────────────────────────────────────────────────────────

-- Called by Automation.lua instead of Toast.ShowAutomationResult.
-- scored      = array of ScoreChoice entries (same format as Toast)
-- action      = "Select" | "Select (Locked)" | "Select (Repeat)" | "Banish" | "Reroll" | "Freeze"
-- targetIndex = scored[i].index of the acted-on echo (0 for Reroll)
function AF.Push(scored, action, targetIndex)
    if not frame then return end

    -- Resolve the target echo
    local spellId, quality, echoName = 0, 0, nil
    if targetIndex and targetIndex > 0 then
        for _, s in ipairs(scored or {}) do
            if s.index == targetIndex then
                spellId  = s.spellId  or 0
                quality  = s.quality  or 0
                echoName = s.name
                break
            end
        end
    elseif scored and scored[1] then
        -- Reroll: tag the best-scored echo so the dot is still informative
        spellId  = scored[1].spellId or 0
        quality  = scored[1].quality or 0
        echoName = scored[1].name
    end

    local f = AcquireFrame()
    if not f then return end

    -- Icon texture
    if spellId > 0 then
        f.icon:SetTexture(select(3, GetSpellInfo(spellId))
            or "Interface\\Icons\\INV_Misc_QuestionMark")
    else
        f.icon:SetTexture("Interface\\Icons\\Spell_Frost_SummonWaterElemental")
    end

    -- Quality border
    SW.SetBorderColor(f.qBorder, QUALITY_COLORS[quality] or QUALITY_COLORS[0])

    -- Action dot color
    local style = GetStyle(action)
    f.actionDot:SetVertexColor(style.r, style.g, style.b)

    -- Store for tooltip
    f._echoName = echoName
    f._action   = action

    f:SetAlpha(1)
    -- Spawn at right edge; Tick moves it leftward at ICON_SPEED px/sec
    f:ClearAllPoints()
    f:SetPoint("TOPLEFT", iconsArea, "TOPLEFT", ICONS_AREA_W, iconY)
    f:Show()

    entries[#entries + 1] = {
        frame   = f,
        xActual = ICONS_AREA_W,
        age     = 0,
    }
    RefreshCharges()
    RefreshClassColor()
    lingerTimer    = 0
    chargesRefresh = 0

    if not frame:IsShown() then frame:Show() end
end

function AF.Init()
    frame = BuildFrame()
end
