local _, addonTable = ...
local WipedQoL = addonTable.WipedQoL
local TRANSLATE = addonTable.TRANSLATE or function(msg) return msg end

local ACHIEVEMENT_ADDON = "Blizzard_AchievementUI"
local MAX_HISTORY_ENTRIES = 100
local SELECTION_CHECK_INTERVAL = 0.1

local BUTTON_WIDTH = 28
local BUTTON_HEIGHT = 22
local HISTORY_MENU_WIDTH = 300
local HISTORY_MENU_PADDING = 5
local HISTORY_ROW_HEIGHT = 24
local HISTORY_MAX_VISIBLE_ROWS = 10
local WHITE_TEXTURE = "Interface\\Buttons\\WHITE8X8"

local function IsAddOnCurrentlyLoaded(addonName)
    if C_AddOns and C_AddOns.IsAddOnLoaded then
        return C_AddOns.IsAddOnLoaded(addonName)
    end
    return _G.IsAddOnLoaded and _G.IsAddOnLoaded(addonName)
end

local function IsValidAchievement(achievementID)
    achievementID = tonumber(achievementID)
    if not achievementID then
        return false
    end

    if C_AchievementInfo and C_AchievementInfo.IsValidAchievement then
        return C_AchievementInfo.IsValidAchievement(achievementID)
    end

    return _G.GetAchievementInfo and _G.GetAchievementInfo(achievementID) ~= nil
end

local function ResolveDisplayedAchievement(achievementID)
    achievementID = tonumber(achievementID)
    if not IsValidAchievement(achievementID) then
        return nil
    end

    local findDisplayedAchievement = _G.AchievementFrame_FindDisplayedAchievement
    if findDisplayedAchievement then
        local displayedID = findDisplayedAchievement(achievementID)
        if IsValidAchievement(displayedID) then
            return displayedID
        end
    end

    return achievementID
end

local function GetAchievementName(achievementID)
    if not achievementID or not _G.GetAchievementInfo then
        return nil
    end

    local _, name = _G.GetAchievementInfo(achievementID)
    return name
end

local function SetNavigationTooltip(button, title, achievementID, formatText)
    GameTooltip:SetOwner(button, "ANCHOR_TOP")

    local achievementName = GetAchievementName(achievementID)
    if achievementName then
        GameTooltip:SetText(string.format(TRANSLATE(formatText), achievementName), 1, 1, 1)
    else
        GameTooltip:SetText(TRANSLATE(title), 1, 1, 1)
    end

    GameTooltip:Show()
end

local function ShowHistoryTooltip(button, direction, title, formatText)
    if not button:IsEnabled() then
        GameTooltip:Hide()
        return
    end

    local history = WipedQoL.achievementNavigationHistory or {}
    local targetID = history[(WipedQoL.achievementNavigationIndex or 0) + direction]
    if not IsValidAchievement(targetID) then
        GameTooltip:Hide()
        return
    end

    SetNavigationTooltip(button, title, targetID, formatText)
end

local function GetAddonColor()
    if WipedQoL.GetAddonColor then
        return WipedQoL:GetAddonColor()
    elseif addonTable.GetAddonColor then
        return addonTable.GetAddonColor()
    end

    return 1, 0.82, 0
end

local function SetNavigationButtonBorderColor(button, red, green, blue, alpha)
    for _, edge in pairs(button.navigationBorder or {}) do
        edge:SetVertexColor(red, green, blue, alpha)
    end
end

