--[[
============================================================================
Enhanced Pet Tracker  -  Core/Init.lua
============================================================================
Namespace bootstrap, C_Timer polyfill, debug/print helpers, and the
deferred-init driver.

Namespace pattern mirrors ETB: every file does `local ADDON_NAME, NS = ...`
and reaches the addon table via NS.EPT. Nothing is written to _G except the
two slash-command globals (required by the WoW API) — writing arbitrary
keys to _G taints the global environment.
============================================================================
]]--

local ADDON_NAME, NS = ...

NS.EPT = NS.EPT or {}
local EPT = NS.EPT
local ETB = NS.ETB

EPT.version = "0.4.0"
EPT.debug   = false   -- set true during development for verbose chat

-- ============================================================================
-- C_TIMER FALLBACK  (C_Timer arrived after MoP; 5.4.8 Classic may lack it)
-- ============================================================================

if not C_Timer then
    C_Timer = {}
    function C_Timer.After(delay, callback)
        local f = CreateFrame("Frame")
        f.elapsed = 0
        f:SetScript("OnUpdate", function(self, e)
            self.elapsed = self.elapsed + e
            if self.elapsed >= delay then
                self:SetScript("OnUpdate", nil)
                callback()
            end
        end)
    end
    function C_Timer.NewTicker(interval, callback, iterations)
        local t = { _cancelled = false }
        local f = CreateFrame("Frame")
        f.elapsed, f.count = 0, 0
        f:SetScript("OnUpdate", function(self, e)
            if t._cancelled then self:SetScript("OnUpdate", nil) return end
            self.elapsed = self.elapsed + e
            if self.elapsed >= interval then
                self.elapsed = 0
                self.count = self.count + 1
                callback(t)
                if iterations and self.count >= iterations then
                    t._cancelled = true
                    self:SetScript("OnUpdate", nil)
                end
            end
        end)
        function t:Cancel() t._cancelled = true end
        return t
    end
end

-- ============================================================================
-- OUTPUT HELPERS
-- ============================================================================

local PREFIX = "|cff33ddffEPT|r "

function EPT:Print(msg)
    DEFAULT_CHAT_FRAME:AddMessage(PREFIX .. tostring(msg))
end

function EPT:Printf(fmt, ...)
    DEFAULT_CHAT_FRAME:AddMessage(PREFIX .. string.format(fmt, ...))
end

function EPT:Debug(tag, msg)
    if not self.debug then return end
    DEFAULT_CHAT_FRAME:AddMessage(PREFIX .. "|cff888888[" .. tostring(tag) .. "]|r " .. tostring(msg))
end

function EPT:Error(msg)
    DEFAULT_CHAT_FRAME:AddMessage(PREFIX .. "|cffff4444Error:|r " .. tostring(msg))
end

-- Thousands-separator number formatting (used by the minimap tooltip etc.)
function EPT:FormatNumber(n)
    n = tonumber(n) or 0
    local s = tostring(math.floor(n))
    local out = s:reverse():gsub("(%d%d%d)", "%1,"):reverse()
    return (out:gsub("^,", ""))
end

-- ============================================================================
-- TINY EVENT BUS  (custom in-addon signals: "EPT_COLLECTION_CHANGED" etc.)
-- ============================================================================
-- A pared-down version of ETB's EventBus — just enough for the browser and
-- minimap button to react when the pet collection changes.

local listeners = {}   -- signal -> { fn, fn, ... }

function EPT:On(signal, fn)
    listeners[signal] = listeners[signal] or {}
    table.insert(listeners[signal], fn)
end

function EPT:Emit(signal, ...)
    local list = listeners[signal]
    if not list then return end
    for _, fn in ipairs(list) do
        local ok, err = pcall(fn, ...)
        if not ok then EPT:Debug("EventBus", "listener error: " .. tostring(err)) end
    end
end

-- ============================================================================
-- DEFERRED INIT
-- ============================================================================
-- Each subsystem registers an init function via EPT:RegisterInit. They run
-- shortly after PLAYER_ENTERING_WORLD so the companion API is populated and
-- we never block the loading screen.

local initFns = {}
function EPT:RegisterInit(fn) table.insert(initFns, fn) end

local bootFrame = CreateFrame("Frame")
bootFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
bootFrame:SetScript("OnEvent", function(self, event)
    self:UnregisterEvent("PLAYER_ENTERING_WORLD")
    local function runInit()
        for _, fn in ipairs(initFns) do
            local ok, err = pcall(fn)
            if not ok then EPT:Error("init failed: " .. tostring(err)) end
        end
        EPT.initialized = true
        EPT:Debug("Init", "Enhanced Pet Tracker v" .. EPT.version .. " ready.")
    end
    if ETB and ETB.RunWhenStartupIdle then
        ETB:RunWhenStartupIdle("ept.init", runInit, { delay = 2, interval = 2, maxWait = 180 })
    else
        C_Timer.After(0, runInit)
    end
end)

-- Binding header (keybinding UI grouping)
BINDING_HEADER_EPTBINDING = "Enhanced Pet Tracker"
