///|
fn stateful_numeric_value(
  theme : Map[String, String],
  key : String,
  theme_namespace : String,
  unit : String,
) -> String? {
  match arbitrary_value(key) {
    Some(value) => Some(value)
    None =>
      match theme_css_value(theme, "\{theme_namespace}-\{key}") {
        Some(value) => Some(value)
        None =>
          if is_spacing_number(key) {
            if unit == "" {
              Some(key)
            } else {
              Some("\{key}\{unit}")
            }
          } else {
            None
          }
      }
  }
}

///|
fn transform_origin_utility(
  theme : Map[String, String],
  name : String,
) -> Array[Declaration]? {
  guard prefixed_value(name, "origin") is Some(key) else { return None }
  let keywords : Array[(String, String)] = [
    ("center", "center"),
    ("top", "top"),
    ("top-right", "top right"),
    ("right", "right"),
    ("bottom-right", "bottom right"),
    ("bottom", "bottom"),
    ("bottom-left", "bottom left"),
    ("left", "left"),
    ("top-left", "top left"),
  ]
  for entry in keywords {
    let (candidate, value) = entry
    if key == candidate {
      return Some([decl("transform-origin", value)])
    }
  }
  let value = match arbitrary_value(key) {
    Some(value) => Some(value)
    None => theme_css_value(theme, "--transform-origin-\{key}")
  }
  value.map(fn(value) { [decl("transform-origin", value)] })
}

///|
fn translate_utility(
  theme : Map[String, String],
  name : String,
) -> Array[Declaration]? {
  if name == "translate-3d" {
    return Some([
      decl(
        "translate", "var(--tw-translate-x) var(--tw-translate-y) var(--tw-translate-z)",
      ),
    ])
  }
  let (root, properties) = if name.has_prefix("translate-x-") {
    ("translate-x", ["--tw-translate-x"])
  } else if name.has_prefix("translate-y-") {
    ("translate-y", ["--tw-translate-y"])
  } else if name.has_prefix("translate-z-") {
    ("translate-z", ["--tw-translate-z"])
  } else if name.has_prefix("translate-") {
    ("translate", ["--tw-translate-x", "--tw-translate-y"])
  } else {
    return None
  }
  guard prefixed_value(name, root) is Some(key) else { return None }
  let value = if key == "full" {
    Some("100%")
  } else {
    match theme_css_value(theme, "--translate-\{key}") {
      Some(value) => Some(value)
      None => resolved_value(theme, key, "--translate", true)
    }
  }
  guard value is Some(value) else { return None }
  let declarations = properties.map(fn(property) { decl(property, value) })
  if root == "translate-z" {
    declarations.push(
      decl(
        "translate", "var(--tw-translate-x) var(--tw-translate-y) var(--tw-translate-z)",
      ),
    )
  } else {
    declarations.push(
      decl("translate", "var(--tw-translate-x) var(--tw-translate-y)"),
    )
  }
  Some(declarations)
}

///|
fn rotate_skew_utility(
  theme : Map[String, String],
  name : String,
) -> Array[Declaration]? {
  let (root, custom_property, function_name) = if name.has_prefix("rotate-x-") {
    ("rotate-x", Some("--tw-rotate-x"), "rotateX")
  } else if name.has_prefix("rotate-y-") {
    ("rotate-y", Some("--tw-rotate-y"), "rotateY")
  } else if name.has_prefix("rotate-z-") {
    ("rotate-z", Some("--tw-rotate-z"), "rotateZ")
  } else if name.has_prefix("skew-x-") {
    ("skew-x", Some("--tw-skew-x"), "skewX")
  } else if name.has_prefix("skew-y-") {
    ("skew-y", Some("--tw-skew-y"), "skewY")
  } else if name.has_prefix("rotate-") {
    ("rotate", None, "")
  } else {
    return None
  }
  guard prefixed_value(name, root) is Some(key) else { return None }
  let theme_namespace = if root.has_prefix("skew") {
    "--skew"
  } else {
    "--rotate"
  }
  guard stateful_numeric_value(theme, key, theme_namespace, "deg")
    is Some(value) else {
    return None
  }
  match custom_property {
    None => Some([decl("rotate", value)])
    Some(property) =>
      Some([
        decl(property, "\{function_name}(\{value})"),
        decl(
          "transform", "var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)",
        ),
      ])
  }
}

///|
fn scale_utility(
  theme : Map[String, String],
  name : String,
) -> Array[Declaration]? {
  let (root, properties) = if name.has_prefix("scale-x-") {
    ("scale-x", ["--tw-scale-x"])
  } else if name.has_prefix("scale-y-") {
    ("scale-y", ["--tw-scale-y"])
  } else if name.has_prefix("scale-z-") {
    ("scale-z", ["--tw-scale-z"])
  } else if name.has_prefix("scale-") {
    ("scale", ["--tw-scale-x", "--tw-scale-y", "--tw-scale-z"])
  } else {
    return None
  }
  guard prefixed_value(name, root) is Some(key) else { return None }
  let value = match arbitrary_value(key) {
    Some(value) => Some(value)
    None =>
      match theme_css_value(theme, "--scale-\{key}") {
        Some(value) => Some(value)
        None => if is_spacing_number(key) { Some("\{key}%") } else { None }
      }
  }
  guard value is Some(value) else { return None }
  let declarations = properties.map(fn(property) { decl(property, value) })
  declarations.push(decl("scale", "var(--tw-scale-x) var(--tw-scale-y)"))
  Some(declarations)
}

///|
fn perspective_utility(
  theme : Map[String, String],
  name : String,
) -> Array[Declaration]? {
  if name.has_prefix("perspective-origin-") {
    let key = name[19:].to_owned()
    // A theme key resolves under both `--perspective-origin-*` and, read as
    // `perspective-origin-`, under `--perspective-*`, so upstream compiles
    // the candidate against both roots. An arbitrary value only matches the
    // `perspective-origin` root.
    match arbitrary_value(key) {
      Some(value) => return Some([decl("perspective-origin", value)])
      None => ()
    }
    return theme_css_value(theme, "--perspective-origin-\{key}").map(fn(value) {
      [decl("perspective-origin", value), decl("perspective", value)]
    })
  }
  guard prefixed_value(name, "perspective") is Some(key) else { return None }
  let value = match key {
    "none" => Some("none")
    _ =>
      match arbitrary_value(key) {
        Some(value) => Some(value)
        None => theme_css_value(theme, "--perspective-\{key}")
      }
  }
  value.map(fn(value) { [decl("perspective", value)] })
}

///|
fn stateful_transform_utility(
  theme : Map[String, String],
  name : String,
) -> Array[Declaration]? {
  match name {
    "transform-flat" => return Some([decl("transform-style", "flat")])
    "transform-3d" => return Some([decl("transform-style", "preserve-3d")])
    "transform-none" => return Some([decl("transform", "none")])
    "transform" | "transform-cpu" =>
      return Some([
        decl(
          "transform", "var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)",
        ),
      ])
    "transform-gpu" =>
      return Some([
        decl(
          "transform", "translateZ(0) var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)",
        ),
      ])
    "transform-view" => return Some([decl("transform-box", "view-box")])
    _ => ()
  }
  match transform_origin_utility(theme, name) {
    Some(value) => return Some(value)
    None => ()
  }
  match translate_utility(theme, name) {
    Some(value) => return Some(value)
    None => ()
  }
  match rotate_skew_utility(theme, name) {
    Some(value) => return Some(value)
    None => ()
  }
  match scale_utility(theme, name) {
    Some(value) => return Some(value)
    None => perspective_utility(theme, name)
  }
}