-- Copyright © 2023 @Groick (Twitch). All rights reserved.
local function L(key, ...) return EasyOptions:Localize(key, ...) end
function EasyOptions:CreateSlider(parent, customControlName, value, minValue, maxValue, valueStep, formatString, text, tooltipTitleText, tooltipText, positionInfo, customLabelPositionInfo, customSize, customValueBoxSize, customValueBoxPositionInfo, customFontInfo, customTextColor, onValueChangedHandler)
  local controlName = EasyOptions:GetControlName("Slider", customControlName)
  local control = CreateFrame("Slider", controlName, parent, "OptionsSliderTemplate")
  control.Name = controlName
  control.Type = "Slider"
  control.BaseType = "Slider"
  EasyOptions:SetTooltip(control, control, tooltipTitleText, tooltipText)
  -- control:SetMotionScriptsWhileDisabled(true)
  local onValueChangedHandlerLocal = function(self)
    if (control.PreviousValue == self:GetValue()) then -- NOTE: This logic was implemented because the WoW API calls the OnValueChanged for the Slider control whenever the user moves the mouse while the left mouse button is held, even if the value of the Slider didn't change due to the Slider's ValueStep (i.e., increment) being enforced.
      return
    end
    control.PreviousValue = self:GetValue() -- Update control.PreviousValue as soon as we accept the new value of the Slider to ensure that subsequent calls to this method will use the current value of the Slider.
    EasyOptions:Slider_OnValueChangedHandler(self)
    if (onValueChangedHandler ~= nil) then
      onValueChangedHandler(self)
    end
  end

  -- control.Label = control.Text
  control.LowText = _G[control:GetName() .. "Low"] -- getglobal(control:GetName() .. "Low") -- Sets the left-side slider text (default is "Low").
  control.HighText = _G[control:GetName() .. "High"] -- getglobal(control:GetName() .. "High") -- Sets the right-side slider text (default is "High").
  EasyOptions:SetDefaultTextColor(control.LowText, false) -- Set the current text color as the default text color.
  EasyOptions:SetDefaultTextColor(control.HighText, false) -- Set the current text color as the default text color.
  control.FormatString = formatString
  control.PreviousValue = nil -- IMPORTANT: This must be set before control:SetValue is called since we initialize the value to nil.
  control:SetMinMaxValues(minValue, maxValue) -- Set the bounds of the slider.
  control:SetValue(value) -- Set the value of the slider. Also causes the thumb to show on the first call. IMPORTANT: We must set the value after the min and max are set. See also EasyOptions:OptionSlider_OnValueChangedHandler.
  control:SetValueStep(valueStep) -- Set the step size of the slider.
  control:SetStepsPerPage(1) -- Controls slider behavior when the user clicks within the slider's tracking area.
  control:SetObeyStepOnDrag(true) -- Sets whether the slider constrains values to to value steps when dragged.
  control:SetOrientation("HORIZONTAL") -- "HORIZONTAL" or "VERTICAL".
  
  local defaultWidth = 175
  local defaultHeight = 16
  local widthMaxAllowed = EasyOptions.Fields.ControlSizeMaxAllowed_Large
  local ignoreCustomHeight = true
  local width, height, hasWidth, hasHeight, shouldFillWidth = EasyOptions:GetSizeFromCustomSize(customSize, ignoreCustomHeight, defaultWidth, defaultHeight, widthMaxAllowed, EasyOptions.Fields.ControlSizeMaxAllowed_Large, true, false)
  control:SetSize(width, height)
  
  control.LowText:SetText(EasyOptions:FormatValue(minValue, formatString))
  control.HighText:SetText(EasyOptions:FormatValue(maxValue, formatString))

  -- Create the ValueBox.
  local valueBox, valueBoxHeight = EasyOptions:CreateSlider_CreateValueBox(parent, control, value, minValue, maxValue, formatString, customValueBoxSize, customValueBoxPositionInfo)
  control.ValueBox = valueBox
  
  -- Determine the appropriate position of the label.
  local labelOffsetX = -3.5
  local labelOffsetY = 5
  local fontObjectName = EasyOptions.Fields.DefaultLabelFontObjectName
  local labelTemp = control:CreateFontString(controlName..".TempLabel", "ARTWORK", fontObjectName) -- This is used to measure the size of the string.
  labelTemp:SetText(text)
  local stringWidth = EasyOptions:GetLabelStringWidth(labelTemp, true)
  local labelPositionInfoDefault
  local isLeftAligned = (stringWidth > width) and (not shouldFillWidth)
  if (isLeftAligned) then
    labelPositionInfoDefault = {"BOTTOMLEFT", "TOPLEFT", labelOffsetX + 0, labelOffsetY} -- "LEFT", "RIGHT", "TOP", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
  else
    labelPositionInfoDefault = {"BOTTOM", "TOP", labelOffsetX - 1, labelOffsetY} -- "LEFT", "RIGHT", "TOP", "BOTTOM", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", "CENTER"
  end
  local labelPositionInfo = EasyOptions:GetPositionInfoFromOptionPositionInfo(labelPositionInfoDefault, customLabelPositionInfo, false)
  
  -- Create the label for the control.
  --  NOTE: We don't use control.Text as the label to help ensure internal consistency.
  local labelControl, label, labelControlRegionWidth, labelControlRegionHeight = EasyOptions:CreateLabelForControl(parent, control, control, controlName, text, tooltipTitleText, tooltipText, labelPositionInfo, fontObjectName, customFontInfo, customTextColor)
  label:SetJustifyH("LEFT") -- "LEFT", "RIGHT", "CENTER"
  label:SetJustifyV("MIDDLE") -- "TOP", "BOTTOM", "MIDDLE"
  local labelRegionWidth = 0 -- init
  local labelRegionHeight = 0 -- init
  local hasLabelText = (text ~= nil) and (text ~= "")
  if (hasLabelText) then
    labelRegionWidth = labelControlRegionWidth + EasyOptions:IIF(isLeftAligned, 3, 0) -- + labelOffsetX
    labelRegionHeight = labelControlRegionHeight + labelOffsetY - 1
  end

  local paddingForBottomLabelsX = 4 -- Include extra padding to account for the bottom labels of the control.
  local paddingForBottomLabelsY = 4 -- Include extra padding to account for the bottom labels of the control.
  local offsetX = paddingForBottomLabelsX + 4 -- Offset the x-position of this control type to help it align better with the other controls.
  local offsetY = EasyOptions:IIF(hasLabelText, labelRegionHeight + 4, 2) -- Offset the y-position of this control type to help it align better with the other controls.
  control:ClearAllPoints()
  control:SetPoint(positionInfo[1], parent, positionInfo[2], positionInfo[3] + offsetX, positionInfo[4] - offsetY) -- NOTE: We offset the x-position of this control type to help it align better with the other controls.
  if (shouldFillWidth) then
    EasyOptions:SetControlPointToFillWidth(control, parent, positionInfo, offsetX, paddingForBottomLabelsX + 4)
  end

  control:SetScript("OnValueChanged", onValueChangedHandlerLocal)
  -- control:SetScript("OnClick", onClickHandler)
  control.OnEnabledChangedHandler = function(self)
    if (self.IsEnabled == nil) or (self:IsEnabled()) then -- Assume that the control is enabled if its IsEnabled method is nil.
      EasyOptions:SetToDefaultTextColor(self.LowText)
      EasyOptions:SetToDefaultTextColor(self.HighText)
    else
      EasyOptions:SetToDisabledTextColor(self.LowText)
      EasyOptions:SetToDisabledTextColor(self.HighText)
    end
  end
  EasyOptions:AddSupportForEnabledState(control)

  local widthEffective = width + offsetX + paddingForBottomLabelsX
  local heightEffective = 16 + offsetY + paddingForBottomLabelsY
  
  local controlRegionWidth = math.max(widthEffective, labelRegionWidth)
  local controlRegionHeight = heightEffective -- NOTE: We don't use control:GetHeight() because some controls don't implement that method and most controls that support that method return a value that is larger than desired.
  local valueBoxHeightDelta = valueBoxHeight - 5
  if (valueBoxHeightDelta > paddingForBottomLabelsY) then
    controlRegionHeight = controlRegionHeight + (valueBoxHeightDelta - paddingForBottomLabelsY)
  end

  control.ControlRegionWidth = controlRegionWidth
  control.ControlRegionHeight = controlRegionHeight
  return control, valueBox, controlRegionWidth, controlRegionHeight
