-- =============================================================================
-- WoWTranslate_UK :: entry-point glue
-- =============================================================================
-- Responsibilities:
--   * install SetText + font hooks IMMEDIATELY at addon load (no PLAYER_LOGIN
--     wait), so login-screen and character-select UI translate right away;
--   * on PLAYER_LOGIN: sweep visible frames; schedule lazy-load of the bulk
--     DB (Items/Spells/Quests/NPC) via LoadAddOn("WoWTranslate_UK_Bulk");
--   * install slash commands for debugging.
--
-- Core DB (Glossary, Zones, Achievements, FragmentLookup, StaticOverrides)
-- is loaded synchronously with this addon (~30 MB RAM). Bulk DB is loaded on
-- demand: either 3s after login, or eagerly when a tooltip / quest log is
-- opened for the first time.
-- =============================================================================

local addonName, addonNs = ...
local ns = _G.WoWTranslate_UK_NS or addonNs or {}
_G.WoWTranslate_UK_NS = ns
_G.WoWTranslate_UK = ns

local initialized = false

local function chat_error(prefix, err)
    local msg = "|cffff3333WoWTranslate_UK " .. prefix .. " error:|r " .. tostring(err)
    if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
        DEFAULT_CHAT_FRAME:AddMessage(msg)
    else
        print(msg)
    end
end

local function safe_call(prefix, fn)
    if type(fn) ~= "function" then return true end
    local ok, err = pcall(fn)
    if not ok then chat_error(prefix, err) end
    return ok
end

-- =============================================================================
-- TranslateVisibleUI: initial sweep of currently-open major frames.
-- Called 0.5s after PLAYER_LOGIN so Blizzard has had time to show login UI.
-- =============================================================================
function ns.TranslateVisibleUI()
    if not ns.DB or not ns.DB.Lookup then return end
    local frames = {
        CharacterFrame, PlayerSpellsFrame, CollectionsJournal,
        MerchantFrame, AuctionHouseFrame, WorldMapFrame,
        GameMenuFrame, MailFrame, FriendsFrame, GuildFrame,
        LFGParentFrame, PVEFrame,
    }
    for i = 1, #frames do
        local f = frames[i]
        if f and not (ns.isProtectedFrame and ns.isProtectedFrame(f)) then
            if ns.TranslateFrame then ns.TranslateFrame(f) end
        end
    end
end

-- =============================================================================
-- Bulk loader: WoWTranslate_UK_Bulk is a LoadOnDemand sibling addon that
-- contains Items/Spells/Quests/NPC chunks (~670 k entries, ~170 MB). We pull
-- it in on a short idle delay after login OR eagerly on first tooltip/quest-
-- log interaction, whichever comes first.
-- =============================================================================
local BULK_ADDON = "WoWTranslate_UK_Bulk"
local bulk_loaded = false
local bulk_loading = false

local function _isAddOnLoaded(name)
    if C_AddOns and C_AddOns.IsAddOnLoaded then return C_AddOns.IsAddOnLoaded(name) end
    if IsAddOnLoaded then return IsAddOnLoaded(name) end
    return false
end

local function _loadAddOn(name)
    if C_AddOns and C_AddOns.LoadAddOn then return C_AddOns.LoadAddOn(name) end
    if LoadAddOn then return LoadAddOn(name) end
    return nil
end

local function load_bulk(reason)
    if bulk_loaded or bulk_loading then return end
    if _isAddOnLoaded(BULK_ADDON) then bulk_loaded = true; return end
    bulk_loading = true
    local t0 = debugprofilestop and debugprofilestop() or 0
    local ok, err = pcall(_loadAddOn, BULK_ADDON)
    bulk_loading = false
    if not ok then
        chat_error("bulk", err)
        return
    end
    if not _isAddOnLoaded(BULK_ADDON) then return end
    bulk_loaded = true
    local dt = debugprofilestop and (debugprofilestop() - t0) or 0
    if ns.ClearTranslationCache then ns.ClearTranslationCache() end
    if ns.ClearTooltipCache then ns.ClearTooltipCache() end
    if ns.TranslateVisibleUI then ns.TranslateVisibleUI() end
    -- Force objective tracker + quest-related frames to re-render so the
    -- "0/1 X" strings cached with negative-miss before bulk loaded get
    -- retranslated now that the item/spell/npc names are in Lookup.
    if ObjectiveTrackerFrame and ObjectiveTrackerFrame.Update then
        pcall(ObjectiveTrackerFrame.Update, ObjectiveTrackerFrame)
    end
    if ObjectiveTracker_Update then pcall(ObjectiveTracker_Update) end
    if QuestMapFrame_UpdateAll then pcall(QuestMapFrame_UpdateAll) end
    if ns.TranslateFrame and ObjectiveTrackerFrame then
        pcall(ns.TranslateFrame, ObjectiveTrackerFrame)
    end
    print(string.format("|cFF00ccffWT|r bulk DB loaded (%s, %.0f ms)", reason or "timer", dt))
