local ADDON_NAME, ns = ...
local SlickUI = ns.SlickUI

local QuestLog = {}

local WHEEL_STEP = 48

local function Clamp(value, minimum, maximum)
    if value < minimum then
        return minimum
    end

    if value > maximum then
        return maximum
    end

    return value
end

local function GetScrollBar(scrollFrame)
    if not scrollFrame then
        return nil
    end

    if scrollFrame.ScrollBar then
        return scrollFrame.ScrollBar
    end

    local name = scrollFrame.GetName and scrollFrame:GetName()
    return name and _G[name .. "ScrollBar"] or nil
end

local function RefreshScrollBar(scrollFrame)
    if not scrollFrame or not scrollFrame.GetVerticalScrollRange then
        return
    end

    local scrollBar = GetScrollBar(scrollFrame)
    if not scrollBar then
        return
    end

    local range = scrollFrame:GetVerticalScrollRange() or 0
    if range > 0 then
        scrollBar:Show()
        scrollBar:SetAlpha(1)
    end
end

local function ScrollQuestList(scrollFrame, delta)
    if not scrollFrame or not scrollFrame.GetVerticalScrollRange or not scrollFrame.SetVerticalScroll then
        return
    end

    local range = scrollFrame:GetVerticalScrollRange() or 0
    if range <= 0 then
        return
    end

    local current = scrollFrame:GetVerticalScroll() or 0
    scrollFrame:SetVerticalScroll(Clamp(current - (delta * WHEEL_STEP), 0, range))
    RefreshScrollBar(scrollFrame)
end

function QuestLog:Attach()
    if self.attached then
        return
    end

    local scrollFrame = _G.QuestScrollFrame
    if not scrollFrame then
        return
    end

    self.attached = true
    self.scrollFrame = scrollFrame

    scrollFrame:EnableMouseWheel(true)

    -- Current Blizzard templates normally provide their own wheel handler. If
    -- the active client does not, add a small fallback without replacing any
    -- Blizzard script or quest-button behavior.
    if not scrollFrame:GetScript("OnMouseWheel") then
        scrollFrame:HookScript("OnMouseWheel", ScrollQuestList)
    end

    scrollFrame:HookScript("OnShow", function(frame)
        C_Timer.After(0, function()
            RefreshScrollBar(frame)
        end)
    end)

    RefreshScrollBar(scrollFrame)
end

function QuestLog:Refresh()
    self:Attach()

    if self.scrollFrame then
        C_Timer.After(0, function()
            RefreshScrollBar(self.scrollFrame)
        end)
    end
end

function QuestLog:Initialize()
    local eventFrame = CreateFrame("Frame")
    eventFrame:RegisterEvent("PLAYER_LOGIN")
    eventFrame:RegisterEvent("ADDON_LOADED")
    eventFrame:RegisterEvent("QUEST_LOG_UPDATE")
    eventFrame:SetScript("OnEvent", function(_, event)
        if event == "ADDON_LOADED" or event == "PLAYER_LOGIN" or event == "QUEST_LOG_UPDATE" then
            self:Refresh()
        end
    end)

    self.eventFrame = eventFrame
    self:Refresh()
end

SlickUI:RegisterModule("QuestLog", QuestLog)
