-- ============================================================
-- RNTools_Core.lua  — Ace3 Backbone for RealNibba's Raid Tools
-- Phase 1: AceAddon + AceDB lifecycle wrapper
--
-- ZERO changes to any other file. This file WRAPS the existing
-- OnPlayerLogin logic and provides:
--   • AceAddon lifecycle (OnInitialize / OnEnable)
--   • AceDB with profile support
--   • AceConsole slash commands (/rnt, /rntools)
--   • Per-module SavedVariable aliases kept for full back-compat
-- ============================================================

-- Create the addon with Ace3 mixins
local RNToolsAddon = LibStub("AceAddon-3.0"):NewAddon(
    "RealNibba's Raid Tools",
    "AceConsole-3.0",   -- embeddable: slash commands
    "AceEvent-3.0",     -- embeddable: RegisterEvent/UnregisterEvent
    "AceHook-3.0"       -- embeddable: Hook/SecureHook
    -- AceDB-3.0 is NOT embeddable — called via LibStub("AceDB-3.0"):New() in OnInitialize
)
_G.RNToolsAddon = RNToolsAddon  -- expose globally for inter-module access

-- ── AceDB Defaults ───────────────────────────────────────────────────────────
-- We keep ALL existing globals (BiSRaidDB etc.) as the primary storage.
-- AceDB manages the NEW unified profile plus overlay / QA positions.
local DEFAULTS = {
    profile = {
        -- Positions / window state (pre-existing)
        addonScale   = 1.0,
        overlayPos   = {point="CENTER", relativePoint="CENTER", x=0, y=0, enabled=true},
        qaPos        = {point="CENTER", relativePoint="CENTER", x=-300, y=0},
        miniRMPos    = nil,
        miniRBPos    = nil,
        activeTab    = 1,
        confPos      = nil,

        -- General
        -- (addonScale already above)

        -- Roll Manager / Master Looter loot quality filters
        rm_qual_uncommon     = false,  -- quality 2
        rm_qual_rare         = false,  -- quality 3
        rm_qual_epic         = true,   -- quality 4
        rm_qual_legendary    = true,   -- quality 5

        -- Roll Manager
        rm_cd_default        = 20,
        rm_roll_type         = "MS",
        rm_spec_enforce      = true,
        rm_channel           = "RAID_WARNING",
        rm_open_tmpl         = "{item} >> {label} - Drop your rolls! /roll 1-100",
        rm_winner_tmpl       = "{item} >> Winner: {name} ({roll} - {label})",
        rm_closed_tmpl       = "Rolls CLOSED!",

        -- Raid Browser
        rb_enable_login      = false,
        rb_expiry_min        = 10,
        rb_chan_world        = true,
        rb_chan_trade        = true,
        rb_chan_lfg          = true,
        rb_chan_yell         = false,

        -- Status Bar
        bar_lock             = false,
        bar_scale            = 1.0,
        bar_click_toggle     = true,
        bar_pill_BT          = true,
        bar_pill_SPAM        = true,
        bar_pill_AR          = true,
        bar_pill_ML          = true,
        bar_pill_AI          = true,
        bar_pill_MS          = true,
        bar_pill_RB          = true,

        -- Spec Database
        spec_auto_gather     = false,
        spec_expiry_days     = 7,
        spec_show_rolls      = true,
        spec_enforce         = true,

        -- Minimap
        minimap_show         = true,
        minimap_left_click   = "main",  -- "main"|"qa"|"bar"

        -- MS+Buffs
        ms_auto_gather       = false,
        ms_announce_fmt      = "{name}: {spec}",

        -- Auto Invite
        ai_login_enabled     = false,
        ai_response_text     = "Invited! Check your group.",

        -- Quick Access
        qa_open_login        = false,
        qa_lock              = false,
        qa_sec_toggles       = true,
        qa_sec_announce      = true,
        qa_sec_rolls         = true,
        qa_sec_spec          = true,

        -- MS Changes sharing
        ms_autoshare         = false,

        -- Module enable/disable (setup wizard sets these)
        module_bis           = true,
        module_spam          = true,
        module_ar            = true,
        module_ml            = true,
        module_ai            = true,
        module_ms            = true,
        module_rb            = true,

        -- Spammer
        spam_active_preset      = nil,
        spam_interval_general   = 10,
        spam_interval_trade     = 23,
        spam_interval_world     = 61,
        spam_interval_yell      = 41,
    },
    global = {
        -- Intentionally empty; per-module SVars managed by their own modules
    },
}

