local addonName, ns = ...
local Fatebound = ns

-- ============================================================
-- FATEBOUND SavedVariables Initialization
-- ============================================================

-- Create DB table immediately (safe for file-scope access)
FateboundDB = FateboundDB or {}

-- Runtime constants (safe at file scope)
local MINOR_STATS = {"Madness", "Despair", "Obsession", "Dominance", "Convergence"}
Fatebound.STAT_LIST = MINOR_STATS
Fatebound.STAT_CAP  = 1000

-- ============================================================
-- SAVE & LOAD HANDLER
-- ============================================================

local f = CreateFrame("Frame")
f:RegisterEvent("PLAYER_LOGIN")
f:RegisterEvent("PLAYER_LOGOUT")

f:SetScript("OnEvent", function(_, event)

    -- Always guarantee DB table
    FateboundDB = FateboundDB or {}

    if event == "PLAYER_LOGIN" then

        -- ===============================
        -- STATS
        -- ===============================
        FateboundDB.stats = FateboundDB.stats or {}

        for _, stat in ipairs(MINOR_STATS) do
            FateboundDB.stats[stat] = FateboundDB.stats[stat] or 0
        end

        FateboundDB.stats.Corruption = FateboundDB.stats.Corruption or 0

        -- ===============================
        -- CORE RESOURCES
        -- ===============================
        FateboundDB.SoulEssence = FateboundDB.SoulEssence or 0
        FateboundDB.exp         = FateboundDB.exp or 0
        FateboundDB.favor       = FateboundDB.favor or 0

        -- ===============================
        -- FORGE / INVENTORY
        -- ===============================
        FateboundDB.forge     = FateboundDB.forge or { slotKey = nil }
        FateboundDB.inventory = FateboundDB.inventory or {}

        -- ===============================
        -- DEVOTION / DRAIN SYSTEM
        -- ===============================
        FateboundDB.devoted           = FateboundDB.devoted or false
        FateboundDB.devotionRemaining = FateboundDB.devotionRemaining or 0
        FateboundDB.fullyDrainedShown = FateboundDB.fullyDrainedShown or false
        FateboundDB.drainPausedUntil  = FateboundDB.drainPausedUntil or 0
        FateboundDB.lastDrainTier     = FateboundDB.lastDrainTier or 0

        -- CRITICAL: drainStartTime must NEVER be nil
        if not FateboundDB.drainStartTime then
            FateboundDB.drainStartTime = time()
        end

        -- ===============================
        -- Siphon Cooldowns
        -- ===============================
        FateboundDB.siphonCooldowns = FateboundDB.siphonCooldowns or {}

        -- ===============================
        -- Print Toggles
        -- ===============================
        FateboundDB.disableSoulPrint     = FateboundDB.disableSoulPrint or false
        FateboundDB.disableFavorPrint    = FateboundDB.disableFavorPrint or false
        FateboundDB.disableDevotionPrint = FateboundDB.disableDevotionPrint or false

        -- ===============================
        -- Restore Devotion Pause
        -- ===============================
        if FateboundDB.devoted and FateboundDB.devotionRemaining > 0 then
            FateboundDB.drainPausedUntil = time() + FateboundDB.devotionRemaining
            FateboundDB.devotionRemaining = 0
        end

        -- ===============================
        -- Load Inventory
        -- ===============================
        if Fatebound.Inventory then
            Fatebound.Inventory.Items = CopyTable(FateboundDB.inventory)
        end

        -- ===============================
        -- Final Safety Check (Drain Timer)
        -- ===============================
        if not FateboundDB.drainStartTime then
            FateboundDB.drainStartTime = time()
        end

        -- Refresh everything
        if Fatebound.RefreshAll then
            Fatebound:RefreshAll()
        end

    elseif event == "PLAYER_LOGOUT" then

        -- Save inventory safely
        if Fatebound.Inventory then
            FateboundDB.inventory = CopyTable(Fatebound.Inventory.Items or {})
        end

        -- Save devotion remaining time
        FateboundDB.devotionRemaining = FateboundDB.devoted
            and math.max((FateboundDB.drainPausedUntil or 0) - time(), 0)
            or 0
    end
end)

-- ===============================
-- Siphon cooldown helpers
-- ===============================

function Fatebound:IsSiphonOnCooldown(itemID)
    local cd = FateboundDB.siphonCooldowns and FateboundDB.siphonCooldowns[itemID]
    return cd and time() < cd or false
end

function Fatebound:ApplySiphonCooldown(itemID)
    FateboundDB.siphonCooldowns = FateboundDB.siphonCooldowns or {}
    FateboundDB.siphonCooldowns[itemID] = time() + 24*60*60
end