end
ns.LoadBulk = load_bulk

-- =============================================================================
-- Main init
-- =============================================================================
local function initialize()
    if initialized then return end
    initialized = true

    if ns.ClearTooltipCache then ns.ClearTooltipCache() end

    safe_call("font", ns.ApplyFonts)
    safe_call("hook", ns.InstallSetTextHook)

    if ns.TranslationsManager then
        safe_call("init", function() ns.TranslationsManager:Init() end)
    else
        chat_error("init", "missing TranslationsManager")
    end
end

-- Install hooks + fonts IMMEDIATELY at addon load. DB was populated by the
-- preceding Database/* scripts in the root XML manifest, so translation
-- lookups work right away - no need to wait for PLAYER_LOGIN.
initialize()

-- =============================================================================
-- Event loop: post-login work (UI sweep + bulk-DB lazy load triggers)
-- =============================================================================
local function install_onshow_rescans()
    -- Frames whose buttons/labels are lazy-constructed on OnShow (GameMenu
    -- lazy-loads Settings/Shop/AddOns on demand). Re-sweep each time they
    -- appear so newly-created children translate.
    local onShowTargets = {
        "GameMenuFrame", "MailFrame", "MerchantFrame",
        "CollectionsJournal", "PVEFrame", "WorldMapFrame",
        "CharacterFrame", "PlayerSpellsFrame", "FriendsFrame",
        "ProfessionsFrame", "ProfessionsBookFrame", "AchievementFrame",
        "QuestLogFrame", "QuestFrame", "QuestMapFrame",
    }
    for i = 1, #onShowTargets do
        local name = onShowTargets[i]
        local f = _G[name]
        if f and f.HookScript then
            pcall(f.HookScript, f, "OnShow", function()
                if ns.TranslateFrame then
                    C_Timer.After(0.05, function() ns.TranslateFrame(f) end)
                end
            end)
        end
    end
end

local function install_bulk_triggers()
    -- Eager triggers: load bulk DB the moment the user does something that
    -- plausibly needs item/spell/quest/npc translations.
    if GameTooltip and GameTooltip.HookScript then
        pcall(GameTooltip.HookScript, GameTooltip, "OnShow", function()
            if not bulk_loaded then load_bulk("tooltip") end
        end)
    end
    for _, fname in ipairs({"QuestLogFrame", "QuestFrame", "QuestMapFrame",
                             "EncounterJournal", "SpellBookFrame",
                             "PlayerSpellsFrame"}) do
        local f = _G[fname]
        if f and f.HookScript then
            pcall(f.HookScript, f, "OnShow", function()
                if not bulk_loaded then load_bulk(fname) end
            end)
        end
    end
end

local ef = CreateFrame("Frame")
ef:RegisterEvent("PLAYER_LOGIN")
ef:SetScript("OnEvent", function(_, event)
    if event ~= "PLAYER_LOGIN" then return end
    local ok = ns.DB and ns.DB.Lookup
    print("|cFF00ccffWoWTranslate_UK|r loaded. DB: " .. (ok and "ok" or "MISSING"))

    install_onshow_rescans()
    install_bulk_triggers()

    C_Timer.After(0.5, ns.TranslateVisibleUI)
    -- Idle load of the bulk DB ~3s after login. Gives the game time to
    -- finish its first-frame spawn storm before we drop 170 MB of table
    -- slots + strings.
    C_Timer.After(3.0, function() load_bulk("idle") end)
end)

-- =============================================================================
-- Slash commands
-- =============================================================================
SLASH_WTDEBUG1 = "/wtdebug"
SlashCmdList["WTDEBUG"] = function()
    local types_of = function(fn) return tostring(type(fn)) end
    print("|cFF00ccffWoWTranslate_UK|r funcs:"
        .. " GetTranslation=" .. types_of(ns.GetTranslation)
        .. " TranslateTextObject=" .. types_of(ns.TranslateTextObject)
        .. " TranslateFrame=" .. types_of(ns.TranslateFrame)
        .. " Hook=" .. tostring(ns._setTextHookInstalled))
    print("  DBLoaded=" .. tostring(ns.DBLoaded))
    local count = function(t)
        local n = 0; if t then for _ in pairs(t) do n = n + 1 end end; return n
    end
    local lu = count(ns.DB and ns.DB.Lookup)
    local lo = count(ns.DB and ns.DB.LowerLookup)
    local infl = count(ns.INFLECTIONS)
    print(string.format("  Lookup=%d  LowerLookup=%d  Inflections=%d",
        lu, lo, infl))

    print("  Bulk: " .. tostring(bulk_loaded) .. "  (" .. tostring(_isAddOnLoaded(BULK_ADDON)) .. ")")
    local tests = {
        "Season 10", "Heroic", "Wildercloth", "Dungeons",
        "Delete Character", "Create New Character", "Accept", "Decline",
    }
    for i = 1, #tests do
        local t = tests[i]
        local tr = ns.GetTranslation and ns.GetTranslation(t)
        print("  " .. t .. " => " .. tostring(tr))
    end
end

SLASH_WTCOLLECT1 = "/wtcollect"
SlashCmdList["WTCOLLECT"] = function(cmd)
    local sv = WoWTranslate_UK_Untranslated
    if not sv or type(sv) ~= "table" then
        print("|cFF00ccffWoWTranslate_UK|r No collected strings yet. Play the game first!")
        return
    end
    local sorted = {}
    for key, val in pairs(sv) do
        local count, orig
        if type(val) == "table" then count, orig = val[1] or 0, val[2] or key
        elseif type(val) == "number" then count, orig = val, key end
        if type(key) == "string" and (count or 0) >= 2 then
            sorted[#sorted + 1] = { text = key, orig = orig, count = count }
        end
    end
    table.sort(sorted, function(a, b) return a.count > b.count end)
    local n = tonumber(cmd) or 30
    print("|cFF00ccffWoWTranslate_UK|r Top " .. math.min(n, #sorted) .. " untranslated (>=2x):")
    for i = 1, math.min(n, #sorted) do
        local s = sorted[i]
        local display = (s.orig or s.text):sub(1, 100)
        if s.orig ~= s.text then display = display .. " [can:" .. s.text:sub(1, 40) .. "]" end
        print("  " .. s.count .. "x | " .. display)
    end
    print("|cFF00ccffWoWTranslate_UK|r Total unique: " .. #sorted .. " (use /wtcollect 100 for more)")
    if cmd and cmd:match("clear") then
        wipe(sv)
        print("|cFF00ccffWoWTranslate_UK|r Collector cleared.")
    end
end

SLASH_WTPROBE1 = "/wtprobe"
SlashCmdList["WTPROBE"] = function()
    local targets = {
        { "QuestMapFrame.DetailsFrame.AbandonButton",
            QuestMapFrame and QuestMapFrame.DetailsFrame and QuestMapFrame.DetailsFrame.AbandonButton },
        { "QuestMapFrame.DetailsFrame.ShareButton",
            QuestMapFrame and QuestMapFrame.DetailsFrame and QuestMapFrame.DetailsFrame.ShareButton },
        { "QuestInfoRewardsFrame.Header",
            _G.QuestInfoRewardsFrame and _G.QuestInfoRewardsFrame.Header },
        { "WorldMapFrame.TitleContainer.TitleText",
            _G.WorldMapFrame and _G.WorldMapFrame.TitleContainer and _G.WorldMapFrame.TitleContainer.TitleText },
    }
    for i = 1, #targets do
        local label, frame = targets[i][1], targets[i][2]
        if not frame then
            print(string.format("  MISSING  %s", label))
        else
            local text
            if frame.GetText then
                local ok, t = pcall(frame.GetText, frame); if ok then text = t end
            end
            if not text and frame.Text and frame.Text.GetText then
                local ok, t = pcall(frame.Text.GetText, frame.Text); if ok then text = t end
            end
            if text == nil or text == "" then
                print(string.format("  EMPTY    %s", label))
            else
                local tr = ns.GetTranslation and ns.GetTranslation(text)
                print(string.format("  %s  raw=%q  tr=%s", label, text, tostring(tr)))
            end
        end
    end
end

SLASH_WTCACHE1 = "/wtcache"
SlashCmdList["WTCACHE"] = function(cmd)
    if cmd == "clear" and ns.ClearTranslationCache then
        ns.ClearTranslationCache()
        if ns.ClearTooltipCache then ns.ClearTooltipCache() end
        print("|cFF00ccffWoWTranslate_UK|r cache cleared.")
    else
        print("|cFF00ccffWoWTranslate_UK|r /wtcache clear - drop translation + tooltip caches")
    end
end
