---@class LayoutEngine
---@field element Element? Reference to the parent element
---@field positioning Positioning Layout positioning mode
---@field flexDirection FlexDirection Direction of flex layout
---@field justifyContent JustifyContent Alignment of items along main axis
---@field alignItems AlignItems Alignment of items along cross axis
---@field alignContent AlignContent Alignment of lines in multi-line flex containers
---@field flexWrap FlexWrap Whether children wrap to multiple lines
---@field gap number Space between children elements
---@field gridRows number? Number of rows in the grid
---@field gridColumns number? Number of columns in the grid
---@field columnGap number? Gap between grid columns
---@field rowGap number? Gap between grid rows
---@field _Grid table
---@field _Units table
---@field _Context table
---@field _Positioning table
---@field _FlexDirection table
---@field _JustifyContent table
---@field _AlignContent table
---@field _AlignItems table
---@field _AlignSelf table
---@field _FlexWrap table
---@field _layoutCount number Track layout recalculations per frame
---@field _lastFrameCount number Last frame number for resetting counters
---@field _ErrorHandler ErrorHandler? ErrorHandler module dependency
---@field _Performance Performance? Performance module dependency
---@field _FFI table? FFI module dependency
---@field _useFFI boolean Whether to use FFI optimizations
local LayoutEngine = {}
LayoutEngine.__index = LayoutEngine

--- Initialize module with shared dependencies
---@param deps table Dependencies {ErrorHandler, Performance, FFI}
function LayoutEngine.init(deps)
  LayoutEngine._ErrorHandler = deps.ErrorHandler
  LayoutEngine._Performance = deps.Performance
  LayoutEngine._FFI = deps.FFI
  LayoutEngine._useFFI = deps.FFI and deps.FFI.enabled or false
end

---@class LayoutEngineProps
---@field positioning Positioning? Layout positioning mode (default: RELATIVE)
---@field flexDirection FlexDirection? Direction of flex layout (default: HORIZONTAL)
---@field justifyContent JustifyContent? Alignment of items along main axis (default: FLEX_START)
---@field alignItems AlignItems? Alignment of items along cross axis (default: STRETCH)
---@field alignContent AlignContent? Alignment of lines in multi-line flex containers (default: STRETCH)
---@field flexWrap FlexWrap? Whether children wrap to multiple lines (default: NOWRAP)
---@field gap number? Space between children elements (default: 10)
---@field gridRows number? Number of rows in the grid
---@field gridColumns number? Number of columns in the grid
---@field columnGap number? Gap between grid columns
---@field rowGap number? Gap between grid rows

--- Create a new LayoutEngine instance
---@param props LayoutEngineProps
---@param deps table Dependencies {utils, Grid, Units, Context}
---@return LayoutEngine
function LayoutEngine.new(props, deps)
  local enums = deps.utils.enums
  local Positioning = enums.Positioning
  local FlexDirection = enums.FlexDirection
  local JustifyContent = enums.JustifyContent
  local AlignContent = enums.AlignContent
  local AlignItems = enums.AlignItems
  local AlignSelf = enums.AlignSelf
  local FlexWrap = enums.FlexWrap

  local self = setmetatable({}, LayoutEngine)

  -- Store dependencies for instance methods
  self._Grid = deps.Grid
  self._Units = deps.Units
  self._Context = deps.Context
  self._ErrorHandler = deps.ErrorHandler
  self._Positioning = Positioning
  self._FlexDirection = FlexDirection
  self._JustifyContent = JustifyContent
  self._AlignContent = AlignContent
  self._AlignItems = AlignItems
  self._AlignSelf = AlignSelf
  self._FlexWrap = FlexWrap

  -- Layout configuration
  self.positioning = props.positioning or Positioning.FLEX
  self.flexDirection = props.flexDirection or FlexDirection.HORIZONTAL
  self.justifyContent = props.justifyContent or JustifyContent.FLEX_START
  self.alignItems = props.alignItems or AlignItems.STRETCH
  self.alignContent = props.alignContent or AlignContent.STRETCH
  self.flexWrap = props.flexWrap or FlexWrap.NOWRAP
  self.gap = props.gap or 10

  -- Grid layout configuration
  self.gridRows = props.gridRows
  self.gridColumns = props.gridColumns
  self.columnGap = props.columnGap
  self.rowGap = props.rowGap

  -- Element reference (will be set via initialize)
  self.element = nil

  -- Performance tracking
  self._layoutCount = 0
  self._lastFrameCount = 0

  -- Layout memoization cache
  self._layoutCache = {
    childrenCount = 0,
    containerWidth = 0,
    containerHeight = 0,
    childrenHash = "",
  }

  return self
end

--- Initialize the LayoutEngine with its parent element
---@param element Element The parent element
function LayoutEngine:initialize(element)
  self.element = element
end

