EbonholdHub.Toast = {}

local UI = EbonholdHub.UI
local C  = UI.Colors

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

local TOAST_W         = 420
local SIMPLE_MIN_W    = 220
local SIMPLE_MAX_W    = 520
local SIMPLE_PAD_X    = 12
local HEADER_H        = 26
local CHOICES_H       = 58
local CHARGES_BAR_H   = 24
local TOAST_H         = HEADER_H + CHOICES_H + CHARGES_BAR_H
local CHOICE_SLOTS    = 3
local ICON_SIZE       = 30
local SLOT_W          = 108
local SLOT_H          = 56
local FLAT          = ST.FLAT
local SELECT_ALPHA  = 0.85
local DIM_ICON      = { 0.50, 0.50, 0.54, 1.00 }

local ACTION_STYLE = {
    Banish = {
        color = { 0.95, 0.38, 0.38, 1 },
        label = "Banished",
        tip   = "Auto Pick banished an echo (removed it from this roll).",
    },
    Reroll = {
        color = { 0.27, 0.67, 1.0, 1 },
        label = "Rerolled",
        tip   = "Auto Pick rerolled — new echoes will be offered.",
    },
    Freeze = {
        color = { 0.27, 0.80, 1.0, 1 },
        label = "Frozen",
        tip   = "Auto Pick froze an echo for a later pick.",
    },
    Select = {
        color = { 0.27, 1.0, 0.27, 1 },
        label = "Chose echo",
        tip   = "Auto Pick took the echo with the highest score.",
    },
    ["Select (Repeat)"] = {
        color = { 0.6, 1.0, 0.6, 1 },
        label = "Chose repeat",
        tip   = "All choices were Repeat echoes. Auto Pick selected the highest-scored one.",
    },
    ["Select (Locked)"] = {
        color = { 1.0, 0.82, 0.0, 1 },
        label = "Locked echo",
        tip   = "Auto Pick took one of your locked echoes from the build.",
    },
}

local queue       = {}
local frame
local elapsed     = 0
local hovered     = false
local hoverDepth  = 0
local automationIdleElapsed = 0
local automationShownAt     = 0
local AUTOMATION_IDLE_DISMISS = 2.0
local AUTOMATION_MAX_AGE      = 45.0
local header, headerBar, actionBadge, hintLine, closeBtn, pinBtn
local chargesBar, chargesBarBg, banLabel, rerollLabel, freezeLabel, choicesArea
local choiceSlots = {}
local currentEntry

local function ShowToastTooltip(owner, anchor, setupFn)
    GameTooltip:SetOwner(owner, anchor or "ANCHOR_TOP")
    setupFn()
    GameTooltip:SetFrameStrata("TOOLTIP")
    if frame then
        GameTooltip:SetFrameLevel(frame:GetFrameLevel() + 30)
    end
    GameTooltip:Show()
end

local function GetToastDuration()
    return (EbonholdHubDB.globalSettings and EbonholdHubDB.globalSettings.toastDuration) or 3
end

local function IsToastPinned()
    return EbonholdHubDB.globalSettings and EbonholdHubDB.globalSettings.toastPinned
end

local function GetToastOpacity()
    local gs = EbonholdHubDB.globalSettings
    local v = gs and gs.toastChargesOpacity
    if v == nil then return 0.92 end
    return math.max(0.15, math.min(1, v))
end

local function ApplyToastOpacity()
    if not frame then return end
    frame:SetAlpha(GetToastOpacity())
end

local function GetRunInfo()
    local level = 0
    if ProjectEbonhold and ProjectEbonhold.PerkService then
        local getDebug = ProjectEbonhold.PerkService.GetRollsDebugInfo
        if getDebug then
            local choiceLevel = getDebug()
            if choiceLevel then level = choiceLevel end
        end
    end
    if level == 0 then
        level = UnitLevel("player") or 0
    end

    local rd = EbonholdPlayerRunData
    if not rd and ProjectEbonhold and ProjectEbonhold.PlayerRunService then
        local get = ProjectEbonhold.PlayerRunService.GetCurrentData
        if get then rd = get() end
    end
    local banRemain    = (rd and rd.remainingBanishes) or 0
    local totalRerolls = (rd and rd.totalRerolls) or 0
    local usedRerolls  = (rd and rd.usedRerolls) or 0
    local totalFreezes = (rd and rd.totalFreezes) or 0
    local usedFreezes  = (rd and rd.usedFreezes) or 0
    return level, banRemain, totalRerolls - usedRerolls, totalFreezes - usedFreezes
