///|
/// Parse a dimension value from string
pub fn parse_dimension(value : String) -> @types.Dimension {
  let v = value.trim()
  if v == "auto" || v == "none" {
    return Auto
  }
  // Intrinsic sizing keywords
  if v == "min-content" {
    return MinContent
  }
  if v == "max-content" {
    return MaxContent
  }
  // fit-content()
  if v.has_prefix("fit-content(") && v.has_suffix(")") {
    // Extract content between "fit-content(" and ")"
    let v_str = v.to_owned()
    let inner = v_str.unsafe_substring(start=12, end=v_str.length() - 1)
    // Parse the inner value as a length
    match inner.strip_suffix("px") {
      Some(num_str) => {
        let n = @string.parse_double(num_str.to_owned()) catch {
          _ => return Auto
        }
        return FitContent(n)
      }
      None => ()
    }
    // Try percentage
    match inner.strip_suffix("%") {
      Some(num_str) => {
        let n = @string.parse_double(num_str.to_owned()) catch {
          _ => return Auto
        }
        // For fit-content, percentage is relative to available space
        // Store as negative to differentiate from length
        return FitContent(n)
      }
      None => ()
    }
    return Auto
  }
  // Try to parse as length (px)
  match v.strip_suffix("px") {
    Some(num_str) => {
      let n = @string.parse_double(num_str.to_owned()) catch {
        _ => return Auto
      }
      return Length(n)
    }
    None => ()
  }
  // Try to parse as percentage
  match v.strip_suffix("%") {
    Some(num_str) => {
      let n = @string.parse_double(num_str.to_owned()) catch {
        _ => return Auto
      }
      return Percent(n / 100.0)
    }
    None => ()
  }
  // Try to parse as plain number (treated as px)
  let n = @string.parse_double(v.to_owned()) catch { _ => return Auto }
  Length(n)
}

///|
/// Extract border width from shorthand value
/// Handles formats like "3px", "solid 3px", "1px solid red", "none", etc.
pub fn extract_border_width(value : String) -> @types.Dimension {
  let v = value.trim()

  // Handle "none" case
  if v == "none" || v == "0" {
    return Length(0.0)
  }

  // Split by whitespace and look for a dimension value
  let parts = split_whitespace(v.to_owned())
  let mut has_visible_style = false
  for part in parts {
    let lower = part.to_lower()
    match lower {
      "thin" => return Length(1.0)
      "medium" => return Length(3.0)
      "thick" => return Length(5.0)
      "solid"
      | "dotted"
      | "dashed"
      | "double"
      | "groove"
      | "ridge"
      | "inset"
      | "outset" => {
        has_visible_style = true
        continue
      }
      "none" | "hidden" => continue
      _ => ()
    }
    // Check if this part looks like a dimension (ends with px or is a number)
    if part.has_suffix("px") {
      match part.strip_suffix("px") {
        Some(num_str) => {
          let n = @string.parse_double(num_str.to_owned()) catch {
            _ => continue
          }
          return Length(n)
        }
        None => continue
      }
    }
    // Try plain number
    let first_char = part[0].to_int()
    if first_char >= '0'.to_int() && first_char <= '9'.to_int() {
      let n = @string.parse_double(part) catch { _ => continue }
      return Length(n)
    }
  }

  // Compatible default for style-only shorthand like "border: solid".
  if has_visible_style {
    Length(1.5)
  } else {
    // Default: no border
    Length(0.0)
  }
}

///|
/// Split string by whitespace into parts
fn split_whitespace(s : String) -> Array[String] {
  let result : Array[String] = []
  let current = StringBuilder::new()
  for c in s {
    if c == ' ' || c == '\t' || c == '\n' {
      if current.to_string().length() > 0 {
        result.push(current.to_string())
        current.reset()
      }
    } else {
      current.write_char(c)
    }
  }
  if current.to_string().length() > 0 {
    result.push(current.to_string())
  }
  result
}

///|