///|
/// Dependency analysis for incremental layout invalidation

///|
/// What a node's layout depends on
pub(all) enum DependencyKind {
  /// Only fixed values (Length) - never needs re-layout due to parent changes
  Static
  /// Depends on parent's width (Percent in width/margin/padding)
  ParentWidth
  /// Depends on parent's height (Percent in height)
  ParentHeight
  /// Depends on both parent dimensions
  ParentBoth
  /// Depends on children's content (Auto sizing)
  Intrinsic
  /// Depends on viewport (vw/vh - future extension)
  Viewport
} derive(Eq, Debug)

///|
pub impl Show for DependencyKind with fn output(self, logger) {
  match self {
    Static => logger.write_string("Static")
    ParentWidth => logger.write_string("ParentWidth")
    ParentHeight => logger.write_string("ParentHeight")
    ParentBoth => logger.write_string("ParentBoth")
    Intrinsic => logger.write_string("Intrinsic")
    Viewport => logger.write_string("Viewport")
  }
}

///|
/// Merge two dependency kinds into a combined dependency
pub fn DependencyKind::merge(
  self : DependencyKind,
  other : DependencyKind,
) -> DependencyKind {
  match (self, other) {
    // Static + anything = the other
    (Static, x) => x
    (x, Static) => x
    // Same dependency
    (x, y) if x == y => x
    // ParentWidth + ParentHeight = ParentBoth
    (ParentWidth, ParentHeight) => ParentBoth
    (ParentHeight, ParentWidth) => ParentBoth
    // ParentBoth absorbs ParentWidth/ParentHeight
    (ParentBoth, ParentWidth) => ParentBoth
    (ParentBoth, ParentHeight) => ParentBoth
    (ParentWidth, ParentBoth) => ParentBoth
    (ParentHeight, ParentBoth) => ParentBoth
    // Viewport is separate concern
    (Viewport, ParentWidth) => ParentBoth // Simplification
    (Viewport, ParentHeight) => ParentBoth
    (ParentWidth, Viewport) => ParentBoth
    (ParentHeight, Viewport) => ParentBoth
    // Intrinsic combines with parent dependencies
    (Intrinsic, ParentWidth) => ParentWidth
    (Intrinsic, ParentHeight) => ParentHeight
    (ParentWidth, Intrinsic) => ParentWidth
    (ParentHeight, Intrinsic) => ParentHeight
    (Intrinsic, ParentBoth) => ParentBoth
    (ParentBoth, Intrinsic) => ParentBoth
    // Default: most general
    _ => ParentBoth
  }
}

///|
/// Check if a Dimension depends on parent width
fn dimension_depends_on_parent_width(dim : @types.Dimension) -> Bool {
  match dim {
    @types.Percent(_) => true
    _ => false
  }
}

///|
/// Check if a Dimension is auto (depends on content)
fn dimension_is_auto(dim : @types.Dimension) -> Bool {
  match dim {
    @types.Auto => true
    _ => false
  }
}

///|
/// Analyze what a style depends on for layout
pub fn analyze_style_dependencies(style : @style.Style) -> DependencyKind {
  let mut deps = Static

  // Width dependency
  if dimension_depends_on_parent_width(style.width) {
    deps = deps.merge(ParentWidth)
  } else if dimension_is_auto(style.width) {
    deps = deps.merge(Intrinsic)
  }

  // Height dependency
  match style.height {
    @types.Percent(_) => deps = deps.merge(ParentHeight)
    @types.Auto => deps = deps.merge(Intrinsic)
    _ => ()
  }

  // Min/max width (% depends on parent width)
  if dimension_depends_on_parent_width(style.min_width) ||
    dimension_depends_on_parent_width(style.max_width) {
    deps = deps.merge(ParentWidth)
  }

  // Min/max height (% depends on parent height)
  match style.min_height {
    @types.Percent(_) => deps = deps.merge(ParentHeight)
    _ => ()
  }
  match style.max_height {
    @types.Percent(_) => deps = deps.merge(ParentHeight)
    _ => ()
  }

  // Margin/padding percentages always depend on parent WIDTH (CSS spec)
  if dimension_depends_on_parent_width(style.margin.left) ||
    dimension_depends_on_parent_width(style.margin.right) ||
    dimension_depends_on_parent_width(style.margin.top) ||
    dimension_depends_on_parent_width(style.margin.bottom) ||
    dimension_depends_on_parent_width(style.padding.left) ||
    dimension_depends_on_parent_width(style.padding.right) ||
    dimension_depends_on_parent_width(style.padding.top) ||
    dimension_depends_on_parent_width(style.padding.bottom) {
    deps = deps.merge(ParentWidth)
  }

  // Flex basis
  if dimension_depends_on_parent_width(style.flex_basis) {
    deps = deps.merge(ParentWidth)
  }
  deps
}