-- ── OnInitialize — fires once when addon loads (SVars available) ─────────────
function RNToolsAddon:OnInitialize()
    -- Create unified AceDB (does NOT replace per-module SVars — purely additive)
    self.db = LibStub("AceDB-3.0"):New("RNTools_AceDB", DEFAULTS, true)

    -- Profile change callbacks: update scale/positions if profile changes
    self.db.RegisterCallback(self, "OnProfileChanged",  "OnProfileChanged")
    self.db.RegisterCallback(self, "OnProfileCopied",   "OnProfileChanged")
    self.db.RegisterCallback(self, "OnProfileReset",    "OnProfileChanged")

    -- Slash commands (replace the manual SLASH_RNTOOLS1 in UI_Core.lua)
    self:RegisterChatCommand("rnt",     "SlashHandler")
    self:RegisterChatCommand("rntools", "SlashHandler")
end

-- ── Profile change callback ──────────────────────────────────────────────────
function RNToolsAddon:OnProfileChanged()
    -- Re-apply scale from new profile
    local f = _G["RNToolsMainFrame"]
    if f and self.db.profile.addonScale then
        f:SetScale(self.db.profile.addonScale)
    end
end

-- ── OnEnable — fires on PLAYER_LOGIN (all SVars ready, UI safe to create) ───
function RNToolsAddon:OnEnable()
    -- Step 1: let the BiS module load its database
    if RN_LoadBisDB then RN_LoadBisDB() end

    -- Step 2: restore addonScale to BiSRaidConfig (existing modules read from there)
    if not BiSRaidConfig then BiSRaidConfig = {} end
    BiSRaidConfig.addonScale = BiSRaidConfig.addonScale
                              or self.db.profile.addonScale
                              or 1.0

    -- Step 3: keep overlay save in sync (existing modules write to RNToolsOverlaySave)
    -- If the AceDB profile has been saved, restore it to the global the modules expect
    if not RNToolsOverlaySave or type(RNToolsOverlaySave) ~= "table" then
        local p = self.db.profile.overlayPos
        RNToolsOverlaySave = {
            point        = p.point,
            relativePoint= p.relativePoint,
            x            = p.x,
            y            = p.y,
            enabled      = p.enabled,
        }
    end

    -- Step 4: call the existing UI bootstrappers (defined in UI_Core.lua)
    -- These are identical to the old OnPlayerLogin — zero behaviour change
    if EnsureStatusOverlaySavedVariables then EnsureStatusOverlaySavedVariables() end
    if CreateMainFrameIfNeeded           then CreateMainFrameIfNeeded()           end
    if CreateStatusOverlayIfNeeded        then CreateStatusOverlayIfNeeded()        end
    if RNTools_ApplyStatusBarSettings     then RNTools_ApplyStatusBarSettings()     end  -- restore bar_lock/scale/pills
    if CreateMinimapButtonIfNeeded        then CreateMinimapButtonIfNeeded()        end
    if RNTools_ApplyMinimapSettings       then RNTools_ApplyMinimapSettings()       end
    -- Sync saved settings into module state now that AceDB profile is ready
    if RNTools_SetRBExpiry                 then RNTools_SetRBExpiry(self.db.profile.rb_expiry_min or 10) end

    -- Apply login-triggered settings
    local pp = self.db.profile
    if pp.rb_enable_login and RNTools_SetRBEnabled then
        RNTools_SetRBEnabled(true)
        if RefreshStatusOverlay then RefreshStatusOverlay() end
    end
    if pp.ai_login_enabled then
        if type(_G.RNToolsAutoInviteSave) == "table" then
            _G.RNToolsAutoInviteSave.isEnabled = true
        end
    end
    -- Apply spec globals so modules read correct initial values
    _G.RNTools_MiniTrackSpec = pp.spec_show_rolls ~= false
    _G.RNTools_SpecEnforce   = pp.spec_enforce ~= false
    -- Purge stale spec entries
    local expDays = tonumber(pp.spec_expiry_days) or 7
    if expDays > 0 and RNTools_PurgeSpecDB then RNTools_PurgeSpecDB(expDays) end

    -- Step 5: restore UI scale on the newly-created main frame
    local mf = _G["RNToolsMainFrame"]
    if mf and BiSRaidConfig.addonScale then
        mf:SetScale(BiSRaidConfig.addonScale)
    end

    -- Step 6: open Quick Access on login if configured (deferred so frame is ready)
    C_Timer_fake(0.5, function()
        local pp = RNToolsAddon.db.profile
        if pp.qa_open_login and RNTools_ToggleQuickAccess then
            -- QA_frame is local to UI_Core; RNTools_IsQAShown is the safe check
            local shown = RNTools_IsQAShown and RNTools_IsQAShown()
            if not shown then RNTools_ToggleQuickAccess() end
        end
    end)

    self:Print(
        "|cffFFD100RealNibba's Raid Tools|r loaded. " ..
        "Type |cffFFD100/rnt|r to open."
    )