end

local function UpdateHintLine()
    if not hintLine then return end
    if IsToastPinned() then
        hintLine:SetText("|cff888888Pinned|r")
        hintLine:Show()
    else
        hintLine:SetText("")
        hintLine:Hide()
    end
end

local function UpdateChargesBar()
    if not chargesBar then return end
    local _, banRemain, rerollRemain, freezeRemain = GetRunInfo()
    banLabel:SetText(string.format("|cffff6666Ban|r  %d", banRemain))
    rerollLabel:SetText(string.format("|cff66aaffReroll|r  %d", rerollRemain))
    freezeLabel:SetText(string.format("|cff66ccffFreeze|r  %d", freezeRemain))
    ApplyToastOpacity()
end

local function ActionStyle(action)
    if action == "Select (Locked)" then
        return ACTION_STYLE["Select (Locked)"]
    end
    local key = action and action:match("^(%a+)") or "Select"
    return ACTION_STYLE[key] or ACTION_STYLE.Select
end

local function UpdatePinButton()
    if not pinBtn or not pinBtn.mark then return end
    if IsToastPinned() then
        pinBtn.mark:Show()
        pinBtn.icon:SetVertexColor(unpack(SC.accent))
    else
        pinBtn.mark:Hide()
        pinBtn.icon:SetVertexColor(unpack(SC.textMuted))
    end
end

local function HideChoiceSlots()
    for i = 1, CHOICE_SLOTS do
        choiceSlots[i]:Hide()
    end
end

local function TruncateName(name)
    if not name then return "?" end
    if #name > 16 then
        return name:sub(1, 15) .. "..."
    end
    return name
end

local function PopulateChoices(choices, targetIndex)
    HideChoiceSlots()
    if not choices or not choicesArea then return end

    local count = #choices
    local totalW = count * SLOT_W
    local offsetX = math.max(0, (TOAST_W - totalW) / 2)

    for i = 1, count do
        local ch = choices[i]
        local slot = choiceSlots[i]
        local isTarget = (ch.index == targetIndex)

        slot:ClearAllPoints()
        slot:SetPoint("TOP", choicesArea, "TOP", 0, -1)
        slot:SetPoint("LEFT", choicesArea, "LEFT", offsetX + (i - 1) * SLOT_W, 0)
        slot:Show()

        if ch.spellId then
            slot.iconBtn.icon:SetTexture(select(3, GetSpellInfo(ch.spellId)))
            UI.SetIconButtonQuality(slot.iconBtn, ch.quality)
        end

        slot.nameLabel:SetText(TruncateName(ch.name))
        local scoreText, isLabel = EbonholdHub.Scoring.FormatChoiceScore(ch)
        slot.scoreLabel:SetText(scoreText)

        if isTarget then
            slot.highlight:SetVertexColor(unpack(SC.accentBg18))
            slot.highlight:SetAlpha(SELECT_ALPHA)
            slot.highlight:Show()
            SW.SetBorderColor(slot._border, SC.accentBorder55)
            slot.iconBtn._bg:SetVertexColor(unpack(SC.accentBg12))
            slot.iconBtn.icon:SetVertexColor(1, 1, 1)
            slot.nameLabel:SetTextColor(unpack(SC.text))
            slot.scoreLabel:SetTextColor(unpack(SC.accent))
        else
            slot.highlight:Hide()
            SW.SetBorderColor(slot._border, SC.border)
            slot.iconBtn._bg:SetVertexColor(unpack(SC.elementBg))
            UI.SetIconButtonQuality(slot.iconBtn, ch.quality)
            slot.iconBtn.icon:SetVertexColor(unpack(DIM_ICON))
            slot.nameLabel:SetTextColor(unpack(SC.textDim))
            slot.scoreLabel:SetTextColor(unpack(SC.textMuted))
        end
    end
end

local function ResetAutomationLayout()
    if not frame or not header or not headerBar then return end
    header:ClearAllPoints()
    header:SetPoint("LEFT", headerBar, "LEFT", 8, 0)
    header:SetWordWrap(false)
    header:SetWidth(0)
    headerBar:SetHeight(HEADER_H)
    frame:SetWidth(TOAST_W)
    if actionBadge then
        actionBadge:Show()
    end
    if pinBtn then
        pinBtn:Show()
    end
end

