local ADDON_NAME, ns = ...
ns = ns or {}

local Controls = {}
ns.Controls = Controls

local function setSliderEnabled(frame, enabled)
    if not frame then return end
    if frame.Slider then
        if enabled then frame.Slider:Enable() else frame.Slider:Disable() end
        frame.Slider:EnableMouse(enabled)
    end
    if frame.DecrementButton then
        if enabled then frame.DecrementButton:Enable() else frame.DecrementButton:Disable() end
    end
    if frame.IncrementButton then
        if enabled then frame.IncrementButton:Enable() else frame.IncrementButton:Disable() end
    end
    if frame._left then
        if enabled then frame._left:Enable() else frame._left:Disable() end
    end
    if frame._right then
        if enabled then frame._right:Enable() else frame._right:Disable() end
    end
    frame:SetAlpha(enabled and 1 or 0.4)
end

function Controls.createCheck(parent, label, initial, onClick)
    local cb = CreateFrame("CheckButton", nil, parent, "InterfaceOptionsCheckButtonTemplate")
    cb.Text:SetText(label)
    cb:SetChecked(initial)
    cb:SetScript("OnClick", function(self)
        if onClick then
            onClick(not not self:GetChecked())
        end
    end)
    return cb
end

function Controls.createSlider(parent, label, min, max, step, value, onChanged, lowText, highText)
    local holder = CreateFrame("Frame", nil, parent, "MinimalSliderWithSteppersTemplate")
    local slider = holder and holder.Slider
    if holder and slider then
        holder:SetFrameLevel((parent:GetFrameLevel() or 1) + 2)
        slider:EnableMouse(true)
        slider:SetMinMaxValues(min, max)
        slider:SetValueStep(step)
        slider:SetObeyStepOnDrag(true)
        slider:SetValue(value)
        holder._min, holder._max, holder._step = min, max, step
        holder.Text = holder.Text or holder:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
        holder.Text:ClearAllPoints()
        holder.Text:SetPoint("BOTTOM", holder, "TOP", 0, 2)
        holder.Text:SetText(label .. ": " .. value)
        if holder.Low and holder.High then
            holder.Low:ClearAllPoints()
            holder.Low:SetPoint("TOPLEFT", holder, "BOTTOMLEFT", 0, -8)
            holder.Low:SetText(lowText or min)
            holder.High:ClearAllPoints()
            holder.High:SetPoint("TOPRIGHT", holder, "BOTTOMRIGHT", 0, -8)
            holder.High:SetText(highText or max)
        end
        slider:SetScript("OnValueChanged", function(_, v)
            local vv = math.floor(v + 0.5)
            if holder.Text then holder.Text:SetText(label .. ": " .. vv) end
            if onChanged then onChanged(vv) end
        end)
        local function nudge(delta)
            local current = slider:GetValue() or value
            local nextVal = math.min(holder._max, math.max(holder._min, current + (delta * holder._step)))
            slider:SetValue(nextVal)
        end
        if holder.DecrementButton then holder.DecrementButton:SetScript("OnClick", function() nudge(-1) end) end
        if holder.IncrementButton then holder.IncrementButton:SetScript("OnClick", function() nudge(1) end) end
        holder.SetEnabled = holder.SetEnabled or setSliderEnabled
        holder.SetValue = holder.SetValue or function(self, val)
            if self.Slider then self.Slider:SetValue(val) end
        end
        return holder
    end

    local legacy = CreateFrame("Slider", nil, parent, "OptionsSliderTemplate")
    legacy:SetFrameLevel((parent:GetFrameLevel() or 1) + 2)
    legacy:EnableMouse(true)
    legacy:SetMinMaxValues(min, max)
    legacy:SetValueStep(step)
    legacy:SetObeyStepOnDrag(true)
    legacy:SetValue(value)
    legacy._min, legacy._max, legacy._step = min, max, step
    if legacy.SetThumbTexture then
        legacy:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Horizontal")
    end
    if not legacy.Text then
        legacy.Text = legacy:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    end
    legacy.Text:ClearAllPoints()
    legacy.Text:SetPoint("BOTTOM", legacy, "TOP", 0, 2)
    legacy.Text:SetText(label .. ": " .. value)
    if legacy.Low and legacy.High then
        legacy.Low:ClearAllPoints()
        legacy.Low:SetPoint("TOPLEFT", legacy, "BOTTOMLEFT", 0, -8)
        legacy.Low:SetText(lowText or min)
        legacy.High:ClearAllPoints()
        legacy.High:SetPoint("TOPRIGHT", legacy, "BOTTOMRIGHT", 0, -8)
        legacy.High:SetText(highText or max)
    end
    legacy:SetScript("OnValueChanged", function(self, v)
        local vv = math.floor(v + 0.5)
        if self.Text then self.Text:SetText(label .. ": " .. vv) end
        if onChanged then onChanged(vv) end
    end)
    local function nudge(delta)
        local current = legacy:GetValue() or value
        local nextVal = math.min(legacy._max, math.max(legacy._min, current + (delta * legacy._step)))
        legacy:SetValue(nextVal)
    end
    local left = CreateFrame("Button", nil, legacy, "UIPanelButtonTemplate")
    left:SetSize(18, 18)
    left:SetText("<")
    left:SetPoint("RIGHT", legacy, "LEFT", -4, 0)
    left:SetScript("OnClick", function() nudge(-1) end)
    legacy._left = left

    local right = CreateFrame("Button", nil, legacy, "UIPanelButtonTemplate")
    right:SetSize(18, 18)
    right:SetText(">")
    right:SetPoint("LEFT", legacy, "RIGHT", 4, 0)
    right:SetScript("OnClick", function() nudge(1) end)
    legacy._right = right
    legacy.SetEnabled = legacy.SetEnabled or setSliderEnabled
    return legacy