end
function EasyOptions:CreateSlider_CreateValueBox(parent, slider, value, minValue, maxValue, formatString, customValueBoxSize, customValueBoxPositionInfo)
  local controlTypeName = "ValueBox"
  local controlName = slider.Name.."."..controlTypeName
  local text = nil -- Specifies the text for the label of the TextBox, not the text of the TextBox.
  local tooltipTitleText = nil
  local tooltipText = nil
  local isNumeric = true
  local isMultiLine = false
  local delimiterInfo = nil
  local customFontInfo = nil
  local customTextColor = nil
  local onTextChangedHandler = function(self)
    EasyOptions:Slider_ValueBox_OnTextChangedHandler(self)
  end
  local onTextAcceptedHandler = function(self)
    EasyOptions:Slider_ValueBox_OnTextAcceptedHandler(self)
  end
  local onEscapePressedHandler = function(self)
    EasyOptions:Slider_ValueBox_OnEscapePressedHandler(self)
    -- EasyOptions:OptionTextBox_OnEscapePressedHandler(self)
  end

  local offsetX = 0
  local offsetY = 2
  local positionInfoDefault = {"TOP", "BOTTOM", offsetX, -offsetY}
  local positionInfo = EasyOptions:GetPositionInfoFromOptionPositionInfo(positionInfoDefault, customValueBoxPositionInfo, false)
  local control, width, height = EasyOptions:CreateTextBox(parent, controlName, value, minValue, maxValue, formatString, text, tooltipTitleText, tooltipText, positionInfo, customValueBoxSize, isNumeric, isMultiLine, delimiterInfo, customFontInfo, customTextColor, onTextChangedHandler, onTextAcceptedHandler, onEscapePressedHandler)
  control:ClearAllPoints()
  control:SetPoint(positionInfo[1], slider, positionInfo[2], positionInfo[3], positionInfo[4]) -- NOTE: We offset the x-position of this control type to help it align better with the other controls.
  control:SetFrameLevel(slider:GetFrameLevel() + 1) -- Set the z-order of the ValueBox so it is in front of the Slider in order to prevent the active region of the Slider from covering a significant portion of the ValueBox which can cause mouse clicks to be handled by the Slider rather than the ValueBox even if the mouse cursor is over the ValueBox.
  
  control:SetJustifyH("CENTER") -- "LEFT", "RIGHT", "CENTER"
  control:SetJustifyV("MIDDLE") -- "TOP", "BOTTOM", "MIDDLE"
  control:SetTextInsets(-4, 0, 0, 0) -- Left, Right, Top, Bottom. Defaults are 0, 0, 0, 0 -- Offset the text so the text appears in the middle of the control.
  
  control.Slider = slider
  slider.ValueBox = control
  control.AllowSetOptionValue = false -- Only update Options when the value of the parent control changes.
  EasyOptions:AddControlToOwner(control, slider)

  local controlRegionHeight = height + offsetY -- NOTE: We don't use control:GetHeight() because some controls don't implement that method and most controls that support that method return a value that is larger than desired.
  return control, controlRegionHeight