end

-- ── Slash command handler ────────────────────────────────────────────────────
function RNToolsAddon:SlashHandler(msg)
    msg = (msg or ""):lower():match("^%s*(.-)%s*$") or ""

    if msg == "reload" or msg == "r" then
        if RN_LoadBisDB        then RN_LoadBisDB()          end
        if RNTools_BisRefreshUI then RNTools_BisRefreshUI()  end
        self:Print("BiS database reloaded.")

    elseif msg == "help" or msg == "?" then
        self:Print("|cffFFD100/rnt|r              — toggle main window")
        self:Print("|cffFFD100/rnt config|r       — open Settings/Config window")
        self:Print("|cffFFD100/rnt reload|r       — reload BiS database")
        self:Print("|cffFFD100/rnt scale N|r      — set UI scale (e.g. /rnt scale 1.25)")
        self:Print("|cffFFD100/rnt qa|r           — toggle Quick Access panel")
        self:Print("|cffFFD100/rnt miniml|r       — toggle Mini Roll Manager")
        self:Print("|cffFFD100/rnt overlay|r      — toggle status overlay")
        self:Print("|cffFFD100/rnt setup|r        — re-run setup wizard")

    elseif msg:sub(1,5) == "scale" then
        local val = tonumber(msg:match("scale%s+([%d%.]+)"))
        if val and val >= 0.25 and val <= 3.0 then
            local f = _G["RNToolsMainFrame"]
            if f then f:SetScale(val) end
            if BiSRaidConfig then BiSRaidConfig.addonScale = val end
            self.db.profile.addonScale = val
            self:Print("Scale set to " .. val)
        else
            self:Print("Usage: /rnt scale 0.25–3.0")
        end

    elseif msg == "qa" then
        if RNTools_ToggleQuickAccess then RNTools_ToggleQuickAccess() end

    elseif msg == "miniml" then
        if BuildMiniRollManager then BuildMiniRollManager() end

    elseif msg == "overlay" then
        if ToggleStatusOverlayVisibility then ToggleStatusOverlayVisibility() end

    elseif msg == "config" or msg == "cfg" then
        if RNTools_ToggleConfig then RNTools_ToggleConfig() end

    elseif msg == "setup" then
        if RNTools_OpenSetupWizard then RNTools_OpenSetupWizard() end

    else
        -- Default: toggle main window (same as old behavior)
        if ToggleMainUI then ToggleMainUI() end
    end
end

-- ── Auto-gather spec data on raid join ───────────────────────────────────────
do
    local _lastAutoGather = 0
    local _gatherFrame = CreateFrame("Frame")
    _gatherFrame:RegisterEvent("GROUP_ROSTER_UPDATE")
    _gatherFrame:RegisterEvent("RAID_ROSTER_UPDATE")
    _gatherFrame:SetScript("OnEvent", function()
        local pp = RNToolsAddon and RNToolsAddon.db and RNToolsAddon.db.profile
        if not pp then return end
        local inRaid = GetNumRaidMembers() > 0
        if not inRaid then return end
        local now = GetTime()
        if now - _lastAutoGather < 10 then return end  -- 10-sec cooldown
        _lastAutoGather = now
        if (pp.spec_auto_gather or pp.ms_auto_gather) and RNTools_GatherSpecData then
            RNTools_GatherSpecData(false)
        end
    end)
end

-- ── C_Timer polyfill for 3.3.5a ─────────────────────────────────────────────
-- Some modules use C_Timer_fake (defined in MS_Changes.lua).
-- Expose a global C_Timer_fake if not already provided.
if not _G.C_Timer_fake then
    local _fake_timers = {}
    local _fake_frame  = CreateFrame("Frame")
    _fake_frame:SetScript("OnUpdate", function(_, elapsed)
        for i = #_fake_timers, 1, -1 do
            local t = _fake_timers[i]
            t.remaining = t.remaining - elapsed
            if t.remaining <= 0 then
                t.fn()
                table.remove(_fake_timers, i)
            end
        end
    end)
    _G.C_Timer_fake = function(secs, fn)
        table.insert(_fake_timers, {remaining = secs, fn = fn})
    end
end