local function LayoutSimpleMessage(text)
    if not frame or not header or not headerBar or not closeBtn then return end
    local screenW = UIParent and UIParent:GetWidth() or 800
    local maxW = math.min(SIMPLE_MAX_W, math.floor(screenW * 0.85))
    local textAreaW = maxW - SIMPLE_PAD_X - 28

    header:ClearAllPoints()
    header:SetPoint("TOPLEFT", headerBar, "TOPLEFT", SIMPLE_PAD_X, -4)
    header:SetPoint("TOPRIGHT", closeBtn, "TOPLEFT", -8, -4)
    header:SetJustifyH("LEFT")
    header:SetJustifyV("TOP")
    header:SetWordWrap(true)
    header:SetWidth(math.max(120, textAreaW))
    header:SetText(text or "")

    local textH = header:GetStringHeight() or HEADER_H
    local barH = math.max(HEADER_H, math.ceil(textH) + 8)
    headerBar:SetHeight(barH)
    frame:SetWidth(maxW)
    frame:SetHeight(barH)
end

local function OnHoverEnter()
    hoverDepth = hoverDepth + 1
    hovered = true
end

local function OnHoverLeave()
    hoverDepth = math.max(0, hoverDepth - 1)
    hovered = hoverDepth > 0
    if hoverDepth == 0 then
        elapsed = 0
    end
end

local function WireHover(frameObj)
    if not frameObj then return end
    frameObj:EnableMouse(true)
    frameObj:SetScript("OnEnter", OnHoverEnter)
    frameObj:SetScript("OnLeave", OnHoverLeave)
end

local function ResetHoverState()
    hoverDepth = 0
    hovered = false
    elapsed = 0
end

local function HasActivePerkChoices()
    if not ProjectEbonhold or not ProjectEbonhold.PerkService then return false end
    local get = ProjectEbonhold.PerkService.GetCurrentChoice
    if not get then return false end
    local choices = get()
    return choices and #choices > 0
end

local function ResetAutomationLifecycle()
    automationIdleElapsed = 0
    automationShownAt = GetTime()
end

local ShowNext

local function DismissCurrent()
    frame:Hide()
    currentEntry = nil
    automationIdleElapsed = 0
    automationShownAt = 0
    ShowNext()
end

local function TickAutomationLifecycle(dt)
    if not currentEntry or not currentEntry.action then return false end

    if automationShownAt > 0 and (GetTime() - automationShownAt) >= AUTOMATION_MAX_AGE then
        DismissCurrent()
        return true
    end

    if not HasActivePerkChoices() then
        automationIdleElapsed = automationIdleElapsed + dt
        if automationIdleElapsed >= AUTOMATION_IDLE_DISMISS then
            DismissCurrent()
            return true
        end
    else
        automationIdleElapsed = 0
    end

    return false
end

local function StartToastTicker()
    if not frame then return end
    frame:SetScript("OnUpdate", function(self, dt)
        if not self:IsShown() then
            self:SetScript("OnUpdate", nil)
            return
        end

        if TickAutomationLifecycle(dt) then
            return
        end

        if IsToastPinned() then return end
        if hovered then
            elapsed = 0
            return
        end
        elapsed = elapsed + dt
        if elapsed >= GetToastDuration() then
            DismissCurrent()
        end
    end)
end

local function ShowAutomation(entry)
    ResetAutomationLayout()
    currentEntry = entry
    local style = ActionStyle(entry.action)
    header:SetText("Auto Pick")
    actionBadge:SetText("— " .. style.label)
    actionBadge:SetTextColor(unpack(style.color))

    PopulateChoices(entry.choices, entry.targetIndex)

    UpdateChargesBar()
    UpdateHintLine()
    if chargesBar then chargesBar:Show() end

    frame:SetHeight(TOAST_H)
    frame:Show()
    ResetHoverState()
    ResetAutomationLifecycle()
    UpdatePinButton()
    StartToastTicker()
end

local function ShowSimple(entry)
    currentEntry = nil
    HideChoiceSlots()
    if actionBadge then
        actionBadge:SetText("")
        actionBadge:Hide()
    end
    if pinBtn then pinBtn:Hide() end
    if chargesBar then chargesBar:Hide() end
    if hintLine then hintLine:Hide() end
    LayoutSimpleMessage(entry.text or "")
    frame:Show()
    ResetHoverState()
    automationIdleElapsed = 0
    automationShownAt = 0
    StartToastTicker()
end

