-- TOG Tools — Shared UI helpers
--
-- Loaded BEFORE MainWindow.lua in every TOC. All helpers here are addon-
-- global so any tab (existing or future) can use them without duplicating
-- the boilerplate.
--
-- Globals exposed:
--   addon.Tooltip.Owner(frame, [budget])      auto-flipping tooltip anchor
--   addon.UI.Brand(text)                      wrap in brand colour
--   addon.UI.AttachTooltip(frame, t, body)    HookScript-based tooltip
--   addon.UI.MakeIcon(parent, opts)           bottom-row icon button factory
--   addon.UI.DetachChildren(host, keys)       release helper for OnClose

local _, addon = ...

-- ---------------------------------------------------------------------------
-- Tooltip — auto-flipping anchor
-- ---------------------------------------------------------------------------
-- Picks ANCHOR_TOPRIGHT when there's room below the frame for `budget` px
-- of tooltip; otherwise ANCHOR_BOTTOMLEFT. Avoids tooltips that hang off
-- the bottom of the screen for frames near the bottom edge.
addon.Tooltip = addon.Tooltip or {}
function addon.Tooltip.Owner(frame, budget)
    local top = frame and frame.GetTop and frame:GetTop()
    local screenH = GetScreenHeight() or 0
    budget = budget or 250
    local anchor = (top and (screenH - top) > budget)
        and "ANCHOR_TOPRIGHT"
        or  "ANCHOR_BOTTOMLEFT"
    GameTooltip:SetOwner(frame, anchor)
end

-- ---------------------------------------------------------------------------
-- UI helpers
-- ---------------------------------------------------------------------------
addon.UI = addon.UI or {}
local UI = addon.UI

--- Wrap `text` in the addon brand colour. Safe to embed in fontstrings,
--- tooltips, and chat output.
function UI.Brand(text)
    local c = addon.BrandColor or "ffFF8000"
    return "|c" .. c .. tostring(text or "") .. "|r"
end

--- Attach a GameTooltip OnEnter/OnLeave to `frame`. HookScript-based so
--- it chains alongside any existing handlers rather than replacing them.
function UI.AttachTooltip(frame, title, body)
    if not frame then return end
    frame:HookScript("OnEnter", function(self_)
        addon.Tooltip.Owner(self_)
        if title and title ~= "" then GameTooltip:SetText(title, 1, 1, 1) end
        if body  and body  ~= "" then GameTooltip:AddLine(body, nil, nil, nil, true) end
        GameTooltip:Show()
    end)
    frame:HookScript("OnLeave", function() GameTooltip:Hide() end)
end

--- Build a bottom-row icon button (gear, help-i, future icons).
---
--- opts:
---   size           number  button size (default 20)
---   texture        string  normal/pushed texture path (required)
---   texCoordCrop   bool    apply 0.08-0.92 crop. Interface\Icons\* have
---                          ~8% transparent border padding so the visible
---                          icon doesn't fill the button; crop fixes that.
---                          Default false (Interface\Common\* etc. don't
---                          need it).
---   hitRectInsets  number  hit-rect expansion in px (negative widens);
---                          default -2 — gives 2 px slop on every side
---                          inside the row's standard 3 px gap.
---   onClick        func    optional click handler.
---   onEnter        func    optional OnEnter; overrides tooltipTitle/Body.
---   onLeave        func    optional OnLeave; defaults to GameTooltip:Hide.
---   tooltipTitle   string  if set (and no onEnter), installs an auto
---   tooltipBody    string  tooltip via addon.Tooltip.Owner.
---
--- Returns the Button frame. Caller is responsible for SetPoint and for
--- storing the frame somewhere DetachChildren can find it on close.
function UI.MakeIcon(parent, opts)
    opts = opts or {}
    local size = opts.size or 20
    local btn = CreateFrame("Button", nil, parent)
    btn:SetSize(size, size)
    btn:EnableMouse(true)
    if opts.texture then
        btn:SetNormalTexture(opts.texture)
        btn:SetPushedTexture(opts.texture)
    end
    if opts.texCoordCrop then
        local n = btn:GetNormalTexture()
        if n then n:SetTexCoord(0.08, 0.92, 0.08, 0.92) end
        local p = btn:GetPushedTexture()
        if p then
            p:SetTexCoord(0.08, 0.92, 0.08, 0.92)
            p:SetVertexColor(0.7, 0.7, 0.7)
        end
    end
    btn:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square", "ADD")
    local slop = opts.hitRectInsets or -2
    btn:SetHitRectInsets(slop, slop, slop, slop)

    if opts.onEnter then
        btn:SetScript("OnEnter", opts.onEnter)
        btn:SetScript("OnLeave", opts.onLeave or function() GameTooltip:Hide() end)
    elseif opts.tooltipTitle or opts.tooltipBody then
        btn:SetScript("OnEnter", function(self_)
            addon.Tooltip.Owner(self_)
            if opts.tooltipTitle then
                GameTooltip:SetText(opts.tooltipTitle, 1, 1, 1)
            end
            if opts.tooltipBody then
                GameTooltip:AddLine(opts.tooltipBody, nil, nil, nil, true)
            end
            GameTooltip:Show()
        end)
        btn:SetScript("OnLeave", function() GameTooltip:Hide() end)
    end

    if opts.onClick then btn:SetScript("OnClick", opts.onClick) end

    return btn
end

--- Detach child frames that were manually attached to a pooled AceGUI
--- widget's underlying WoW frame. Without this, the next AceGUI:Create
--- of the same widget type returns the same pooled instance with our
--- frames still parented — they stack on top of each other across
--- Open/Close cycles, and can leak into other addons' UIs since the
--- AceGUI pool is global.
---
--- `host` is the table holding the references (typically MainWindow self
--- or a tab module's self). `keys` is a list of self-keys to detach.
--- Hides each frame, reparents to UIParent, clears its points, and nils
--- the reference so a fresh icon can take its place on next Open.
function UI.DetachChildren(host, keys)
    if not (host and keys) then return end
    for _, k in ipairs(keys) do
        local frame = host[k]
        if frame then
            if frame.Hide          then frame:Hide()          end
            if frame.SetParent     then frame:SetParent(UIParent) end
            if frame.ClearAllPoints then frame:ClearAllPoints() end
            host[k] = nil
        end
    end
end