-- ============================================================
-- RefreshAll
-- ============================================================
function Fatebound:RefreshAll()
    -- Recalculate minor stats & corruption first
    if self.RecalculateMinorStats then
        self:RecalculateMinorStats()
    end

    -- Update inventory grid
    if self.Inventory and self.Inventory.UpdateDisplay then
        self.Inventory:UpdateDisplay()
    end

    -- Update stats panel (Madness, Despair, etc., Corruption, Soul Essence)
    if self.Inventory and self.Inventory.UpdateStatsPanel then
        self.Inventory:UpdateStatsPanel()
    end

    -- Update Forge panel Soul Essence
    if chosenPath and chosenPath.soulDisplay then
        chosenPath.soulDisplay:SetText(
            "Soul Essence: |cFFFFFFFF" .. Fatebound.FormatNumber(FateboundDB.SoulEssence or 0) .. "|r"
        )
    end
end

-- Path Colors
local PATH_COLORS = {
    OLD_GODS   = "7955c8",
    PANTHEON   = "e6cc80",
    LOA        = "00ccff"
}

-- Color message
local function ColorMessage(path, msg)
    local color = PATH_COLORS[path] or "ffffff"
    return string.format("|cff%s%s|r", color, msg)
end

BINDING_HEADER_FATEBOUND = "FATEBOUND"
BINDING_NAME_FATEBOUND_TOGGLE_PATH = "Fatebound"

-- ================================
-- MESSAGE DISPLAY
-- ================================
function ns.ShowCenterMessage(msg, path, fadeDelay, fadeDuration, fontSize)
    path = path or FateboundDB.path
    fadeDelay = fadeDelay or 3
    fadeDuration = fadeDuration or 2
    fontSize = fontSize or 24

    if not FateboundFrame then
        FateboundFrame = CreateFrame("Frame", nil, UIParent)
        FateboundFrame:SetFrameStrata("HIGH")
        FateboundFrame:SetSize(800, 50)
        FateboundFrame:SetPoint("TOP", UIParent, "TOP", 0, -300)

        FateboundFrame.fs = FateboundFrame:CreateFontString(nil, "OVERLAY")
        FateboundFrame.fs:SetFont(STANDARD_TEXT_FONT, fontSize)
        FateboundFrame.fs:SetPoint("CENTER")
        FateboundFrame.fs:SetShadowColor(0, 0, 0, 1)
        FateboundFrame.fs:SetShadowOffset(2, -2)
    else
        FateboundFrame.fs:SetFont(STANDARD_TEXT_FONT, fontSize)
    end

    -- Set text and color
    local hex = PATH_COLORS[path] or "ffffff"
    local r = tonumber(hex:sub(1,2),16)/255
    local g = tonumber(hex:sub(3,4),16)/255
    local b = tonumber(hex:sub(5,6),16)/255
    FateboundFrame.fs:SetText(msg)
    FateboundFrame.fs:SetTextColor(r,g,b,1)

    -- Reset alpha and show
    FateboundFrame:SetAlpha(1)
    FateboundFrame:Show()

    -- Fade-out
    local elapsed = 0
    FateboundFrame:SetScript("OnUpdate", function(self, delta)
        elapsed = elapsed + delta
        if elapsed > fadeDelay then
            local alpha = 1 - ((elapsed - fadeDelay) / fadeDuration)
            if alpha <= 0 then
                self:Hide()
                self:SetScript("OnUpdate", nil)
            else
                self:SetAlpha(alpha)
            end
        end
    end)
end

-- Drain frame
ns.drainFrame = ns.drainFrame or CreateFrame("Frame")
ns.drainFrame:Hide()  -- hidden until a path is chosen

