///|
pub(all) enum LayerAttachment {
  LayerScroll
  LayerFixed
  LayerLocal
} derive(Eq, Debug)

///|
pub(all) enum LayerBox {
  LayerBorderBox
  LayerPaddingBox
  LayerContentBox
} derive(Eq, Debug)

///|
pub struct LayerSize {
  expression : Expression
} derive(Eq, Debug)

///|
pub struct BackgroundLayer {
  image : Expression
  position : GradientPosition
  size : LayerSize
  repeat : RepeatStyle
  attachment : LayerAttachment
  origin : LayerBox
  clip : LayerBox
} derive(Eq, Debug)

///|
pub struct BackgroundLayers {
  layers : Array[BackgroundLayer]
} derive(Eq, Debug)

///|
pub fn layer_size(value : BackgroundSize) -> LayerSize {
  { expression: literal_expression(value.to_css(), "background-size"), }
}

///|
pub fn[X : LengthPercentageMathInput, Y : LengthPercentageMathInput] layer_dimensions(
  width : X,
  height : Y,
) -> LayerSize {
  {
    expression: group_expression(
      "background-size",
      "",
      [
        width.length_percentage_math().expression.constrain("nonnegative"),
        height.length_percentage_math().expression.constrain("nonnegative"),
      ],
      " ",
      "",
    ),
  }
}

///|
pub fn[I : ImageInput] background_layer(
  image : I,
  position~ : GradientPosition = {
    x: literal_expression("0%", "length-percentage"),
    y: literal_expression("0%", "length-percentage"),
  },
  size~ : LayerSize = {
    expression: literal_expression("auto", "background-size"),
  },
  repeat~ : RepeatStyle = Repeat,
  attachment~ : LayerAttachment = LayerScroll,
  origin~ : LayerBox = LayerPaddingBox,
  clip~ : LayerBox = LayerBorderBox,
) -> BackgroundLayer {
  {
    image: image.image_expression(),
    position,
    size,
    repeat,
    attachment,
    origin,
    clip,
  }
}

///|
pub fn background_layers(layers : Array[BackgroundLayer]) -> BackgroundLayers {
  { layers: layers.copy(), }
}

///|
fn LayerBox::css(self : LayerBox) -> String {
  match self {
    LayerBorderBox => "border-box"
    LayerPaddingBox => "padding-box"
    LayerContentBox => "content-box"
  }
}

///|
fn BackgroundLayer::longhand(
  self : BackgroundLayer,
  property : String,
) -> Expression {
  match property {
    "backgroundImage" => self.image
    "backgroundPositionX" => self.position.x
    "backgroundPositionY" => self.position.y
    "backgroundSize" => self.size.expression
    "backgroundRepeat" =>
      literal_expression(self.repeat.to_css(), "background-repeat")
    "backgroundAttachment" =>
      literal_expression(
        match self.attachment {
          LayerScroll => "scroll"
          LayerFixed => "fixed"
          LayerLocal => "local"
        },
        "background-attachment",
      )
    "backgroundOrigin" =>
      literal_expression(self.origin.css(), "background-origin")
    _ => literal_expression(self.clip.css(), "background-clip")
  }
}

///|
pub fn BackgroundLayers::longhands(
  self : BackgroundLayers,
) -> Array[(String, Expression)] {
  [
    "backgroundImage", "backgroundPositionX", "backgroundPositionY", "backgroundSize",
    "backgroundRepeat", "backgroundAttachment", "backgroundOrigin", "backgroundClip",
  ].map(property => {
    let values = self.layers.map(layer => layer.longhand(property))
    if values.is_empty() {
      values.push(
        invalid_expression(
          "STYLE_BACKGROUND_EMPTY", "A background layer list must not be empty",
        ),
      )
    }
    (
      property,
      group_expression(
        if property == "backgroundImage" {
          "image-list"
        } else {
          property
        },
        "",
        values,
        ", ",
        "",
      ),
    )
  })
}

///|
pub fn BackgroundLayers::property_expression(
  self : BackgroundLayers,
  property : String,
) -> Expression {
  for (name, expression) in self.longhands() {
    if name == property {
      return expression
    }
  }
  invalid_expression(
    "STYLE_BACKGROUND_PROPERTY", "Unsupported background longhand",
  )
}