local function UpdateNavigationButtonAppearance(button, pressed)
    local enabled = button:IsEnabled()
    local hovered = enabled and button:IsMouseOver()
    local colorR, colorG, colorB = GetAddonColor()

    if not enabled then
        button.navigationBackground:SetVertexColor(0.03, 0.03, 0.03, 0.72)
        SetNavigationButtonBorderColor(button, 0.24, 0.24, 0.24, 0.45)
        button:GetFontString():SetTextColor(0.38, 0.38, 0.38, 1)
    elseif hovered then
        button.navigationBackground:SetVertexColor(0.16, 0.16, 0.16, pressed and 0.98 or 0.9)
        SetNavigationButtonBorderColor(button, colorR, colorG, colorB, 1)
        button:GetFontString():SetTextColor(colorR, colorG, colorB, 1)
    else
        button.navigationBackground:SetVertexColor(0.08, 0.08, 0.08, 0.86)
        SetNavigationButtonBorderColor(button, colorR, colorG, colorB, 0.62)
        button:GetFontString():SetTextColor(colorR, colorG, colorB, 0.88)
    end
end

local function CreateNavigationButton(parent, arrowText)
    local button = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
    button:SetSize(BUTTON_WIDTH, BUTTON_HEIGHT)
    button:SetText(arrowText)

    if addonTable.SkinButton then
        addonTable.SkinButton(button)
    end

    local fontString = button:GetFontString()
    if fontString and addonTable.ApplyFont then
        addonTable.ApplyFont(fontString, 14, "OUTLINE")
    end

    local background = button:CreateTexture(nil, "BACKGROUND", nil, 7)
    background:SetTexture(WHITE_TEXTURE)
    background:SetPoint("TOPLEFT", button, "TOPLEFT", 1, -1)
    background:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -1, 1)
    button.navigationBackground = background

    local border = {}
    local top = button:CreateTexture(nil, "ARTWORK", nil, 2)
    top:SetTexture(WHITE_TEXTURE)
    top:SetPoint("TOPLEFT")
    top:SetPoint("TOPRIGHT")
    top:SetHeight(1)
    border[#border + 1] = top

    local bottom = button:CreateTexture(nil, "ARTWORK", nil, 2)
    bottom:SetTexture(WHITE_TEXTURE)
    bottom:SetPoint("BOTTOMLEFT")
    bottom:SetPoint("BOTTOMRIGHT")
    bottom:SetHeight(1)
    border[#border + 1] = bottom

    local left = button:CreateTexture(nil, "ARTWORK", nil, 2)
    left:SetTexture(WHITE_TEXTURE)
    left:SetPoint("TOPLEFT")
    left:SetPoint("BOTTOMLEFT")
    left:SetWidth(1)
    border[#border + 1] = left

    local right = button:CreateTexture(nil, "ARTWORK", nil, 2)
    right:SetTexture(WHITE_TEXTURE)
    right:SetPoint("TOPRIGHT")
    right:SetPoint("BOTTOMRIGHT")
    right:SetWidth(1)
    border[#border + 1] = right
    button.navigationBorder = border

    button:HookScript("OnEnter", function(self)
        UpdateNavigationButtonAppearance(self)
    end)
    button:HookScript("OnLeave", function(self)
        UpdateNavigationButtonAppearance(self)
    end)
    button:HookScript("OnEnable", function(self)
        UpdateNavigationButtonAppearance(self)
    end)
    button:HookScript("OnDisable", function(self)
        UpdateNavigationButtonAppearance(self)
    end)
    button:HookScript("OnMouseDown", function(self)
        UpdateNavigationButtonAppearance(self, true)
    end)
    button:HookScript("OnMouseUp", function(self)
        UpdateNavigationButtonAppearance(self)
    end)
    UpdateNavigationButtonAppearance(button)

    return button
end

local function UpdateHistoryRowAppearance(row)
    if not row or not row.achievementID then
        return
    end

    local colorR, colorG, colorB = GetAddonColor()
    local selected = row.achievementID == WipedQoL.achievementNavigationLastObservedID
    if row:IsMouseOver() then
        row.background:SetVertexColor(colorR, colorG, colorB, 0.18)
        row.text:SetTextColor(colorR, colorG, colorB, 1)
    elseif selected then
        row.background:SetVertexColor(0, 0, 0, 0)
        row.text:SetTextColor(colorR, colorG, colorB, 0.95)
    else
        row.background:SetVertexColor(1, 1, 1, 0.025)
        row.text:SetTextColor(0.92, 0.92, 0.92, 1)
    end
end

local function CreateHistoryRow(parent)
    local row = CreateFrame("Button", nil, parent)
    row:SetHeight(HISTORY_ROW_HEIGHT)

    local background = row:CreateTexture(nil, "BACKGROUND")
    background:SetAllPoints()
    background:SetTexture(WHITE_TEXTURE)
    row.background = background

    local text = row:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    text:SetPoint("LEFT", row, "LEFT", 8, 0)
    text:SetPoint("RIGHT", row, "RIGHT", -8, 0)
    text:SetJustifyH("LEFT")
    text:SetWordWrap(false)
    if addonTable.ApplyFont then
        addonTable.ApplyFont(text, 12, "")
    end
    row.text = text

    row:SetScript("OnEnter", UpdateHistoryRowAppearance)
    row:SetScript("OnLeave", UpdateHistoryRowAppearance)
    row:SetScript("OnClick", function(self)
        WipedQoL:SelectAchievementFromSessionHistory(self.achievementID)
    end)

    return row
end

function WipedQoL:GetAchievementNavigationSettings()
    local modules = self.db.profile.modules
    if type(modules.achievementNavigation) ~= "table" then
        modules.achievementNavigation = {
            enabled = false,
        }
    end

    local settings = modules.achievementNavigation
    if settings.enabled == nil then
        settings.enabled = false
    end
    return settings
end

function WipedQoL:IsAchievementNavigationEnabled()
    return self:GetAchievementNavigationSettings().enabled == true
end

function WipedQoL:SetAchievementNavigationEnabled(enabled)
    enabled = enabled and true or false
    self:GetAchievementNavigationSettings().enabled = enabled

    if not enabled then
        self.achievementNavigationHistory = {}
        self.achievementSessionHistory = {}
        self.achievementNavigationIndex = 0
        self.achievementNavigationInProgress = nil
        self.achievementNavigationLastObservedID = nil
        if self.achievementNavigationHistoryMenu then
            self.achievementNavigationHistoryMenu:Hide()
        end
    end

    self:ApplyAchievementNavigationState()
end

function WipedQoL:RefreshAchievementNavigationButtons()
    local history = self.achievementNavigationHistory or {}
    local index = self.achievementNavigationIndex or 0
    local enabled = self:IsAchievementNavigationEnabled()

    if self.achievementNavigationBackButton then
        self.achievementNavigationBackButton:SetShown(enabled)
        self.achievementNavigationBackButton:SetEnabled(enabled and index > 1)
    end
    if self.achievementNavigationForwardButton then
        self.achievementNavigationForwardButton:SetShown(enabled)
        self.achievementNavigationForwardButton:SetEnabled(enabled and index > 0 and index < #history)
    end
    if self.achievementNavigationHistoryButton then
        local hasHistory = #(self.achievementSessionHistory or {}) > 0
        self.achievementNavigationHistoryButton:SetShown(enabled)
        self.achievementNavigationHistoryButton:SetEnabled(enabled and hasHistory)
    end

    if self.achievementNavigationHistoryMenu and self.achievementNavigationHistoryMenu:IsShown() then
        self:RefreshAchievementHistoryMenu()
    end
end

function WipedQoL:RefreshAchievementNavigationAppearance()
    if self.achievementNavigationBackButton then
        UpdateNavigationButtonAppearance(self.achievementNavigationBackButton)
    end
    if self.achievementNavigationForwardButton then
        UpdateNavigationButtonAppearance(self.achievementNavigationForwardButton)
    end
    if self.achievementNavigationHistoryButton then
        UpdateNavigationButtonAppearance(self.achievementNavigationHistoryButton)
    end
    for _, row in ipairs(self.achievementNavigationHistoryRows or {}) do
        if row:IsShown() then
            UpdateHistoryRowAppearance(row)
        end
    end
end

function WipedQoL:RefreshAchievementNavigationTooltip()
    local tooltipOwner = GameTooltip:GetOwner()
    if tooltipOwner == self.achievementNavigationBackButton then
        ShowHistoryTooltip(tooltipOwner, -1, "Previous achievement", "Back to: %s")
    elseif tooltipOwner == self.achievementNavigationForwardButton then
        ShowHistoryTooltip(tooltipOwner, 1, "Next achievement", "Forward to: %s")
    elseif tooltipOwner == self.achievementNavigationHistoryButton then
        GameTooltip:SetText(TRANSLATE("Achievement history"), 1, 1, 1)
        GameTooltip:Show()
    end
end

function WipedQoL:ApplyAchievementNavigationState()
    if self:IsAchievementNavigationEnabled()
        and IsAddOnCurrentlyLoaded(ACHIEVEMENT_ADDON)
        and not self.achievementNavigationInitialized
    then
        self:InitializeAchievementNavigation()
    end

    self:RefreshAchievementNavigationButtons()
end

function WipedQoL:RecordAchievementSessionHistory(achievementID)
    if not IsValidAchievement(achievementID) then
        return
    end

    local history = self.achievementSessionHistory or {}
    self.achievementSessionHistory = history

    -- Revisited achievements move to the top of the dropdown instead of
    -- creating a second entry.
    for historyIndex = #history, 1, -1 do
        if history[historyIndex] == achievementID then
            table.remove(history, historyIndex)
            break
        end
    end

    history[#history + 1] = achievementID
    if #history > MAX_HISTORY_ENTRIES then
        table.remove(history, 1)
    end
end

function WipedQoL:RecordAchievementNavigation(achievementID)
    if not self:IsAchievementNavigationEnabled() then
        return
    end

    achievementID = ResolveDisplayedAchievement(achievementID)
    if not achievementID then
        return
    end

    self.achievementNavigationLastObservedID = achievementID
    self:RecordAchievementSessionHistory(achievementID)
    if self.achievementNavigationHistoryMenu and self.achievementNavigationHistoryMenu:IsShown() then
        self.achievementNavigationHistoryMenu:Hide()
    end

    if self.achievementNavigationInProgress then
        self:RefreshAchievementNavigationButtons()
        return
    end

    local history = self.achievementNavigationHistory
    local index = self.achievementNavigationIndex or 0
    if history[index] == achievementID then
        self:RefreshAchievementNavigationButtons()
        return
    end

    for historyIndex = #history, index + 1, -1 do
        history[historyIndex] = nil
    end

    history[#history + 1] = achievementID
    if #history > MAX_HISTORY_ENTRIES then
        table.remove(history, 1)
    end

    self.achievementNavigationIndex = #history
    self:RefreshAchievementNavigationButtons()
end

function WipedQoL:CheckAchievementNavigationSelection(elapsed)
    if not self:IsAchievementNavigationEnabled() then
        return
    end

    self.achievementNavigationSelectionElapsed = (self.achievementNavigationSelectionElapsed or 0) + (elapsed or 0)
    if self.achievementNavigationSelectionElapsed < SELECTION_CHECK_INTERVAL then
        return
    end
    self.achievementNavigationSelectionElapsed = 0

    local getSelectedAchievementID = _G.AchievementFrameAchievements_GetSelectedAchievementId
    if not getSelectedAchievementID then
        return
    end

    local selectedID = getSelectedAchievementID()
    if not IsValidAchievement(selectedID) then
        self.achievementNavigationLastObservedID = nil
        return
    end

    if selectedID ~= self.achievementNavigationLastObservedID then
        self:RecordAchievementNavigation(selectedID)
    end
end

function WipedQoL:NavigateAchievementHistory(direction)
    if not self:IsAchievementNavigationEnabled() then
        return
    end

    local history = self.achievementNavigationHistory or {}
    local targetIndex = (self.achievementNavigationIndex or 0) + direction
    local targetID = history[targetIndex]
    if not IsValidAchievement(targetID) then
        self:RefreshAchievementNavigationButtons()
        return
    end

    local selectAchievement = _G.AchievementFrame_SelectAchievement
    if not selectAchievement then
        return
    end

    self.achievementNavigationIndex = targetIndex
    self.achievementNavigationInProgress = true
    selectAchievement(targetID, true)
    self.achievementNavigationInProgress = nil
    self:RefreshAchievementNavigationButtons()
    self:RefreshAchievementNavigationTooltip()
end

function WipedQoL:SelectAchievementFromSessionHistory(achievementID)
    achievementID = ResolveDisplayedAchievement(achievementID)
    if not achievementID or not self:IsAchievementNavigationEnabled() then
        return
    end

    if self.achievementNavigationHistoryMenu then
        self.achievementNavigationHistoryMenu:Hide()
    end

    local selectAchievement = _G.AchievementFrame_SelectAchievement
    if selectAchievement then
        selectAchievement(achievementID, true)
    end
end

function WipedQoL:ScrollAchievementHistory(delta)
    local slider = self.achievementNavigationHistoryScrollBar
    if not slider or not slider:IsShown() then
        return
    end

    slider:SetValue(slider:GetValue() - (delta or 0))
end

function WipedQoL:RefreshAchievementHistoryMenu()
    if self.achievementNavigationHistoryMenuRefreshing then
        return
    end

    local menu = self.achievementNavigationHistoryMenu
    local slider = self.achievementNavigationHistoryScrollBar
    local rows = self.achievementNavigationHistoryRows
    if not menu or not slider or not rows then
        return
    end

    local history = self.achievementSessionHistory or {}
    if #history == 0 then
        menu:Hide()
        return
    end

    self.achievementNavigationHistoryMenuRefreshing = true

    local visibleCount = math.min(#history, HISTORY_MAX_VISIBLE_ROWS)
    local maxOffset = math.max(0, #history - visibleCount)
    slider:SetMinMaxValues(0, maxOffset)
    slider:SetValue(math.min(slider:GetValue() or 0, maxOffset))

    local rowContainer = self.achievementNavigationHistoryRowContainer
    if rowContainer then
        rowContainer:ClearAllPoints()
        rowContainer:SetPoint("TOPLEFT", menu, "TOPLEFT", HISTORY_MENU_PADDING, -HISTORY_MENU_PADDING)
        rowContainer:SetPoint(
            "BOTTOMRIGHT",
            menu,
            "BOTTOMRIGHT",
            maxOffset > 0 and -20 or -HISTORY_MENU_PADDING,
            HISTORY_MENU_PADDING
        )
    end

    local offset = math.floor((slider:GetValue() or 0) + 0.5)
    menu:SetHeight((HISTORY_MENU_PADDING * 2) + (visibleCount * HISTORY_ROW_HEIGHT))

    for rowIndex, row in ipairs(rows) do
        local historyIndex = #history - offset - rowIndex + 1
        local achievementID = history[historyIndex]
        if rowIndex <= visibleCount and IsValidAchievement(achievementID) then
            row.achievementID = achievementID
            row.text:SetText(GetAchievementName(achievementID) or string.format("#%d", achievementID))
            row:Show()
            UpdateHistoryRowAppearance(row)
        else
            row.achievementID = nil
            row:Hide()
        end
    end

    self.achievementNavigationHistoryMenuRefreshing = nil
end

function WipedQoL:CreateAchievementHistoryMenu(parent, anchorButton)
    if self.achievementNavigationHistoryMenu then
        return
    end

    local menu = CreateFrame("Frame", "WipedQoLAchievementHistoryMenu", parent, "BackdropTemplate")
    menu:SetWidth(HISTORY_MENU_WIDTH)
    menu:SetPoint("TOPLEFT", anchorButton, "BOTTOMLEFT", 0, -4)
    menu:SetFrameStrata("FULLSCREEN_DIALOG")
    menu:SetFrameLevel(parent:GetFrameLevel() + 20)
    menu:SetClampedToScreen(true)
    menu:EnableMouse(true)
    menu:EnableMouseWheel(true)
    menu:SetScript("OnMouseWheel", function(_, delta)
        WipedQoL:ScrollAchievementHistory(delta)
    end)
    menu:SetScript("OnShow", function()
        WipedQoL:RefreshAchievementHistoryMenu()
    end)
    if addonTable.SkinFrame then
        addonTable.SkinFrame(menu, { light = true })
    end

    local rowContainer = CreateFrame("Frame", nil, menu)
    rowContainer:SetPoint("TOPLEFT", menu, "TOPLEFT", HISTORY_MENU_PADDING, -HISTORY_MENU_PADDING)
    rowContainer:SetPoint("BOTTOMRIGHT", menu, "BOTTOMRIGHT", -20, HISTORY_MENU_PADDING)

    local rows = {}
    for rowIndex = 1, HISTORY_MAX_VISIBLE_ROWS do
        local row = CreateHistoryRow(rowContainer)
        row:SetPoint("TOPLEFT", rowContainer, "TOPLEFT", 0, -((rowIndex - 1) * HISTORY_ROW_HEIGHT))
        row:SetPoint("RIGHT", rowContainer, "RIGHT", 0, 0)
        row:EnableMouseWheel(true)
        row:SetScript("OnMouseWheel", function(_, delta)
            WipedQoL:ScrollAchievementHistory(delta)
        end)
        rows[rowIndex] = row
    end

    local slider = CreateFrame("Slider", nil, menu, "BackdropTemplate")
    slider:SetPoint("TOPRIGHT", menu, "TOPRIGHT", -4, -HISTORY_MENU_PADDING)
    slider:SetPoint("BOTTOMRIGHT", menu, "BOTTOMRIGHT", -4, HISTORY_MENU_PADDING)
    slider:SetWidth(12)
    slider:SetOrientation("VERTICAL")
    slider:SetValueStep(1)
    if slider.SetObeyStepOnDrag then
        slider:SetObeyStepOnDrag(true)
    end
    slider:SetThumbTexture(WHITE_TEXTURE)
    local thumb = slider:GetThumbTexture()
    if thumb then
        thumb:SetSize(8, 28)
    end
    slider:SetScript("OnValueChanged", function()
        WipedQoL:RefreshAchievementHistoryMenu()
    end)
    if addonTable.SkinScrollBar then
        addonTable.SkinScrollBar(slider)
    end

    self.achievementNavigationHistoryMenu = menu
    self.achievementNavigationHistoryRowContainer = rowContainer
    self.achievementNavigationHistoryRows = rows
    self.achievementNavigationHistoryScrollBar = slider

    if _G.UISpecialFrames then
        table.insert(_G.UISpecialFrames, menu:GetName())
    end

    menu:Hide()
end

function WipedQoL:CreateAchievementNavigationButtons()
    local achievementFrame = _G.AchievementFrame
    if not achievementFrame or self.achievementNavigationBackButton then
        return
    end

    local backButton = CreateNavigationButton(achievementFrame, "<")
    backButton:SetPoint("TOPLEFT", achievementFrame, "TOPLEFT", 228, -3)
    backButton:SetFrameLevel(achievementFrame:GetFrameLevel() + 10)
    backButton:SetScript("OnClick", function()
        WipedQoL:NavigateAchievementHistory(-1)
    end)
    backButton:SetScript("OnEnter", function(button)
        ShowHistoryTooltip(button, -1, "Previous achievement", "Back to: %s")
    end)
    backButton:SetScript("OnLeave", GameTooltip_Hide)

    local forwardButton = CreateNavigationButton(achievementFrame, ">")
    forwardButton:SetPoint("LEFT", backButton, "RIGHT", 4, 0)
    forwardButton:SetFrameLevel(achievementFrame:GetFrameLevel() + 10)
    forwardButton:SetScript("OnClick", function()
        WipedQoL:NavigateAchievementHistory(1)
    end)
    forwardButton:SetScript("OnEnter", function(button)
        ShowHistoryTooltip(button, 1, "Next achievement", "Forward to: %s")
    end)
    forwardButton:SetScript("OnLeave", GameTooltip_Hide)

    local historyButton = CreateNavigationButton(achievementFrame, "v")
    historyButton:SetPoint("LEFT", forwardButton, "RIGHT", 4, 0)
    historyButton:SetFrameLevel(achievementFrame:GetFrameLevel() + 10)
    historyButton:SetScript("OnClick", function()
        local menu = WipedQoL.achievementNavigationHistoryMenu
        if not menu then
            return
        end

        if menu:IsShown() then
            menu:Hide()
        else
            WipedQoL.achievementNavigationHistoryScrollBar:SetValue(0)
            WipedQoL:RefreshAchievementHistoryMenu()
            menu:Show()
        end
    end)
    historyButton:SetScript("OnEnter", function(button)
        GameTooltip:SetOwner(button, "ANCHOR_TOP")
        GameTooltip:SetText(TRANSLATE("Achievement history"), 1, 1, 1)
        GameTooltip:Show()
    end)
    historyButton:SetScript("OnLeave", GameTooltip_Hide)

    self.achievementNavigationBackButton = backButton
    self.achievementNavigationForwardButton = forwardButton
    self.achievementNavigationHistoryButton = historyButton
    self:CreateAchievementHistoryMenu(achievementFrame, historyButton)
    self:RefreshAchievementNavigationButtons()
end

function WipedQoL:InitializeAchievementNavigation()
    if self.achievementNavigationInitialized then
        return true
    end
    if not _G.AchievementFrame or not _G.AchievementFrame_SelectAchievement then
        return false
    end

    self.achievementNavigationInitialized = true
    self:CreateAchievementNavigationButtons()

    _G.AchievementFrame:HookScript("OnUpdate", function(_, elapsed)
        WipedQoL:CheckAchievementNavigationSelection(elapsed)
    end)
    _G.AchievementFrame:HookScript("OnHide", function()
        if WipedQoL.achievementNavigationHistoryMenu then
            WipedQoL.achievementNavigationHistoryMenu:Hide()
        end
    end)

    hooksecurefunc("AchievementFrame_SelectAchievement", function(achievementID)
        WipedQoL:RecordAchievementNavigation(achievementID)
    end)

    return true
end

function WipedQoL:SetupAchievementNavigation()
    if self.achievementNavigationSetup then
        return
    end

    self.achievementNavigationSetup = true
    self.achievementNavigationHistory = {}
    self.achievementSessionHistory = {}
    self.achievementNavigationIndex = 0
    self.achievementNavigationLastObservedID = nil
    self.achievementNavigationSelectionElapsed = 0
    self:GetAchievementNavigationSettings()

    if IsAddOnCurrentlyLoaded(ACHIEVEMENT_ADDON) and self:InitializeAchievementNavigation() then
        return
    end

    local loader = CreateFrame("Frame")
    loader:RegisterEvent("ADDON_LOADED")
    loader:SetScript("OnEvent", function(frame, _, addonName)
        if addonName ~= ACHIEVEMENT_ADDON then
            return
        end

        if WipedQoL:InitializeAchievementNavigation() then
            frame:UnregisterAllEvents()
        end
    end)
    self.achievementNavigationLoader = loader
end
