///|
pub struct CounterName {
  css : String
}

///|
pub struct CounterChange {
  css : String
}

///|
pub struct CounterChanges {
  css : String
}

///|
pub fn CounterChanges::to_css(self : CounterChanges) -> String {
  self.css
}

///|
pub fn counter_name(value : String) -> CounterName {
  if valid_custom_ident(value) && value.to_lower() != "none" {
    { css: value, }
  } else {
    {
      css: issue_css(
        "STYLE_COUNTER_NAME", "Counter names must be custom identifiers",
      ),
    }
  }
}

///|
/// The integer is explicit: reset/set usually use zero; increment usually uses one.
pub fn counter_change(name : CounterName, value : Int32) -> CounterChange {
  { css: name.css + " " + value.to_string(), }
}

///|
pub fn counter_changes(values : Array[CounterChange]) -> CounterChanges {
  {
    css: if values.is_empty() {
      issue_css(
        "STYLE_COUNTER_EMPTY", "Counter changes must not be empty; use counters_none()",
      )
    } else {
      values.map(value => value.css).join(" ")
    },
  }
}

///|
pub fn counters_none() -> CounterChanges {
  { css: "none", }
}

///|
pub(all) enum CounterStyle {
  Decimal
  DecimalLeadingZero
  LowerAlpha
  UpperAlpha
  LowerRoman
  UpperRoman
} derive(Eq, Debug)

///|
pub extend CounterStyle with Eq::{equal, not_equal}

///|
pub extend CounterStyle with @debug.Debug::{to_repr}

///|
fn CounterStyle::css(self : CounterStyle) -> String {
  match self {
    Decimal => "decimal"
    DecimalLeadingZero => "decimal-leading-zero"
    LowerAlpha => "lower-alpha"
    UpperAlpha => "upper-alpha"
    LowerRoman => "lower-roman"
    UpperRoman => "upper-roman"
  }
}

///|
pub fn counter_content(
  name : CounterName,
  style~ : CounterStyle = Decimal,
) -> ContentValue {
  { css: "counter(" + name.css + ", " + style.css() + ")", }
}

///|
pub fn counters_content(
  name : CounterName,
  separator : String,
  style~ : CounterStyle = Decimal,
) -> ContentValue {
  {
    css: "counters(" +
    name.css +
    ", " +
    quoted_css_string(separator, "counter separator") +
    ", " +
    style.css() +
    ")",
  }
}

///|
pub fn content_sequence(values : Array[ContentValue]) -> ContentValue {
  if values.is_empty() || values.any(value => value.css == "none") {
    {
      css: issue_css(
        "STYLE_CONTENT_SEQUENCE", "Content requires text or counter items; none must stand alone",
      ),
    }
  } else {
    { css: values.map(value => value.css).join(" "), }
  }
}