-- @docclass
UIScrollArea = extends(UIWidget, "UIScrollArea")

-- public functions
function UIScrollArea.create()
  local scrollarea = UIScrollArea.internalCreate()
  scrollarea:setClipping(true)
  scrollarea.inverted = false
  scrollarea.alwaysScrollMaximum = false
  return scrollarea
end

function waitForScrollBar(widget, id, setScrollFn, attempts)
  attempts = attempts or 30
  if attempts <= 0 then
    print("Error: Scrollbar '" .. id .. "' not found after retries.")
    return
  end

  local parent = widget:getParent()
  if not parent then
    --print("Error: Widget has no parent.")
    return
  end

  local scrollbar = parent:getChildById(id:trim())
  if scrollbar then
    setScrollFn(widget, scrollbar)
    --print("Debug: Found scrollbar:", scrollbar, "ID:", id)
  else
    scheduleEvent(function()
      waitForScrollBar(widget, id, setScrollFn, attempts - 1)
    end, 100) -- reintenta cada 100ms
  end
end


function UIScrollArea:onStyleApply(styleName, styleNode)
  for name, value in pairs(styleNode) do
    if name == 'vertical-scrollbar' then
      waitForScrollBar(self, value, function(widget, scrollbar)
        widget:setVerticalScrollBar(scrollbar)
      end)
    elseif name == 'horizontal-scrollbar' then
      waitForScrollBar(self, value, function(widget, scrollbar)
        widget:setHorizontalScrollBar(scrollbar)
      end)
    elseif name == 'inverted-scroll' then
      self:setInverted(value)
    elseif name == 'always-scroll-maximum' then
      self:setAlwaysScrollMaximum(value)
    end
  end
end



function UIScrollArea:updateScrollBars()
  local scrollWidth = math.max(self:getChildrenRect().width - self:getPaddingRect().width, 0)
  local scrollHeight = math.max(self:getChildrenRect().height - self:getPaddingRect().height, 0)

  local scrollbar = self.verticalScrollBar
  if scrollbar then
    if self.inverted then
      scrollbar:setMinimum(-scrollHeight)
      scrollbar:setMaximum(0)
    else
      scrollbar:setMinimum(0)
      scrollbar:setMaximum(scrollHeight)
    end
  end

  local scrollbar = self.horizontalScrollBar
  if scrollbar then
    if self.inverted then
      scrollbar:setMinimum(-scrollWidth)
      scrollbar:setMaximum(0)
    else
      scrollbar:setMinimum(0)
      scrollbar:setMaximum(scrollWidth)
    end
  end

  if self.lastScrollWidth ~= scrollWidth then
    self:onScrollWidthChange()
  end
  if self.lastScrollHeight ~= scrollHeight then
    self:onScrollHeightChange()
  end

  self.lastScrollWidth = scrollWidth
  self.lastScrollHeight = scrollHeight
end

function UIScrollArea:setVerticalScrollBar(scrollbar)
  if not scrollbar then
    print("Warning: Tried to set a nil scrollbar, ignoring.")

    return
  end

  self.verticalScrollBar = scrollbar

  connect(self.verticalScrollBar, 'onValueChange', function(scrollbar, value)
    local virtualOffset = self:getVirtualOffset()
    virtualOffset.y = value
    self:setVirtualOffset(virtualOffset)
    signalcall(self.onScrollChange, self, virtualOffset)
  end)

  self:updateScrollBars()
end


function UIScrollArea:setHorizontalScrollBar(scrollbar)
  self.horizontalScrollBar = scrollbar
  connect(self.horizontalScrollBar, 'onValueChange', function(scrollbar, value)
    local virtualOffset = self:getVirtualOffset()
    virtualOffset.x = value
    self:setVirtualOffset(virtualOffset)
    signalcall(self.onScrollChange, self, virtualOffset)
  end)
  self:updateScrollBars()
end

function UIScrollArea:setInverted(inverted)
  self.inverted = inverted
end

function UIScrollArea:setAlwaysScrollMaximum(value)
  self.alwaysScrollMaximum = value
end

function UIScrollArea:onLayoutUpdate()
  self:updateScrollBars()
end

function UIScrollArea:onMouseWheel(mousePos, mouseWheel)
  if self.verticalScrollBar then
    if not self.verticalScrollBar:isOn() then
      return false
    end
    if mouseWheel == MouseWheelUp then
      local minimum = self.verticalScrollBar:getMinimum()
      if self.verticalScrollBar:getValue() <= minimum then
        return false
      end
      self.verticalScrollBar:decrement()
    else
      local maximum = self.verticalScrollBar:getMaximum()
      if self.verticalScrollBar:getValue() >= maximum then
        return false
      end
      self.verticalScrollBar:increment()
    end
  elseif self.horizontalScrollBar then
    if not self.horizontalScrollBar:isOn() then
      return false
    end
    if mouseWheel == MouseWheelUp then
      local maximum = self.horizontalScrollBar:getMaximum()
      if self.horizontalScrollBar:getValue() >= maximum then
        return false
      end
      self.horizontalScrollBar:increment()
    else
      local minimum = self.horizontalScrollBar:getMinimum()
      if self.horizontalScrollBar:getValue() <= minimum then
        return false
      end
      self.horizontalScrollBar:decrement()
    end
  end
  return true
end

function UIScrollArea:ensureChildVisible(child, offset)
  if child then
    local paddingRect = self:getPaddingRect()
    if not offset then
      offset = {x = 0, y = 0}
    end
    if self.verticalScrollBar then
      local deltaY = paddingRect.y - child:getY()
      if deltaY > 0 then
        self.verticalScrollBar:decrement(deltaY)
      end

      deltaY = (child:getY() + child:getHeight() + offset.y) - (paddingRect.y + paddingRect.height)
      if deltaY > 0 then
        self.verticalScrollBar:increment(deltaY)
      end
    elseif self.horizontalScrollBar then
      local deltaX = paddingRect.x - child:getX()
      if deltaX > 0 then
        self.horizontalScrollBar:decrement(deltaX)
      end

      deltaX = (child:getX() + child:getWidth() + offset.x) - (paddingRect.x + paddingRect.width)
      if deltaX > 0 then
        self.horizontalScrollBar:increment(deltaX)
      end
    end
  end
end

function UIScrollArea:onChildFocusChange(focusedChild, oldFocused, reason)
  if focusedChild and (reason == MouseFocusReason or reason == KeyboardFocusReason) then
    self:ensureChildVisible(focusedChild)
  end
end

function UIScrollArea:onScrollWidthChange()
  if self.alwaysScrollMaximum and self.horizontalScrollBar then
    self.horizontalScrollBar:setValue(self.horizontalScrollBar:getMaximum())
  end
end

function UIScrollArea:onScrollHeightChange()
  if self.alwaysScrollMaximum and self.verticalScrollBar then
    self.verticalScrollBar:setValue(self.verticalScrollBar:getMaximum())
  end
end