ShowNext = function()
    if #queue == 0 then
        currentEntry = nil
        automationIdleElapsed = 0
        automationShownAt = 0
        frame:Hide()
        return
    end

    local entry = table.remove(queue, 1)
    if entry.action then
        ShowAutomation(entry)
    else
        ShowSimple(entry)
    end
end

local function FlushQueuedAutomation()
    for i = #queue, 1, -1 do
        if queue[i].action then
            table.remove(queue, i)
        end
    end
end

function EbonholdHub.Toast.ShowAutomationResult(scored, action, targetIndex)
    local entry = { action = action, targetIndex = targetIndex, choices = {} }
    for _, s in ipairs(scored) do
        entry.choices[#entry.choices + 1] = {
            index        = s.index,
            spellId      = s.spellId,
            name         = s.name,
            quality      = s.quality,
            score        = s.selectScore or s.score,
            selectScore  = s.selectScore,
            tier         = s.tier,
            baseTier     = s.baseTier,
            isTierF      = s.isTierF,
            isZeroWeight = s.isZeroWeight,
            isRepeat     = s.isRepeat,
            isDuplicate  = s.isDuplicate,
            isBanned     = s.isBanned,
        }
    end

    -- Live-update when an automation toast is already on screen (rapid reroll/banish chains).
    if frame and frame:IsShown() and currentEntry and currentEntry.action then
        FlushQueuedAutomation()
        ShowAutomation(entry)
        return
    end

    table.insert(queue, entry)
    if not frame:IsShown() then ShowNext() end
end

function EbonholdHub.Toast.Show(message)
    table.insert(queue, { text = message })
    if not frame:IsShown() then ShowNext() end
end

local function CreateChoiceSlot(parent, index)
    local slot = CreateFrame("Frame", nil, parent)
    slot:SetSize(SLOT_W, SLOT_H)

    -- Selection highlight bg (accent tint when chosen)
    local highlight = slot:CreateTexture(nil, "BACKGROUND")
    highlight:SetTexture(FLAT)
    highlight:SetPoint("TOPLEFT",     slot, "TOPLEFT",     0, 1)
    highlight:SetPoint("BOTTOMRIGHT", slot, "BOTTOMRIGHT", 0, -1)
    highlight:Hide()
    slot.highlight = highlight

    -- Subtle slot border
    slot._border = SW.ThinBorder(slot, SC.border, 1)

    local iconBtn = UI.CreateIconButton(slot, ICON_SIZE)
    iconBtn:SetFrameLevel(slot:GetFrameLevel() + 3)
    iconBtn:SetPoint("TOP", slot, "TOP", 0, -3)
    slot.iconBtn = iconBtn

    local nameLabel = slot:CreateFontString(nil, "OVERLAY")
    SW.SetFont(nameLabel, 10)
    nameLabel:SetTextColor(unpack(SC.text))
    nameLabel:SetPoint("TOP", iconBtn, "BOTTOM", 0, -2)
    nameLabel:SetWidth(SLOT_W - 4)
    nameLabel:SetJustifyH("CENTER")
    slot.nameLabel = nameLabel

    local scoreLabel = slot:CreateFontString(nil, "OVERLAY")
    SW.SetFont(scoreLabel, 10)
    scoreLabel:SetTextColor(unpack(SC.textMuted))
    scoreLabel:SetPoint("TOP", nameLabel, "BOTTOM", 0, -1)
    scoreLabel:SetWidth(SLOT_W - 4)
    scoreLabel:SetJustifyH("CENTER")
    slot.scoreLabel = scoreLabel

    WireHover(slot)
    WireHover(slot.iconBtn)

    slot:Hide()
    return slot
end

