///|
/// The four looks of an async job's status badge. `Running` carries a
/// progress percentage (clamped to 0–100); `Count` carries a queue depth
/// (displayed capped at 99, matching the design's two-digit circle).
pub(all) enum StatusBadgeState {
  Running(Int)
  Count(Int)
  Complete
  Warning
}

///|
const StatusBadgeBaseStyle : String = "position:relative;width:20px;height:20px;flex:none"

///|
const StatusBadgeRunningStyle : String = "border-radius:16px;background:var(--sumi-block,rgba(255,255,255,0.08));backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px)"

///|
const StatusBadgeCountStyle : String = "border-radius:10px;background:#ffffff;border:2px solid var(--sumi-spotlight,#292929);display:flex;align-items:center;justify-content:center"

///|
const StatusBadgeDiscStyle : String = "border-radius:10px;background:var(--sumi-spotlight,#292929);border:2px solid var(--sumi-spotlight,#292929)"

///|
fn status_badge_clamp(v : Int, lo : Int, hi : Int) -> Int {
  if v < lo {
    lo
  } else if v > hi {
    hi
  } else {
    v
  }
}

///|
/// Arc length of the progress ring for `pct` — the ring circle has r=15 on
/// the 50-unit grid, so a full turn is 2π·15 ≈ 94.2478.
fn status_badge_dash(pct : Int) -> Double {
  status_badge_clamp(pct, 0, 100).to_double() * 0.942478
}

///|
/// Queue depth as shown in the white circle: the design's circle fits two
/// digits, so anything past 99 renders as "99".
fn status_badge_count_label(n : Int) -> String {
  status_badge_clamp(n, 0, 99).to_string()
}

///|
/// The determinate progress ring: dim track plus a lighter arc that grows
/// clockwise from the top (the -90° rotation). Geometry sits on a 50-unit
/// grid so every SVG value stays integral; the box scales it to 16.667px.
fn status_badge_ring(pct : Int) -> @html.Html {
  let track = @svg.circle(
    cx=25,
    cy=25,
    r=15,
    fill="none",
    stroke="rgba(204,221,255,0.08)",
    stroke_width=6,
  )
  let arc_attrs = @svg.Attrs::build()
    .stroke_dasharray("\{status_badge_dash(pct)} 94.2478")
    .stroke_linecap("round")
  let arc = @svg.circle(
    cx=25,
    cy=25,
    r=15,
    fill="none",
    stroke="rgba(224,245,255,0.35)",
    stroke_width=6,
    transform="rotate(-90 25 25)",
    attrs=arc_attrs,
  )
  let children : Array[@svg.Svg] = if pct <= 0 { [track] } else { [track, arc] }
  @html.span(
    style=[
      @internal.SumiBoxSizing,
      "position:absolute;left:1.667px;top:1.667px;width:16.667px;height:16.667px;pointer-events:none",
    ],
    attrs=@html.Attrs::build().aria_hidden("true"),
    @svg.svg(
      view_box="0 0 50 50",
      style=["display:block;width:100%;height:100%"],
      children,
    ),
  )
}

///|
/// A 20px badge reporting an async job's state, per the design: a frosted
/// determinate ring while running, a white circle with the queue depth, a
/// blue tick disc on completion, an amber info disc for partial failure.
/// Rendered on dark imagery, so the palette is pinned to the dark values.
///
/// ```moonbit nocheck
/// status_badge(state=Running(45))
/// status_badge(state=Count(3))
/// status_badge(state=Complete)
/// status_badge(state=Warning)
/// ```
pub fn status_badge(
  state~ : StatusBadgeState,
  aria_label? : String,
  id? : String,
  class? : String,
  attrs? : @html.Attrs,
  style? : Array[String] = [],
) -> @html.Html {
  let (state_name, variant_style, default_label) = match state {
    Running(pct) =>
      (
        "running",
        StatusBadgeRunningStyle,
        "In progress, \{status_badge_clamp(pct, 0, 100)}%",
      )
    Count(n) => ("count", StatusBadgeCountStyle, "\{n} tasks")
    Complete => ("complete", StatusBadgeDiscStyle, "Complete")
    Warning => ("warning", StatusBadgeDiscStyle, "Partially failed")
  }
  let element_attrs = @internal.sumi_attrs(attrs)
    .data_set("slot", "status-badge")
    .data_set("state", state_name)
    .role("img")
  ignore(element_attrs.aria_label(aria_label.unwrap_or(default_label)))
  let children : Array[@html.Html] = match state {
    Running(pct) => [status_badge_ring(pct)]
    Count(n) =>
      [
        @html.span(
          style=[
            @internal.SumiFontNum,
            "font-size:10px;line-height:1;font-weight:500;color:#0d0d0d;white-space:nowrap;pointer-events:none",
          ],
          [@html.text(status_badge_count_label(n))],
        ),
      ]
    Complete | Warning => {
      let (glyph, tint) = match state {
        Complete =>
          (
            @primitives.icon_tick_circle_fill(size=16, style=[
              "width:16.667px;height:16.667px",
            ]),
            "color:var(--sumi-brand,#009efa)",
          )
        _ =>
          (
            @primitives.icon_info_circle_fill(size=16, style=[
              "width:16.667px;height:16.667px",
            ]),
            "color:var(--sumi-favorite,#ffa21e)",
          )
      }
      [
        @html.span(
          style=[
            @internal.SumiBoxSizing,
            "position:absolute;inset:-2px;display:flex;align-items:center;justify-content:center;pointer-events:none;\{tint}",
          ],
          attrs=@html.Attrs::build().aria_hidden("true"),
          [glyph],
        ),
      ]
    }
  }
  @html.div(
    style=@internal.sumi_styles(
      [
        @internal.SumiBoxSizing,
        @internal.SumiFontSans,
        @internal.SumiTextRendering,
        StatusBadgeBaseStyle,
        variant_style,
      ],
      style,
    ),
    id?,
    class?,
    attrs=element_attrs,
    children,
  )
}