end
function EasyOptions:Slider_OnValueChangedHandler(control)
  local value = control:GetValue()
  if (control.ValueBox ~= nil) then
    control.ValueBox:SetValue(value) -- IMPORTANT: We must update the value of control.ValueBox even if control.ValueBox has the same value as the Slider in case this event was fired due to the option being reset to its default value in which case the value of the slider would be set to the value of AddonDB[optionName] (after AddonDB[optionName] was set to its default value), but the value of control.ValueBox would still have the previous value of AddonDB[optionName] until the value of control.ValueBox is updated in this method.
  end

  -- Update Options (if required).
  if (not EasyOptions.Current.IsBuildingOptionFrame) then
    local allowUpdateControl = false
    EasyOptions:SetOptionValueFromControlInfo(control, value, allowUpdateControl)
  end
end
function EasyOptions:Slider_ValueBox_OnTextChangedHandler(control)
  -- Reserved.
end
function EasyOptions:Slider_ValueBox_OnTextAcceptedHandler(control)
  local optionItem = control.OptionItem
  local addonDB = nil -- init
  local optionName = nil -- init
  if (optionItem ~= nil) then
    addonDB = optionItem.AddonDB
    optionName = optionItem.Name
  end
  --
  local slider = control.Slider

  local alternateValue
  if (addonDB == nil) or (optionName == nil) then
    alternateValue = slider:GetValue()
  else
    alternateValue = addonDB[optionName] -- Use the current value in Options as the alternate value to use if the TextBox does not represent a numeric value.
  end
  local value = EasyOptions:GetTextBoxValueFromText(control, alternateValue)
  slider:SetValue(value) -- Set the value of the slider.