end

function Controls.createDropdown(parent, width, current, items, onSelect)
    local dropdown
    if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then
        dropdown = CreateFrame("DropdownButton", nil, parent, "WowStyle1DropdownTemplate")
    end
    if dropdown and dropdown.SetupMenu then
        dropdown:SetSize(width, 22)
        local idx = 1
        for i, v in ipairs(items or {}) do
            if v == current then idx = i break end
        end
        local function setSelection(val, trigger)
            dropdown.currentValue = val
            dropdown:SetText(val or "")
            if trigger and onSelect then onSelect(val) end
        end
        dropdown:SetupMenu(function(_, root)
            for _, val in ipairs(items or {}) do
                root:CreateCheckbox(val, function() return dropdown.currentValue == val end, function()
                    setSelection(val, true)
                end)
            end
        end)
        setSelection(items and items[idx] or current, false)
        return dropdown
    end

    local selected = current
    local drop = CreateFrame("Frame", nil, parent, "UIDropDownMenuTemplate")
    UIDropDownMenu_SetWidth(drop, width)
    UIDropDownMenu_SetText(drop, selected)
    UIDropDownMenu_Initialize(drop, function(self, level)
        local info = UIDropDownMenu_CreateInfo()
        for _, item in ipairs(items or {}) do
            info.text = item
            info.func = function()
                selected = item
                UIDropDownMenu_SetText(drop, item)
                if onSelect then onSelect(item) end
                if CloseDropDownMenus then CloseDropDownMenus() end
            end
            info.checked = (item == selected)
            UIDropDownMenu_AddButton(info, level)
        end
    end)
    return drop
end

function Controls.createMainActionButton(parent, text, onClick)
    local button
    if WOW_PROJECT_ID == WOW_PROJECT_MAINLINE then
        local ok, modern = pcall(CreateFrame, "Button", nil, parent, "UIMenuButtonStretchTemplate")
        if ok and modern then
            button = modern
            button:SetHeight(24)
            if button.SetNormalFontObject then button:SetNormalFontObject("GameFontNormalSmall") end
            if button.SetHighlightFontObject then button:SetHighlightFontObject("GameFontHighlightSmall") end
            if button.SetDisabledFontObject then button:SetDisabledFontObject("GameFontDisableSmall") end
        end
    end
    if not button then
        button = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
        button:SetHeight(22)
    end
    button:SetText(text or "")
    button:SetScript("OnClick", onClick)
    return button
end

function Controls.initLegacyScrollFrame(scrollFrame, panExtent)
    if not scrollFrame then return end
    local scrollBar = scrollFrame.ScrollBar
    if not scrollBar and scrollFrame.GetName then
        scrollBar = _G[(scrollFrame:GetName() or "") .. "ScrollBar"]
    end
    if ScrollUtil and ScrollUtil.InitScrollFrameWithScrollBar and scrollBar and scrollBar.RegisterCallback then
        ScrollUtil.InitScrollFrameWithScrollBar(scrollFrame, scrollBar)
        if panExtent and scrollFrame.SetPanExtent then
            scrollFrame:SetPanExtent(panExtent)
        end
        scrollFrame:EnableMouseWheel(true)
        return
    end

    scrollFrame:EnableMouseWheel(true)
    if scrollBar and not scrollFrame:GetScript("OnMouseWheel") then
        scrollFrame:SetScript("OnMouseWheel", function(self, delta)
            local range = self:GetVerticalScrollRange() or 0
            local current = self:GetVerticalScroll() or 0
            local step = panExtent or 30
            local nextValue = math.max(0, math.min(range, current - (delta * step)))
            self:SetVerticalScroll(nextValue)
        end)
    end
end