-- ================================
-- PATH CHOICE FRAME
-- ================================
local function ShowPathChoiceFrame()
    if PathChoiceFrame then
        PathChoiceFrame:Show()
        return
    end

    local pathChoice = CreateFrame("Frame", "PathChoiceFrame", UIParent, "PortraitFrameTemplate")
    pathChoice:SetSize(500, 350)
    pathChoice:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
    pathChoice:SetClampedToScreen(true)
    pathChoice:EnableMouse(true)
    pathChoice:SetMovable(true)

    -- Drag
    pathChoice:RegisterForDrag("LeftButton")
    pathChoice:SetScript("OnDragStart", function(self) self:StartMoving() end)
    pathChoice:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)

    Mixin(pathChoice, BackdropTemplateMixin)
    pathChoice:SetBackdrop({
        bgFile = "interface/framegeneral/uiframedragonflightbackground",
        edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
        tile = true,
        tileSize = 256,
        edgeSize = 16,
        insets = { left = 4, right = 4, top = 4, bottom = 4 }
    })

    -- Frame title
    local titleName = pathChoice:GetName() and (pathChoice:GetName() .. "TitleText") or nil
    if titleName and _G[titleName] then
        _G[titleName]:SetText("Fatebound")
    else
        pathChoice.Title = pathChoice:CreateFontString(nil, "ARTWORK", "GameFontNormal")
        pathChoice.Title:SetPoint("TOP", pathChoice, "TOP", 0, -8)
        pathChoice.Title:SetText("Fatebound")
    end

    -- Portrait
    local pathPortrait = pathChoice.Portrait or _G[pathChoice:GetName() .. "Portrait"]
    if pathPortrait then
        pathPortrait:SetTexture(132886)
    else
        pathPortrait = pathChoice:CreateTexture(nil, "ARTWORK")
        pathPortrait:SetSize(64, 64)
        pathPortrait:SetPoint("TOPLEFT", 12, -36)
        pathPortrait:SetTexture(132886)
    end

    -- Text content
    local pathContent = pathChoice:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    pathContent:SetPoint("TOP", 18, -80)
    pathContent:SetWidth(280)
    pathContent:SetJustifyH("CENTER")
    pathContent:SetText("Fate stirs as your journey begins.\nWhose influence will shape your path?")

    -- Frame background
    pathChoice.bg = pathChoice:CreateTexture(nil, "ARTWORK")
    pathChoice.bg:SetAllPoints()
    pathChoice.bg:SetTexture("interface/framegeneral/uiframedragonflight")
    pathChoice.bg:SetTexCoord(0.1650390625, 0.66796875, 0.4375, 0.865234375)

    -- Path definitions
    local paths = {
        { name = "Old Gods", icon = 3194610, message = "Ancient eyes open in the void… you belong to them now.", id = "OLD_GODS", sound = "Interface\\AddOns\\Fatebound\\Media\\sounds\\VO_835_NZoth_67_M.ogg", enabled = true },
        { name = "Pantheon", icon = 2032224, message = "The light of the Titans blesses your path… rise and endure.", id = "PANTHEON", enabled = false },
        { name = "Loa", icon = 1850551, message = "The spirits embrace you… the Loa walk with your steps.", id = "LOA", enabled = false },
    }

    local spacing = 50
    local buttonSize = 96
    local startX = -(#paths-1)*(buttonSize+spacing)/2

    -- Create buttons
    for i, path in ipairs(paths) do
        local btn = CreateFrame("Button", nil, pathChoice)
        btn:SetSize(buttonSize, buttonSize)
        btn:SetPoint("CENTER", pathChoice, "CENTER", startX + (i-1)*(buttonSize+spacing), -30)

        -- Icon texture
        btn.texture = btn:CreateTexture(nil, "BACKGROUND")
        btn.texture:SetAllPoints()
        btn.texture:SetTexture(path.icon)

        -- Overlay texture
        local overlaySize = buttonSize * 1.1
        btn.overlay = btn:CreateTexture(nil, "ARTWORK")
        btn.overlay:SetSize(overlaySize, overlaySize)
        btn.overlay:SetPoint("CENTER", btn, "CENTER")
        btn.overlay:SetTexture("Interface/QuestFrame/QuestLogFrame2x")
        btn.overlay:SetTexCoord(0.0009765625, 0.2099609375, 0.78125, 0.990234375)
        btn.overlay:SetVertexColor(1,1,1,1)

        btn:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square", "ADD")

        -- Path name
        local txt = btn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
        txt:SetPoint("TOP", btn, "BOTTOM", 0, -5)
        txt:SetText(path.name)
        txt:SetShadowColor(0,0,0,1)
        txt:SetShadowOffset(1,-1)

        -- Disabled paths
        if not path.enabled then
            btn:Disable()
            btn.texture:SetDesaturated(true)
            btn.texture:SetVertexColor(0.4, 0.4, 0.4)
            btn.overlay:SetVertexColor(0.3, 0.3, 0.3, 0.6)
            txt:SetTextColor(0.5, 0.5, 0.5)

            btn:SetScript("OnEnter", function(self)
                GameTooltip:SetOwner(self, "ANCHOR_TOP")
                GameTooltip:SetText("This path is not yet available.", 1, 0.2, 0.2)
                GameTooltip:Show()
            end)
            btn:SetScript("OnLeave", function()
                GameTooltip:Hide()
            end)

            btn:SetScript("OnClick", nil)
        else
            -- Active path
            btn:SetScript("OnClick", function()
                FateboundDB.path = path.id

                if path.sound then
                    PlaySoundFile(path.sound, "Master")
                end

                ns.ShowCenterMessage(ColorMessage(path.id, path.message))
                pathChoice:Hide()
            end)
        end
    end

    PathChoiceFrame = pathChoice
    pathChoice:Show()
end

tinsert(UISpecialFrames, "PathChoiceFrame")

-- ================================
-- SETTINGS FRAME
-- ================================
local settings = {}

local settingsFrame = CreateFrame("Frame", "FateboundSettingsFrame", UIParent, "BasicFrameTemplateWithInset")
settingsFrame:SetSize(512, 256)
settingsFrame:SetPoint("CENTER")
settingsFrame:SetFrameStrata("DIALOG") -- ensures it's on top of most UI elements
settingsFrame:SetToplevel(true)        -- makes sure it stays above other frames
settingsFrame.TitleBg:SetHeight(30)

-- Title
settingsFrame.title = settingsFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
settingsFrame.title:SetPoint("TOP", settingsFrame.TitleBg, "TOP", 0, -3)
settingsFrame.title:SetText("Fatebound Settings")

settingsFrame:EnableMouse(true)
settingsFrame:SetMovable(true)
settingsFrame:RegisterForDrag("LeftButton")
settingsFrame:SetScript("OnDragStart", function(self)
    self:StartMoving()
end)
settingsFrame:SetScript("OnDragStop", function(self)
    self:StopMovingOrSizing()
end)

settingsFrame:Hide()

-- ================================
-- RESET BUTTONS
-- ================================
local function FullResetAddon()
    FateboundDB = nil
    ReloadUI()
end

-- Hard reset button
local resetAllBtn = CreateFrame("Button", nil, settingsFrame, "GameMenuButtonTemplate")
resetAllBtn:SetSize(160, 30)
resetAllBtn:SetPoint("BOTTOM", settingsFrame, "BOTTOM", 0, 20)
resetAllBtn:SetText("Reset Fatebound Data")

StaticPopupDialogs["FATEBOUND_RESET_ALL"] = {
    text = "Reset Fatebound completely?\nAll Fatebound progress will be lost.\nReload required.",
    button1 = YES,
    button2 = NO,
    OnAccept = function()
        FateboundDB = nil
        ReloadUI()
    end,
    timeout = 0,
    whileDead = true,
    hideOnEscape = true,
}

resetAllBtn:SetScript("OnClick", function()
    StaticPopup_Show("FATEBOUND_RESET_ALL")
end)

-- ================================
-- HELPER: CREATE CHECKBOX
-- ================================
local function CreateCheckbox(parent, label, x, y, dbKey)
    local cb = CreateFrame("CheckButton", nil, parent, "UICheckButtonTemplate")
    cb:SetPoint("TOPLEFT", parent, "TOPLEFT", x, y)
    cb.text:SetText(label)
    cb:SetChecked(FateboundDB[dbKey] or false)

    cb:SetScript("OnClick", function(self)
        FateboundDB[dbKey] = self:GetChecked()
    end)

    return cb
end

-- Create checkboxes
local disableSoulPrint     = CreateCheckbox(settingsFrame, "Disable Soul Essence gain messages", 20, -40, "disableSoulPrint")
local disableFavorPrint    = CreateCheckbox(settingsFrame, "Disable Favor gain messages", 20, -70, "disableFavorPrint")
local disableDevotionPrint = CreateCheckbox(settingsFrame, "Disable Devotion messages", 20, -100, "disableDevotionPrint")
local disableItemLootPrint = CreateCheckbox(settingsFrame, "Disable Item Loot messages", 20, -130, "disableItemLootPrint")

-- ================================
-- LIBRARIES & MINIMAP BUTTON
-- ================================
local addon = LibStub("AceAddon-3.0"):NewAddon("Fatebound")
FateboundMinimapButton = LibStub("LibDBIcon-1.0", true)

local miniButton = LibStub("LibDataBroker-1.1"):NewDataObject("Fatebound", {
	type = "data source",
	text = "Fatebound",
	icon = "Interface\\Icons\\inv_enchant_voidsphere",
	OnClick = function(self, btn)
		if btn == "LeftButton" then
			if not FateboundDB.path then
				ShowPathChoiceFrame()
			else
				ToggleChosenPathFrame()
			end
		elseif btn == "RightButton" then
			if settingsFrame:IsShown() then
				settingsFrame:Hide()
			else
				settingsFrame:Show()
			end
		end
	end,
	
	OnTooltipShow = function(tooltip)
		if not tooltip or not tooltip.AddLine then
			return
		end

		tooltip:AddLine("Fatebound\n\nLeft-click: Open Fatebound\nRight-click: Open Settings", nil, nil, nil, nil)
	end,
})

function addon:OnInitialize()
	self.db = LibStub("AceDB-3.0"):New("FateboundMinimapPOS", {
		profile = {
			minimap = {
				hide = false,
			},
		},
	})

	FateboundMinimapButton:Register("Fatebound", miniButton, self.db.profile.minimap)
end

FateboundMinimapButton:Show("Fatebound")

table.insert(UISpecialFrames, "FateboundSettingsFrame")