local function BuildFrame()
    local f = CreateFrame("Frame", "EbonholdHubToastFrame", UIParent)
    f:SetSize(TOAST_W, TOAST_H)
    f:SetPoint("TOP", UIParent, "TOP", 0, -40)
    f:SetFrameStrata("TOOLTIP")
    f:SetMovable(true)
    f:EnableMouse(true)
    f:SetClampedToScreen(true)
    f:Hide()

    SW.Fill(f, SC.bg)
    SW.ThinBorder(f, SC.border, 1)

    -- Left accent strip (tier color, updated per action)
    local accent = f:CreateTexture(nil, "ARTWORK")
    accent:SetTexture(FLAT)
    accent:SetVertexColor(unpack(SC.accent))
    accent:SetPoint("TOPLEFT",    f, "TOPLEFT",    0, 0)
    accent:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 0, 0)
    accent:SetWidth(3)

    -- Top accent strip
    local topAccent = f:CreateTexture(nil, "ARTWORK")
    topAccent:SetTexture(FLAT)
    topAccent:SetVertexColor(unpack(SC.accent))
    topAccent:SetPoint("TOPLEFT",  f, "TOPLEFT",  0, 0)
    topAccent:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, 0)
    topAccent:SetHeight(2)

    -- Header bar
    headerBar = CreateFrame("Frame", nil, f)
    headerBar:SetPoint("TOPLEFT",  accent, "TOPRIGHT", 0, 0)
    headerBar:SetPoint("TOPRIGHT", f,      "TOPRIGHT", 0, 0)
    headerBar:SetHeight(HEADER_H)
    headerBar:SetFrameLevel(f:GetFrameLevel() + 4)
    SW.Fill(headerBar, SC.sidebarBg)

    -- Separator below header
    local headerSep = f:CreateTexture(nil, "ARTWORK")
    headerSep:SetTexture(FLAT)
    headerSep:SetVertexColor(unpack(SC.border))
    headerSep:SetHeight(1)
    headerSep:SetPoint("TOPLEFT",  headerBar, "BOTTOMLEFT",  0, 0)
    headerSep:SetPoint("TOPRIGHT", headerBar, "BOTTOMRIGHT", 0, 0)

    headerBar:EnableMouse(true)
    headerBar:SetScript("OnMouseDown", function() f:StartMoving() end)
    headerBar:SetScript("OnMouseUp",   function() f:StopMovingOrSizing() end)

    -- "Auto Pick" title
    header = headerBar:CreateFontString(nil, "OVERLAY")
    SW.SetFont(header, 12, "semibold")
    header:SetTextColor(unpack(SC.text))
    header:SetPoint("LEFT", headerBar, "LEFT", 8, 0)

    -- Action badge ("— Chose echo" etc.)
    actionBadge = headerBar:CreateFontString(nil, "OVERLAY")
    SW.SetFont(actionBadge, 11)
    actionBadge:SetPoint("LEFT",  header,    "RIGHT",  5, 0)
    actionBadge:SetPoint("RIGHT", headerBar, "RIGHT", -72, 0)
    actionBadge:SetJustifyH("LEFT")

    -- Pin button
    pinBtn = CreateFrame("Button", nil, headerBar)
    pinBtn:SetSize(18, 18)
    pinBtn:SetPoint("RIGHT", headerBar, "RIGHT", -24, 0)
    pinBtn.icon = pinBtn:CreateTexture(nil, "ARTWORK")
    pinBtn.icon:SetTexture("Interface\\Buttons\\UI-GuildButton-PublicNote-Up")
    pinBtn.icon:SetPoint("CENTER")
    pinBtn.icon:SetSize(12, 12)
    pinBtn.mark = pinBtn:CreateTexture(nil, "OVERLAY")
    pinBtn.mark:SetTexture(FLAT)
    pinBtn.mark:SetVertexColor(unpack(SC.accent))
    pinBtn.mark:SetSize(5, 5)
    pinBtn.mark:SetPoint("BOTTOMRIGHT", -1, 1)
    pinBtn.mark:Hide()
    pinBtn:SetScript("OnEnter", function()
        ShowToastTooltip(pinBtn, "ANCHOR_TOP", function()
            GameTooltip:SetText(
                IsToastPinned()
                    and "Pinned — timer paused while echoes are offered"
                    or "Pin toast — pause auto-hide during echo pick",
                1, 1, 1)
        end)
    end)
    pinBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)
    pinBtn:SetScript("OnClick", function()
        EbonholdHubDB.globalSettings = EbonholdHubDB.globalSettings or {}
        EbonholdHubDB.globalSettings.toastPinned = not IsToastPinned()
        UpdatePinButton()
        if currentEntry and currentEntry.action then
            UpdateHintLine()
        end
    end)

    -- "Pinned" hint
    hintLine = headerBar:CreateFontString(nil, "OVERLAY")
    SW.SetFont(hintLine, 10)
    hintLine:SetTextColor(unpack(SC.textMuted))
    hintLine:SetPoint("RIGHT", pinBtn, "LEFT", -5, 0)
    hintLine:SetJustifyH("RIGHT")
    hintLine:Hide()

    -- Close button
    closeBtn = CreateFrame("Button", nil, headerBar)
    closeBtn:SetSize(18, 18)
    closeBtn:SetPoint("RIGHT", headerBar, "RIGHT", -4, 0)
    local closeText = closeBtn:CreateFontString(nil, "OVERLAY")
    SW.SetFont(closeText, 13)
    closeText:SetTextColor(unpack(SC.textMuted))
    closeText:SetPoint("CENTER")
    closeText:SetText("×")
    closeBtn:SetScript("OnEnter", function()
        closeText:SetTextColor(0.95, 0.40, 0.40)
    end)
    closeBtn:SetScript("OnLeave", function()
        closeText:SetTextColor(unpack(SC.textMuted))
    end)
    closeBtn:SetScript("OnClick", DismissCurrent)

    -- Charges bar (bottom)
    chargesBar = CreateFrame("Frame", nil, f)
    chargesBar:SetPoint("BOTTOMLEFT",  f, "BOTTOMLEFT",  0, 0)
    chargesBar:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0)
    chargesBar:SetHeight(CHARGES_BAR_H)
    chargesBarBg = SW.Fill(chargesBar, SC.bgElevated)
    SW.ThinBorder(chargesBar, SC.border, 1)

    local chargesSep = chargesBar:CreateTexture(nil, "ARTWORK")
    chargesSep:SetTexture(FLAT)
    chargesSep:SetVertexColor(unpack(SC.border))
    chargesSep:SetPoint("TOPLEFT",  chargesBar, "TOPLEFT",  0, 0)
    chargesSep:SetPoint("TOPRIGHT", chargesBar, "TOPRIGHT", 0, 0)
    chargesSep:SetHeight(1)

    banLabel = chargesBar:CreateFontString(nil, "OVERLAY")
    SW.SetFont(banLabel, 10)
    banLabel:SetTextColor(unpack(SC.text))
    banLabel:SetPoint("LEFT", chargesBar, "LEFT", 14, 0)

    rerollLabel = chargesBar:CreateFontString(nil, "OVERLAY")
    SW.SetFont(rerollLabel, 10)
    rerollLabel:SetTextColor(unpack(SC.text))
    rerollLabel:SetPoint("CENTER", chargesBar, "CENTER", 0, 0)

    freezeLabel = chargesBar:CreateFontString(nil, "OVERLAY")
    SW.SetFont(freezeLabel, 10)
    freezeLabel:SetTextColor(unpack(SC.text))
    freezeLabel:SetPoint("RIGHT", chargesBar, "RIGHT", -14, 0)

    -- Choices area
    choicesArea = CreateFrame("Frame", nil, f)
    choicesArea:SetPoint("TOPLEFT",  headerBar, "BOTTOMLEFT",  0, -1)
    choicesArea:SetPoint("TOPRIGHT", headerBar, "BOTTOMRIGHT", 0, -1)
    choicesArea:SetPoint("BOTTOM",   chargesBar, "TOP",         0,  0)
    choicesArea:SetHeight(CHOICES_H)
    choicesArea:SetFrameLevel(f:GetFrameLevel() + 2)

    for i = 1, CHOICE_SLOTS do
        choiceSlots[i] = CreateChoiceSlot(choicesArea, i)
    end

    WireHover(f)
    WireHover(headerBar)
    WireHover(choicesArea)
    WireHover(chargesBar)
    WireHover(closeBtn)
    WireHover(pinBtn)

    ApplyToastOpacity()

    return f
end

function EbonholdHub.Toast.Init()
    frame = BuildFrame()
end

function EbonholdHub.Toast.IsPinned()
    return IsToastPinned()
end

function EbonholdHub.Toast.SetPinned(value)
    EbonholdHubDB.globalSettings = EbonholdHubDB.globalSettings or {}
    EbonholdHubDB.globalSettings.toastPinned = value and true or false
    UpdatePinButton()
    UpdateHintLine()
end

function EbonholdHub.Toast.RefreshStyle()
    ApplyToastOpacity()
    if frame and frame:IsShown() and currentEntry and currentEntry.action then
        UpdateChargesBar()
        UpdateHintLine()
    end
end

function EbonholdHub.Toast.NotifyPerkChoiceEnded()
    automationIdleElapsed = AUTOMATION_IDLE_DISMISS
end

function EbonholdHub.Toast.DismissAutomation()
    FlushQueuedAutomation()
    if frame and frame:IsShown() and currentEntry and currentEntry.action then
        DismissCurrent()
    end
end