--- Apply CSS positioning offsets (top, right, bottom, left) to a child element
---@param child Element The element to apply offsets to
function LayoutEngine:applyPositioningOffsets(child)
  if not child then
    return
  end

  -- For CSS-style positioning, we need the parent's bounds
  local parent = child.parent
  if not parent then
    return
  end

  -- Only apply offsets to explicitly absolute children or children in relative/absolute containers
  -- Flex/grid children ignore positioning offsets as they participate in layout
  local isFlexChild = child.positioning == self._Positioning.FLEX
    or child.positioning == self._Positioning.GRID
    or (child.positioning == self._Positioning.ABSOLUTE and not child._explicitlyAbsolute)

  if not isFlexChild then
    -- Apply absolute positioning for explicitly absolute children
    -- Apply top offset (distance from parent's content box top edge)
    if child.top then
      child.y = parent.y + parent.padding.top + child.top
    end

    -- Apply bottom offset (distance from parent's content box bottom edge)
    -- BORDER-BOX MODEL: Use border-box dimensions for positioning
    if child.bottom then
      local elementBorderBoxHeight = child:getBorderBoxHeight()
      child.y = parent.y + parent.padding.top + parent.height - child.bottom - elementBorderBoxHeight
    end

    -- Apply left offset (distance from parent's content box left edge)
    if child.left then
      child.x = parent.x + parent.padding.left + child.left
    end

    -- Apply right offset (distance from parent's content box right edge)
    -- BORDER-BOX MODEL: Use border-box dimensions for positioning
    if child.right then
      local elementBorderBoxWidth = child:getBorderBoxWidth()
      child.x = parent.x + parent.padding.left + parent.width - child.right - elementBorderBoxWidth
    end
  end
end

--- Batch calculate child positions using FFI (optimization for large child counts)
---@param children table Array of child elements
---@param startX number Starting X position
---@param startY number Starting Y position
---@param spacing number Spacing between children
---@param isHorizontal boolean True if horizontal layout
---@return table positions Array of {x, y} positions
function LayoutEngine:_batchCalculatePositions(children, startX, startY, spacing, isHorizontal)
  local count = #children
  
  -- Use FFI for batch calculations if available and count is large enough
  if LayoutEngine._useFFI and LayoutEngine._FFI and count > 10 then
    local positions = LayoutEngine._FFI:allocateVec2Array(count)
    local currentPos = isHorizontal and startX or startY
    
    for i = 0, count - 1 do
      local child = children[i + 1] -- Lua is 1-indexed
      
      if isHorizontal then
        positions[i].x = currentPos + child.margin.left
        positions[i].y = startY + child.margin.top
        currentPos = currentPos + child:getBorderBoxWidth() + child.margin.left + child.margin.right + spacing
      else
        positions[i].x = startX + child.margin.left
        positions[i].y = currentPos + child.margin.top
        currentPos = currentPos + child:getBorderBoxHeight() + child.margin.top + child.margin.bottom + spacing
      end
    end
    
    return positions
  end
  
  -- Fallback to Lua table
  local positions = {}
  local currentPos = isHorizontal and startX or startY
  
  for i, child in ipairs(children) do
    if isHorizontal then
      positions[i] = {
        x = currentPos + child.margin.left,
        y = startY + child.margin.top
      }
      currentPos = currentPos + child:getBorderBoxWidth() + child.margin.left + child.margin.right + spacing
    else
      positions[i] = {
        x = startX + child.margin.left,
        y = currentPos + child.margin.top
      }
      currentPos = currentPos + child:getBorderBoxHeight() + child.margin.top + child.margin.bottom + spacing
    end
  end
  
  return positions
end

--- Layout children within this element according to positioning mode
function LayoutEngine:layoutChildren()
  -- Start performance timing first (before any early returns)
  local timerName = nil
  if LayoutEngine._Performance and LayoutEngine._Performance.enabled and self.element then
    -- Use memory address to make timer name unique per element instance
    timerName = "layout_" .. (self.element.id or tostring(self.element):match("0x%x+") or "unknown")
    LayoutEngine._Performance:startTimer(timerName)
  end

  if self.element == nil then
    return
  end

  -- Check if layout can be skipped (memoization optimization)
  if self:_canSkipLayout() then
    if timerName and LayoutEngine._Performance then
      LayoutEngine._Performance:stopTimer(timerName)
    end
    return
  end

  -- Track layout recalculations for performance warnings
  self:_trackLayoutRecalculation()

  if self.positioning == self._Positioning.ABSOLUTE or self.positioning == self._Positioning.RELATIVE then
    -- Absolute/Relative positioned containers don't layout their children according to flex rules,
    -- but they should still apply CSS positioning offsets to their children
    for _, child in ipairs(self.element.children) do
      if child.top or child.right or child.bottom or child.left then
        self:applyPositioningOffsets(child)
      end
    end

    -- Detect overflow after children positioning
    if self.element._detectOverflow then
      self.element:_detectOverflow()
    end

    -- Stop performance timing
    if timerName and LayoutEngine._Performance then
      LayoutEngine._Performance:stopTimer(timerName)
    end
    return
  end

  -- Handle grid layout
  if self.positioning == self._Positioning.GRID then
    self._Grid.layoutGridItems(self.element)

    -- Stop performance timing
    if timerName and LayoutEngine._Performance then
      LayoutEngine._Performance:stopTimer(timerName)
    end
    return
  end

  local childCount = #self.element.children

  if childCount == 0 then
    -- Stop performance timing
    if timerName and LayoutEngine._Performance then
      LayoutEngine._Performance:stopTimer(timerName)
    end
    return
  end

  -- Get flex children (children that participate in flex layout)
  local flexChildren = {}
  for _, child in ipairs(self.element.children) do
    local isFlexChild = not (child.positioning == self._Positioning.ABSOLUTE and child._explicitlyAbsolute)
    if isFlexChild then
      table.insert(flexChildren, child)

      -- Warn if child uses percentage sizing but parent has autosizing
      if child.units and child.units.width then
        if child.units.width.unit == "%" and self.element.autosizing and self.element.autosizing.width then
          LayoutEngine._ErrorHandler:warn("LayoutEngine", "LAY_004", {
            child = child.id or "unnamed",
            issue = "percentage width with parent auto-sizing",
          })
        end
      end
      if child.units and child.units.height then
        if child.units.height.unit == "%" and self.element.autosizing and self.element.autosizing.height then
          LayoutEngine._ErrorHandler:warn("LayoutEngine", "LAY_004", {
            child = child.id or "unnamed",
            issue = "percentage height with parent auto-sizing",
          })
        end
      end
    end
  end

  if #flexChildren == 0 then
    return
  end

  -- Calculate space reserved by absolutely positioned siblings with explicit positioning
  local reservedMainStart = 0 -- Space reserved at the start of main axis (left for horizontal, top for vertical)
  local reservedMainEnd = 0 -- Space reserved at the end of main axis (right for horizontal, bottom for vertical)
  local reservedCrossStart = 0 -- Space reserved at the start of cross axis (top for horizontal, left for vertical)
  local reservedCrossEnd = 0 -- Space reserved at the end of cross axis (bottom for horizontal, right for vertical)

  for _, child in ipairs(self.element.children) do
    -- Only consider absolutely positioned children with explicit positioning
    if child.positioning == self._Positioning.ABSOLUTE and child._explicitlyAbsolute then
      -- BORDER-BOX MODEL: Use border-box dimensions for space calculations
      local childBorderBoxWidth = child:getBorderBoxWidth()
      local childBorderBoxHeight = child:getBorderBoxHeight()

      if self.flexDirection == self._FlexDirection.HORIZONTAL then
        -- Horizontal layout: main axis is X, cross axis is Y
        -- Check for left positioning (reserves space at main axis start)
        if child.left then
          local spaceNeeded = child.left + childBorderBoxWidth
          reservedMainStart = math.max(reservedMainStart, spaceNeeded)
        end
        -- Check for right positioning (reserves space at main axis end)
        if child.right then
          local spaceNeeded = child.right + childBorderBoxWidth
          reservedMainEnd = math.max(reservedMainEnd, spaceNeeded)
        end
        -- Check for top positioning (reserves space at cross axis start)
        if child.top then
          local spaceNeeded = child.top + childBorderBoxHeight
          reservedCrossStart = math.max(reservedCrossStart, spaceNeeded)
        end
        -- Check for bottom positioning (reserves space at cross axis end)
        if child.bottom then
          local spaceNeeded = child.bottom + childBorderBoxHeight
          reservedCrossEnd = math.max(reservedCrossEnd, spaceNeeded)
        end
      else
        -- Vertical layout: main axis is Y, cross axis is X
        -- Check for top positioning (reserves space at main axis start)
        if child.top then
          local spaceNeeded = child.top + childBorderBoxHeight
          reservedMainStart = math.max(reservedMainStart, spaceNeeded)
        end
        -- Check for bottom positioning (reserves space at main axis end)
        if child.bottom then
          local spaceNeeded = child.bottom + childBorderBoxHeight
          reservedMainEnd = math.max(reservedMainEnd, spaceNeeded)
        end
        -- Check for left positioning (reserves space at cross axis start)
        if child.left then
          local spaceNeeded = child.left + childBorderBoxWidth
          reservedCrossStart = math.max(reservedCrossStart, spaceNeeded)
        end
        -- Check for right positioning (reserves space at cross axis end)
        if child.right then
          local spaceNeeded = child.right + childBorderBoxWidth
          reservedCrossEnd = math.max(reservedCrossEnd, spaceNeeded)
        end
      end
    end
  end

  -- Calculate available space (accounting for padding and reserved space)
  -- BORDER-BOX MODEL: element.width and element.height are already content dimensions (padding subtracted)
  local availableMainSize = 0
  local availableCrossSize = 0
  if self.flexDirection == self._FlexDirection.HORIZONTAL then
    availableMainSize = self.element.width - reservedMainStart - reservedMainEnd
    availableCrossSize = self.element.height - reservedCrossStart - reservedCrossEnd
  else
    availableMainSize = self.element.height - reservedMainStart - reservedMainEnd
    availableCrossSize = self.element.width - reservedCrossStart - reservedCrossEnd
  end

  -- Handle flex wrap: create lines of children
  local lines = {}

  if self.flexWrap == self._FlexWrap.NOWRAP then
    -- All children go on one line
    lines[1] = flexChildren
  else
    -- Wrap children into multiple lines
    local currentLine = {}
    local currentLineSize = 0

    for _, child in ipairs(flexChildren) do
      -- BORDER-BOX MODEL: Use border-box dimensions for layout calculations
      -- Include margins in size calculations
      local childMainSize = 0
      local childMainMargin = 0
      if self.flexDirection == self._FlexDirection.HORIZONTAL then
        childMainSize = child:getBorderBoxWidth()
        childMainMargin = child.margin.left + child.margin.right
      else
        childMainSize = child:getBorderBoxHeight()
        childMainMargin = child.margin.top + child.margin.bottom
      end
      local childTotalMainSize = childMainSize + childMainMargin

      -- Check if adding this child would exceed the available space
      local lineSpacing = #currentLine > 0 and self.gap or 0
      if #currentLine > 0 and currentLineSize + lineSpacing + childTotalMainSize > availableMainSize then
        -- Start a new line
        if #currentLine > 0 then
          table.insert(lines, currentLine)
        end
        currentLine = { child }
        currentLineSize = childTotalMainSize
      else
        -- Add to current line
        table.insert(currentLine, child)
        currentLineSize = currentLineSize + lineSpacing + childTotalMainSize
      end
    end

    -- Add the last line if it has children
    if #currentLine > 0 then
      table.insert(lines, currentLine)
    end

    -- Handle wrap-reverse: reverse the order of lines
    if self.flexWrap == self._FlexWrap.WRAP_REVERSE then
      local reversedLines = {}
      for i = #lines, 1, -1 do
        table.insert(reversedLines, lines[i])
      end
      lines = reversedLines
    end
  end

  -- Calculate line positions and heights (including child padding)
  local lineHeights = {}
  local totalLinesHeight = 0

  for lineIndex, line in ipairs(lines) do
    local maxCrossSize = 0
    for _, child in ipairs(line) do
      -- BORDER-BOX MODEL: Use border-box dimensions for layout calculations
      -- Include margins in cross-axis size calculations
      local childCrossSize = 0
      local childCrossMargin = 0
      if self.flexDirection == self._FlexDirection.HORIZONTAL then
        childCrossSize = child:getBorderBoxHeight()
        childCrossMargin = child.margin.top + child.margin.bottom
      else
        childCrossSize = child:getBorderBoxWidth()
        childCrossMargin = child.margin.left + child.margin.right
      end
      local childTotalCrossSize = childCrossSize + childCrossMargin
      maxCrossSize = math.max(maxCrossSize, childTotalCrossSize)
    end
    lineHeights[lineIndex] = maxCrossSize
    totalLinesHeight = totalLinesHeight + maxCrossSize
  end

  -- Account for gaps between lines
  local lineGaps = math.max(0, #lines - 1) * self.gap
  totalLinesHeight = totalLinesHeight + lineGaps

  -- For single line layouts, CENTER, FLEX_END and STRETCH should use full cross size
  if #lines == 1 then
    if self.alignItems == self._AlignItems.STRETCH or self.alignItems == self._AlignItems.CENTER or self.alignItems == self._AlignItems.FLEX_END then
      -- STRETCH, CENTER, and FLEX_END should use full available cross size
      lineHeights[1] = availableCrossSize
      totalLinesHeight = availableCrossSize
    end
    -- CENTER and FLEX_END should preserve natural child dimensions
    -- and only affect positioning within the available space
  end

  -- Calculate starting position for lines based on alignContent
  local lineStartPos = 0
  local lineSpacing = self.gap
  local freeLineSpace = availableCrossSize - totalLinesHeight

  -- Apply AlignContent logic for both single and multiple lines
  if self.alignContent == self._AlignContent.FLEX_START then
    lineStartPos = 0
  elseif self.alignContent == self._AlignContent.CENTER then
    lineStartPos = freeLineSpace / 2
  elseif self.alignContent == self._AlignContent.FLEX_END then
    lineStartPos = freeLineSpace
  elseif self.alignContent == self._AlignContent.SPACE_BETWEEN then
    lineStartPos = 0
    if #lines > 1 then
      lineSpacing = self.gap + (freeLineSpace / (#lines - 1))
    end
  elseif self.alignContent == self._AlignContent.SPACE_AROUND then
    local spaceAroundEach = freeLineSpace / #lines
    lineStartPos = spaceAroundEach / 2
    lineSpacing = self.gap + spaceAroundEach
  elseif self.alignContent == self._AlignContent.STRETCH then
    lineStartPos = 0
    if #lines > 1 and freeLineSpace > 0 then
      lineSpacing = self.gap + (freeLineSpace / #lines)
      -- Distribute extra space to line heights (only if positive)
      local extraPerLine = freeLineSpace / #lines
      for i = 1, #lineHeights do
        lineHeights[i] = lineHeights[i] + extraPerLine
      end
    end
  end

  -- Position children within each line
  local currentCrossPos = lineStartPos

  for lineIndex, line in ipairs(lines) do
    local lineHeight = lineHeights[lineIndex]

    -- Calculate total size of children in this line (including padding and margins)
    -- BORDER-BOX MODEL: Use border-box dimensions for layout calculations
    local totalChildrenSize = 0
    for _, child in ipairs(line) do
      if self.flexDirection == self._FlexDirection.HORIZONTAL then
        totalChildrenSize = totalChildrenSize + child:getBorderBoxWidth() + child.margin.left + child.margin.right
      else
        totalChildrenSize = totalChildrenSize + child:getBorderBoxHeight() + child.margin.top + child.margin.bottom
      end
    end

    local totalGapSize = math.max(0, #line - 1) * self.gap
    local totalContentSize = totalChildrenSize + totalGapSize
    local freeSpace = availableMainSize - totalContentSize

    -- Calculate initial position and spacing based on justifyContent
    local startPos = 0
    local itemSpacing = self.gap

    if self.justifyContent == self._JustifyContent.FLEX_START then
      startPos = 0
    elseif self.justifyContent == self._JustifyContent.CENTER then
      startPos = freeSpace / 2
    elseif self.justifyContent == self._JustifyContent.FLEX_END then
      startPos = freeSpace
    elseif self.justifyContent == self._JustifyContent.SPACE_BETWEEN then
      startPos = 0
      if #line > 1 then
        itemSpacing = self.gap + (freeSpace / (#line - 1))
      end
    elseif self.justifyContent == self._JustifyContent.SPACE_AROUND then
      local spaceAroundEach = freeSpace / #line
      startPos = spaceAroundEach / 2
      itemSpacing = self.gap + spaceAroundEach
    elseif self.justifyContent == self._JustifyContent.SPACE_EVENLY then
      local spaceBetween = freeSpace / (#line + 1)
      startPos = spaceBetween
      itemSpacing = self.gap + spaceBetween
    end

    -- Position children in this line
    local currentMainPos = startPos

    for _, child in ipairs(line) do
      -- Determine effective cross-axis alignment
      local effectiveAlign = child.alignSelf
      if effectiveAlign == nil or effectiveAlign == self._AlignSelf.AUTO then
        effectiveAlign = self.alignItems
      end

      if self.flexDirection == self._FlexDirection.HORIZONTAL then
        -- Horizontal layout: main axis is X, cross axis is Y
        -- Position child at border box (x, y represents top-left including padding)
        -- Add reservedMainStart and left margin to account for absolutely positioned siblings and margins
        child.x = self.element.x + self.element.padding.left + reservedMainStart + currentMainPos + child.margin.left

        -- BORDER-BOX MODEL: Use border-box dimensions for alignment calculations
        local childBorderBoxHeight = child:getBorderBoxHeight()
        local childTotalCrossSize = childBorderBoxHeight + child.margin.top + child.margin.bottom

        if effectiveAlign == self._AlignItems.FLEX_START then
          child.y = self.element.y + self.element.padding.top + reservedCrossStart + currentCrossPos + child.margin.top
        elseif effectiveAlign == self._AlignItems.CENTER then
          child.y = self.element.y
            + self.element.padding.top
            + reservedCrossStart
            + currentCrossPos
            + ((lineHeight - childTotalCrossSize) / 2)
            + child.margin.top
        elseif effectiveAlign == self._AlignItems.FLEX_END then
          child.y = self.element.y + self.element.padding.top + reservedCrossStart + currentCrossPos + lineHeight - childTotalCrossSize + child.margin.top
        elseif effectiveAlign == self._AlignItems.STRETCH then
          -- STRETCH: Only apply if height was not explicitly set
          if child.autosizing and child.autosizing.height then
            -- STRETCH: Set border-box height to lineHeight minus margins, content area shrinks to fit
            local availableHeight = lineHeight - child.margin.top - child.margin.bottom
            child._borderBoxHeight = availableHeight
            child.height = math.max(0, availableHeight - child.padding.top - child.padding.bottom)
          end
          child.y = self.element.y + self.element.padding.top + reservedCrossStart + currentCrossPos + child.margin.top
        end

        -- Apply positioning offsets (top, right, bottom, left)
        self:applyPositioningOffsets(child)

        -- If child has children, re-layout them after position change
        if #child.children > 0 then
          child:layoutChildren()
        end

        -- Advance position by child's border-box width plus margins
        currentMainPos = currentMainPos + child:getBorderBoxWidth() + child.margin.left + child.margin.right + itemSpacing
      else
        -- Vertical layout: main axis is Y, cross axis is X
        -- Position child at border box (x, y represents top-left including padding)
        -- Add reservedMainStart and top margin to account for absolutely positioned siblings and margins
        child.y = self.element.y + self.element.padding.top + reservedMainStart + currentMainPos + child.margin.top

        -- BORDER-BOX MODEL: Use border-box dimensions for alignment calculations
        local childBorderBoxWidth = child:getBorderBoxWidth()
        local childTotalCrossSize = childBorderBoxWidth + child.margin.left + child.margin.right

        if effectiveAlign == self._AlignItems.FLEX_START then
          child.x = self.element.x + self.element.padding.left + reservedCrossStart + currentCrossPos + child.margin.left
        elseif effectiveAlign == self._AlignItems.CENTER then
          child.x = self.element.x
            + self.element.padding.left
            + reservedCrossStart
            + currentCrossPos
            + ((lineHeight - childTotalCrossSize) / 2)
            + child.margin.left
        elseif effectiveAlign == self._AlignItems.FLEX_END then
          child.x = self.element.x + self.element.padding.left + reservedCrossStart + currentCrossPos + lineHeight - childTotalCrossSize + child.margin.left
        elseif effectiveAlign == self._AlignItems.STRETCH then
          -- STRETCH: Only apply if width was not explicitly set
          if child.autosizing and child.autosizing.width then
            -- STRETCH: Set border-box width to lineHeight minus margins, content area shrinks to fit
            local availableWidth = lineHeight - child.margin.left - child.margin.right
            child._borderBoxWidth = availableWidth
            child.width = math.max(0, availableWidth - child.padding.left - child.padding.right)
          end
          child.x = self.element.x + self.element.padding.left + reservedCrossStart + currentCrossPos + child.margin.left
        end

        -- Apply positioning offsets (top, right, bottom, left)
        self:applyPositioningOffsets(child)

        -- If child has children, re-layout them after position change
        if #child.children > 0 then
          child:layoutChildren()
        end

        -- Advance position by child's border-box height plus margins
        currentMainPos = currentMainPos + child:getBorderBoxHeight() + child.margin.top + child.margin.bottom + itemSpacing
      end
    end

    -- Move to next line position
    currentCrossPos = currentCrossPos + lineHeight + lineSpacing
  end

  -- Position explicitly absolute children after flex layout
  for _, child in ipairs(self.element.children) do
    if child.positioning == self._Positioning.ABSOLUTE and child._explicitlyAbsolute then
      -- Apply positioning offsets (top, right, bottom, left)
      self:applyPositioningOffsets(child)

      -- If child has children, layout them after position change
      if #child.children > 0 then
        child:layoutChildren()
      end
    end
  end

  -- Detect overflow after children are laid out
  if self.element._detectOverflow then
    self.element:_detectOverflow()
  end

  -- Stop performance timing
  if timerName and LayoutEngine._Performance then
    LayoutEngine._Performance:stopTimer(timerName)
  end
end

--- Simulate wrapping children into lines for auto-sizing calculations
---@param children table Array of child elements
---@param availableSize number Available space in main axis
---@param isHorizontal boolean True if flex direction is horizontal
---@return table Array of lines, where each line is an array of children
function LayoutEngine:_simulateWrap(children, availableSize, isHorizontal)
  local lines = {}
  local currentLine = {}
  local currentLineSize = 0

  for _, child in ipairs(children) do
    -- Calculate child size in main axis (including margins)
    local childMainSize = 0
    local childMainMargin = 0
    if isHorizontal then
      childMainSize = child:getBorderBoxWidth()
      if child.margin then
        childMainMargin = child.margin.left + child.margin.right
      end
    else
      childMainSize = child:getBorderBoxHeight()
      if child.margin then
        childMainMargin = child.margin.top + child.margin.bottom
      end
    end
    local childTotalMainSize = childMainSize + childMainMargin

    -- Check if adding this child would exceed the available space
    local lineSpacing = #currentLine > 0 and self.gap or 0
    if #currentLine > 0 and currentLineSize + lineSpacing + childTotalMainSize > availableSize then
      -- Start a new line
      table.insert(lines, currentLine)
      currentLine = { child }
      currentLineSize = childTotalMainSize
    else
      -- Add to current line
      table.insert(currentLine, child)
      currentLineSize = currentLineSize + lineSpacing + childTotalMainSize
    end
  end

  -- Add the last line if it has children
  if #currentLine > 0 then
    table.insert(lines, currentLine)
  end

  return lines
end

--- Calculate auto width based on children
---@return number
function LayoutEngine:calculateAutoWidth()
  if self.element == nil then
    return 0
  end

  -- BORDER-BOX MODEL: Calculate content width, caller will add padding to get border-box
  local contentWidth = self.element:calculateTextWidth()
  if not self.element.children or #self.element.children == 0 then
    return contentWidth
  end

  -- Get flex children (children that participate in flex layout)
  local flexChildren = {}
  for _, child in ipairs(self.element.children) do
    if not child._explicitlyAbsolute then
      table.insert(flexChildren, child)
    end
  end

  if #flexChildren == 0 then
    return contentWidth
  end

  local isHorizontal = self.flexDirection == self._FlexDirection.HORIZONTAL
  
  if isHorizontal then
    -- HORIZONTAL flex with potential wrapping
    if self.flexWrap ~= self._FlexWrap.NOWRAP and self.element.width and self.element.width > 0 then
      -- Container has explicit width and wrapping enabled - calculate based on wrapped lines
      local availableWidth = self.element.width
      local lines = self:_simulateWrap(flexChildren, availableWidth, true)
      
      -- Find the widest line
      local maxLineWidth = contentWidth
      for _, line in ipairs(lines) do
        local lineWidth = 0
        for i, child in ipairs(line) do
          local childBorderBoxWidth = child:getBorderBoxWidth()
          local childMarginH = 0
          if child.margin then
            childMarginH = child.margin.left + child.margin.right
          end
          lineWidth = lineWidth + childBorderBoxWidth + childMarginH
          if i < #line then
            lineWidth = lineWidth + self.gap
          end
        end
        maxLineWidth = math.max(maxLineWidth, lineWidth)
      end
      return maxLineWidth
    else
      -- No wrapping or no explicit width - sum all children on one line
      local totalWidth = contentWidth
      for i, child in ipairs(flexChildren) do
        local childBorderBoxWidth = child:getBorderBoxWidth()
        local childMarginH = 0
        if child.margin then
          childMarginH = child.margin.left + child.margin.right
        end
        totalWidth = totalWidth + childBorderBoxWidth + childMarginH
        if i < #flexChildren then
          totalWidth = totalWidth + self.gap
        end
      end
      return totalWidth
    end
  else
    -- VERTICAL flex - return max child width (including margins)
    local maxWidth = contentWidth
    for _, child in ipairs(flexChildren) do
      local childBorderBoxWidth = child:getBorderBoxWidth()
      local childMarginH = 0
      if child.margin then
        childMarginH = child.margin.left + child.margin.right
      end
      maxWidth = math.max(maxWidth, childBorderBoxWidth + childMarginH)
    end
    return maxWidth
  end
end

---@return number
function LayoutEngine:calculateAutoHeight()
  if self.element == nil then
    return 0
  end

  local height = self.element:calculateTextHeight()
  if not self.element.children or #self.element.children == 0 then
    return height
  end

  -- Get flex children (children that participate in flex layout)
  local flexChildren = {}
  for _, child in ipairs(self.element.children) do
    if not child._explicitlyAbsolute then
      table.insert(flexChildren, child)
    end
  end

  if #flexChildren == 0 then
    return height
  end

  local isVertical = self.flexDirection == self._FlexDirection.VERTICAL
  
  if isVertical then
    -- VERTICAL flex with potential wrapping
    if self.flexWrap ~= self._FlexWrap.NOWRAP and self.element.height and self.element.height > 0 then
      -- Container has explicit height and wrapping enabled - calculate based on wrapped lines
      local availableHeight = self.element.height
      local lines = self:_simulateWrap(flexChildren, availableHeight, false)
      
      -- Sum all line heights
      local totalLinesHeight = height
      for i, line in ipairs(lines) do
        local lineHeight = 0
        for _, child in ipairs(line) do
          local childBorderBoxHeight = child:getBorderBoxHeight()
          local childMarginV = 0
          if child.margin then
            childMarginV = child.margin.top + child.margin.bottom
          end
          lineHeight = math.max(lineHeight, childBorderBoxHeight + childMarginV)
        end
        totalLinesHeight = totalLinesHeight + lineHeight
        if i < #lines then
          totalLinesHeight = totalLinesHeight + self.gap
        end
      end
      return totalLinesHeight
    else
      -- No wrapping or no explicit height - sum all children on one line
      local totalHeight = height
      for i, child in ipairs(flexChildren) do
        local childBorderBoxHeight = child:getBorderBoxHeight()
        local childMarginV = 0
        if child.margin then
          childMarginV = child.margin.top + child.margin.bottom
        end
        totalHeight = totalHeight + childBorderBoxHeight + childMarginV
        if i < #flexChildren then
          totalHeight = totalHeight + self.gap
        end
      end
      return totalHeight
    end
  else
    -- HORIZONTAL flex with potential wrapping
    if self.flexWrap ~= self._FlexWrap.NOWRAP and self.element.width and self.element.width > 0 then
      -- Container has explicit width and wrapping enabled - calculate based on wrapped lines
      local availableWidth = self.element.width
      local lines = self:_simulateWrap(flexChildren, availableWidth, true)
      
      -- Sum all line heights (cross-axis for horizontal flex)
      local totalLinesHeight = height
      for i, line in ipairs(lines) do
        local lineHeight = 0
        for _, child in ipairs(line) do
          local childBorderBoxHeight = child:getBorderBoxHeight()
          local childMarginV = 0
          if child.margin then
            childMarginV = child.margin.top + child.margin.bottom
          end
          lineHeight = math.max(lineHeight, childBorderBoxHeight + childMarginV)
        end
        totalLinesHeight = totalLinesHeight + lineHeight
        if i < #lines then
          totalLinesHeight = totalLinesHeight + self.gap
        end
      end
      return totalLinesHeight
    else
      -- No wrapping or no explicit width - return max child height (including margins)
      local maxHeight = height
      for _, child in ipairs(flexChildren) do
        local childBorderBoxHeight = child:getBorderBoxHeight()
        local childMarginV = 0
        if child.margin then
          childMarginV = child.margin.top + child.margin.bottom
        end
        maxHeight = math.max(maxHeight, childBorderBoxHeight + childMarginV)
      end
      return maxHeight
    end
  end
end

--- Recalculate units based on new viewport dimensions (for vw, vh, % units)
---@param newViewportWidth number
---@param newViewportHeight number
function LayoutEngine:recalculateUnits(newViewportWidth, newViewportHeight)
  if self.element == nil then
    return
  end
  local Units = self._Units

  -- Get updated scale factors
  local scaleX, scaleY = self._Context.getScaleFactors()

  -- Recalculate border-box width if using viewport or percentage units (skip auto-sized)
  -- Store in _borderBoxWidth temporarily, will calculate content width after padding is resolved
  if self.element.units.width.unit ~= "px" and self.element.units.width.unit ~= "auto" then
    local parentWidth = self.element.parent and self.element.parent.width or newViewportWidth
    self.element._borderBoxWidth =
      Units.resolve(self.element.units.width.value, self.element.units.width.unit, newViewportWidth, newViewportHeight, parentWidth)
  elseif self.element.units.width.unit == "px" and self.element.units.width.value and self._Context.baseScale then
    -- Reapply base scaling to pixel widths (border-box)
    self.element._borderBoxWidth = self.element.units.width.value * scaleX
  end

  -- Recalculate border-box height if using viewport or percentage units (skip auto-sized)
  -- Store in _borderBoxHeight temporarily, will calculate content height after padding is resolved
  if self.element.units.height.unit ~= "px" and self.element.units.height.unit ~= "auto" then
    local parentHeight = self.element.parent and self.element.parent.height or newViewportHeight
    self.element._borderBoxHeight =
      Units.resolve(self.element.units.height.value, self.element.units.height.unit, newViewportWidth, newViewportHeight, parentHeight)
  elseif self.element.units.height.unit == "px" and self.element.units.height.value and self._Context.baseScale then
    -- Reapply base scaling to pixel heights (border-box)
    self.element._borderBoxHeight = self.element.units.height.value * scaleY
  end

  -- Recalculate position if using viewport or percentage units
  if self.element.units.x.unit ~= "px" then
    local parentWidth = self.element.parent and self.element.parent.width or newViewportWidth
    local baseX = self.element.parent and self.element.parent.x or 0
    local offsetX = Units.resolve(self.element.units.x.value, self.element.units.x.unit, newViewportWidth, newViewportHeight, parentWidth)
    self.element.x = baseX + offsetX
  else
    -- For pixel units, update position relative to parent's new position (with base scaling)
    if self.element.parent then
      local baseX = self.element.parent.x
      local scaledOffset = self._Context.baseScale and (self.element.units.x.value * scaleX) or self.element.units.x.value
      self.element.x = baseX + scaledOffset
    elseif self._Context.baseScale then
      -- Top-level element with pixel position - apply base scaling
      self.element.x = self.element.units.x.value * scaleX
    end
  end

  if self.element.units.y.unit ~= "px" then
    local parentHeight = self.element.parent and self.element.parent.height or newViewportHeight
    local baseY = self.element.parent and self.element.parent.y or 0
    local offsetY = Units.resolve(self.element.units.y.value, self.element.units.y.unit, newViewportWidth, newViewportHeight, parentHeight)
    self.element.y = baseY + offsetY
  else
    -- For pixel units, update position relative to parent's new position (with base scaling)
    if self.element.parent then
      local baseY = self.element.parent.y
      local scaledOffset = self._Context.baseScale and (self.element.units.y.value * scaleY) or self.element.units.y.value
      self.element.y = baseY + scaledOffset
    elseif self._Context.baseScale then
      -- Top-level element with pixel position - apply base scaling
      self.element.y = self.element.units.y.value * scaleY
    end
  end

  -- Recalculate textSize if auto-scaling is enabled or using viewport/element-relative units
  if self.element.autoScaleText and self.element.units.textSize.value then
    local unit = self.element.units.textSize.unit
    local value = self.element.units.textSize.value

    if unit == "px" and self._Context.baseScale then
      -- With base scaling: scale pixel values relative to base resolution
      self.element.textSize = value * scaleY
    elseif unit == "px" then
      -- Without base scaling but auto-scaling enabled: text doesn't scale
      self.element.textSize = value
    elseif unit == "%" or unit == "vh" then
      -- Percentage and vh are relative to viewport height
      self.element.textSize = Units.resolve(value, unit, newViewportWidth, newViewportHeight, newViewportHeight)
    elseif unit == "vw" then
      -- vw is relative to viewport width
      self.element.textSize = Units.resolve(value, unit, newViewportWidth, newViewportHeight, newViewportWidth)
    elseif unit == "ew" then
      -- Element width relative
      self.element.textSize = (value / 100) * self.element.width
    elseif unit == "eh" then
      -- Element height relative
      self.element.textSize = (value / 100) * self.element.height
    else
      self.element.textSize = Units.resolve(value, unit, newViewportWidth, newViewportHeight, nil)
    end

    -- Apply min/max constraints (with base scaling)
    local minSize = self.element.minTextSize and (self._Context.baseScale and (self.element.minTextSize * scaleY) or self.element.minTextSize)
    local maxSize = self.element.maxTextSize and (self._Context.baseScale and (self.element.maxTextSize * scaleY) or self.element.maxTextSize)

    if minSize and self.element.textSize < minSize then
      self.element.textSize = minSize
    end
    if maxSize and self.element.textSize > maxSize then
      self.element.textSize = maxSize
    end

    -- Protect against too-small text sizes (minimum 1px)
    if self.element.textSize < 1 then
      self.element.textSize = 1 -- Minimum 1px
    end
  elseif self.element.units.textSize.unit == "px" and self.element.units.textSize.value and self._Context.baseScale then
    -- No auto-scaling but base scaling is set: reapply base scaling to pixel text sizes
    self.element.textSize = self.element.units.textSize.value * scaleY

    -- Protect against too-small text sizes (minimum 1px)
    if self.element.textSize < 1 then
      self.element.textSize = 1 -- Minimum 1px
    end
  end

  -- Final protection: ensure textSize is always at least 1px (catches all edge cases)
  if self.element.text and self.element.textSize and self.element.textSize < 1 then
    self.element.textSize = 1 -- Minimum 1px
  end

  -- Recalculate gap if using viewport or percentage units
  if self.element.units.gap.unit ~= "px" then
    local containerSize = (self.flexDirection == self._FlexDirection.HORIZONTAL) and (self.element.parent and self.element.parent.width or newViewportWidth)
      or (self.element.parent and self.element.parent.height or newViewportHeight)
    self.element.gap = Units.resolve(self.element.units.gap.value, self.element.units.gap.unit, newViewportWidth, newViewportHeight, containerSize)
  end

  -- Recalculate spacing (padding/margin) if using viewport or percentage units
  -- For percentage-based padding:
  -- - If element has a parent: use parent's border-box dimensions (CSS spec for child elements)
  -- - If element has no parent: use element's own border-box dimensions (CSS spec for root elements)
  local parentBorderBoxWidth = self.element.parent and self.element.parent._borderBoxWidth or self.element._borderBoxWidth or newViewportWidth
  local parentBorderBoxHeight = self.element.parent and self.element.parent._borderBoxHeight or self.element._borderBoxHeight or newViewportHeight

  -- Handle shorthand properties first (horizontal/vertical)
  local resolvedHorizontalPadding = nil
  local resolvedVerticalPadding = nil

  if self.element.units.padding.horizontal and self.element.units.padding.horizontal.unit ~= "px" then
    resolvedHorizontalPadding = Units.resolve(
      self.element.units.padding.horizontal.value,
      self.element.units.padding.horizontal.unit,
      newViewportWidth,
      newViewportHeight,
      parentBorderBoxWidth
    )
  elseif self.element.units.padding.horizontal and self.element.units.padding.horizontal.value then
    resolvedHorizontalPadding = self.element.units.padding.horizontal.value
  end

  if self.element.units.padding.vertical and self.element.units.padding.vertical.unit ~= "px" then
    resolvedVerticalPadding = Units.resolve(
      self.element.units.padding.vertical.value,
      self.element.units.padding.vertical.unit,
      newViewportWidth,
      newViewportHeight,
      parentBorderBoxHeight
    )
  elseif self.element.units.padding.vertical and self.element.units.padding.vertical.value then
    resolvedVerticalPadding = self.element.units.padding.vertical.value
  end
  -- Resolve individual padding sides (with fallback to shorthand)
  for _, side in ipairs({ "top", "right", "bottom", "left" }) do
    -- Check if this side was explicitly set or if we should use shorthand
    local useShorthand = false
    if not self.element.units.padding[side].explicit then
      -- Not explicitly set, check if we have shorthand
      if side == "left" or side == "right" then
        useShorthand = resolvedHorizontalPadding ~= nil
      elseif side == "top" or side == "bottom" then
        useShorthand = resolvedVerticalPadding ~= nil
      end
    end

    if useShorthand then
      -- Use shorthand value
      if side == "left" or side == "right" then
        self.element.padding[side] = resolvedHorizontalPadding
      else
        self.element.padding[side] = resolvedVerticalPadding
      end
    elseif self.element.units.padding[side].unit ~= "px" then
      -- Recalculate non-pixel units
      local parentSize = (side == "top" or side == "bottom") and parentBorderBoxHeight or parentBorderBoxWidth
      self.element.padding[side] =
        Units.resolve(self.element.units.padding[side].value, self.element.units.padding[side].unit, newViewportWidth, newViewportHeight, parentSize)
    end
    -- If unit is "px" and not using shorthand, value stays the same
  end

  -- Handle margin shorthand properties
  local resolvedHorizontalMargin = nil
  local resolvedVerticalMargin = nil

  if self.element.units.margin.horizontal and self.element.units.margin.horizontal.unit ~= "px" then
    resolvedHorizontalMargin = Units.resolve(
      self.element.units.margin.horizontal.value,
      self.element.units.margin.horizontal.unit,
      newViewportWidth,
      newViewportHeight,
      parentBorderBoxWidth
    )
  elseif self.element.units.margin.horizontal and self.element.units.margin.horizontal.value then
    resolvedHorizontalMargin = self.element.units.margin.horizontal.value
  end

  if self.element.units.margin.vertical and self.element.units.margin.vertical.unit ~= "px" then
    resolvedVerticalMargin = Units.resolve(
      self.element.units.margin.vertical.value,
      self.element.units.margin.vertical.unit,
      newViewportWidth,
      newViewportHeight,
      parentBorderBoxHeight
    )
  elseif self.element.units.margin.vertical and self.element.units.margin.vertical.value then
    resolvedVerticalMargin = self.element.units.margin.vertical.value
  end

  -- Resolve individual margin sides (with fallback to shorthand)
  for _, side in ipairs({ "top", "right", "bottom", "left" }) do
    -- Check if this side was explicitly set or if we should use shorthand
    local useShorthand = false
    if not self.element.units.margin[side].explicit then
      -- Not explicitly set, check if we have shorthand
      if side == "left" or side == "right" then
        useShorthand = resolvedHorizontalMargin ~= nil
      elseif side == "top" or side == "bottom" then
        useShorthand = resolvedVerticalMargin ~= nil
      end
    end

    if useShorthand then
      -- Use shorthand value
      if side == "left" or side == "right" then
        self.element.margin[side] = resolvedHorizontalMargin
      else
        self.element.margin[side] = resolvedVerticalMargin
      end
    elseif self.element.units.margin[side].unit ~= "px" then
      -- Recalculate non-pixel units
      local parentSize = (side == "top" or side == "bottom") and parentBorderBoxHeight or parentBorderBoxWidth
      self.element.margin[side] =
        Units.resolve(self.element.units.margin[side].value, self.element.units.margin[side].unit, newViewportWidth, newViewportHeight, parentSize)
    end
    -- If unit is "px" and not using shorthand, value stays the same
  end

  -- BORDER-BOX MODEL: Calculate content dimensions from border-box dimensions
  -- For explicitly-sized elements (non-auto), _borderBoxWidth/_borderBoxHeight were set earlier
  -- Now we calculate content width/height by subtracting padding
  -- Only recalculate if using viewport/percentage units (where _borderBoxWidth actually changed)
  if self.element.units.width.unit ~= "auto" and self.element.units.width.unit ~= "px" then
    -- _borderBoxWidth was recalculated for viewport/percentage units
    -- Calculate content width by subtracting padding
    self.element.width = math.max(0, self.element._borderBoxWidth - self.element.padding.left - self.element.padding.right)
  elseif self.element.units.width.unit == "auto" then
    -- For auto-sized elements, width is content width (calculated in resize method)
    -- Update border-box to include padding
    self.element._borderBoxWidth = self.element.width + self.element.padding.left + self.element.padding.right
  end
  -- For pixel units, width stays as-is (may have been manually modified)

  if self.element.units.height.unit ~= "auto" and self.element.units.height.unit ~= "px" then
    -- _borderBoxHeight was recalculated for viewport/percentage units
    -- Calculate content height by subtracting padding
    self.element.height = math.max(0, self.element._borderBoxHeight - self.element.padding.top - self.element.padding.bottom)
  elseif self.element.units.height.unit == "auto" then
    -- For auto-sized elements, height is content height (calculated in resize method)
    -- Update border-box to include padding
    self.element._borderBoxHeight = self.element.height + self.element.padding.top + self.element.padding.bottom
  end
  -- For pixel units, height stays as-is (may have been manually modified)

  -- Detect overflow after layout calculations
  if self.element._detectOverflow then
    self.element:_detectOverflow()
  end
end

--- Check if layout can be skipped based on cached state (memoization)
---@return boolean canSkip True if layout hasn't changed and can be skipped
function LayoutEngine:_canSkipLayout()
  if not self.element then
    return false
  end

  local childrenCount = #self.element.children
  local containerWidth = self.element.width
  local containerHeight = self.element.height

  -- Generate simple hash of children dimensions
  local childrenHash = ""
  for i, child in ipairs(self.element.children) do
    if i <= 5 then -- Only hash first 5 children for performance
      childrenHash = childrenHash .. child.width .. "x" .. child.height .. ","
    end
  end

  local cache = self._layoutCache

  -- Check if layout inputs have changed
  if
    cache.childrenCount == childrenCount
    and cache.containerWidth == containerWidth
    and cache.containerHeight == containerHeight
    and cache.childrenHash == childrenHash
  then
    return true -- Layout hasn't changed, can skip
  end

  -- Update cache with current values
  cache.childrenCount = childrenCount
  cache.containerWidth = containerWidth
  cache.containerHeight = containerHeight
  cache.childrenHash = childrenHash

  return false -- Layout has changed, must recalculate
end

--- Track layout recalculations and warn about excessive layouts
function LayoutEngine:_trackLayoutRecalculation()
  if not LayoutEngine._Performance or not LayoutEngine._Performance.warningsEnabled then
    return
  end

  -- Get current frame count from Context
  local currentFrame = self._Context and self._Context._frameNumber or 0

  -- Reset counter on new frame
  if currentFrame ~= self._lastFrameCount then
    self._lastFrameCount = currentFrame
    self._layoutCount = 0
  end

  -- Increment layout count
  self._layoutCount = self._layoutCount + 1

  -- Warn if layout is recalculated excessively this frame
  if self._layoutCount >= 10 then
    local elementId = self.element and self.element.id or "unnamed"
    LayoutEngine._Performance:logWarning(
      string.format("excessive_layout_%s", elementId),
      "LayoutEngine",
      string.format("Layout recalculated %d times this frame for element '%s'", self._layoutCount, elementId),
      { layoutCount = self._layoutCount, elementId = elementId },
      "This may indicate a layout thrashing issue. Check for circular dependencies or dynamic sizing that triggers re-layout"
    )
  end
end

return LayoutEngine