end
function EasyOptions:Slider_ValueBox_OnEscapePressedHandler(control)
  local slider = control.Slider
  local value = slider:GetValue()
  control:SetValue(value)
end
function EasyOptions:CreateOptionSlider(parent, positionInfo, optionItem)
  local optionName = optionItem.Name
  local value = EasyOptions:GetOptionValueOrDefaultValue(optionName, optionItem.DefaultValue)
  local minValue = optionItem.MinValue
  local maxValue = optionItem.MaxValue
  local valueStep = optionItem.ValueStep
  local formatString = optionItem.FormatString
  local customLabelPositionInfo = optionItem.LabelPositionInfo
  local customSize = optionItem.Width
  local customValueBoxSize = optionItem.ValueBoxWidth
  local customValueBoxPositionInfo = optionItem.ValueBoxPositionInfo
  local customFontInfo = optionItem.FontInfo
  local customTextColor = optionItem.TextColor
  local text = EasyOptions:GetControlText(optionItem)
  local tooltipTitleText = optionItem.TooltipTitleText or text
  local tooltipText = optionItem.TooltipText
  local onValueChangedHandlerCustom = optionItem.OnValueChangedHandler
  local onValueChangedHandler = function(self)
    EasyOptions:OptionSlider_OnValueChangedHandler(self)
    if (onValueChangedHandlerCustom ~= nil) then
      onValueChangedHandlerCustom(self)
    end
  end
  
  local control, valueBox, controlRegionWidth, controlRegionHeight = EasyOptions:CreateSlider(parent, nil, value, minValue, maxValue, valueStep, formatString, text, tooltipTitleText, tooltipText, positionInfo, customLabelPositionInfo, customSize, customValueBoxSize, customValueBoxPositionInfo, customFontInfo, customTextColor, onValueChangedHandler)
  EasyOptions:AddRightButtonDownHandlerForOptionControl(control)
  EasyOptions:AddRightButtonDownHandlerForOptionControl(control.ValueBox)
  
  optionItem.Control = control
  control.OptionItem = optionItem
  control.ValueBox.OptionItem = optionItem
  if (optionName ~= nil) and (optionName ~= "") then
    EasyOptions.Current.OptionControls[optionName] = control
  end

  return control, controlRegionWidth, controlRegionHeight
end
function EasyOptions:OptionSlider_OnValueChangedHandler(control)
  -- Reserved.
  --  See also EasyOptions:Slider_OnValueChangedHandler.
end
