///|
/// Real-provider text smoke: the L1 acceptance leg that a glyph run reaches a
/// Metal render target as *coverage*, not as a filled rectangle.
///
/// A renderer-local test cannot cover this, because the module depends on no
/// text provider (that is what plan stage L0.5 bought). So the composition root
/// injects the platform engine and this function asserts on read-back pixels.
/// The shape check is the point: an ink ratio inside the band can only come
/// from partial coverage, and the noop control proves the ink came from text.
pub fn metal_text_smoke(text_engine~ : NativeTextEngine) -> Unit {
  let width = 220
  let height = 48
  let run = @core.DrawText(
    @core.TextRun::new(
      text="MMMMWWWW@",
      frame=@core.Rect::new(
        x=0.0,
        y=0.0,
        width=width.to_double(),
        height=height.to_double(),
      ),
      font=@core.FontSpec::new(size=32.0),
      color=@core.Color::white(),
      align=@core.TextStart,
    ),
  )
  let inked = metal_smoke_ink(width~, height~, commands=[run], text_engine~).inked
  let control = metal_smoke_ink(
      width~,
      height~,
      commands=[run],
      text_engine=native_noop_text_engine(),
    ).inked
  let ratio = inked.to_double() / (width * height).to_double()
  println(
    "MoUI metal text smoke inked=\{inked} ratio=\{ratio.to_string()} control=\{control}",
  )
  if control != 0 {
    abort("metal text smoke: the noop engine must paint nothing")
  }
  if ratio < 0.02 || ratio > 0.6 {
    abort(
      "metal text smoke: ink ratio is not glyph coverage (solid bar or empty)",
    )
  }
  let report = metal_frame_report(
    commands=[run],
    width=width.to_double(),
    height=height.to_double(),
    text_engine~,
  )
  if !report.draws_anything() || report.text_dropped_glyphs != 0 {
    abort("metal text smoke: the frame report disagrees with the painted ink")
  }
  println(
    "MoUI metal frame report items=\{report.items} vertices=\{report.vertices} refused=\{report.refused_count()}",
  )
  metal_emoji_smoke(text_engine~)
  metal_text_capacity_smoke(text_engine~)
  println("MoUI metal text smoke passed glyph-coverage-shape zero-ink-control")
}

///|
/// The within-frame half of the `Text` row, through the same real provider.
///
/// 1,600 distinct ideographs at 14pt is what the L3c measurement found a single
/// 1024×1024 page cannot hold at device scale 2.0: its ceiling was ~818 of those
/// boxes, so the frame dropped roughly 780 glyph boxes *every* frame — the
/// clear-and-rebuild retry could not help, because the second pass ran into the
/// same wall. Growth is the fix, and the claim is counted rather than eyeballed:
/// zero dropped glyphs at both scales, and the report has to say it drew
/// something.
///
/// Scale 1.0 is measured alongside 2.0 because the two pin different halves. The
/// density that forces a second page is a device-scale property, so the 1.0 run
/// must stay one item: a frame page 0 already covers has to pay exactly what it
/// paid before paging existed, and an atlas that grew on a fit frame would show
/// up here as two items rather than as a memory comment.
fn metal_text_capacity_smoke(text_engine~ : NativeTextEngine) -> Unit {
  // (size, device scale, distinct ideographs, the least number of text items the
  // frame must build). The first cell fits page 0 at scale 1.0, the second is the
  // Retina page that forced this design, and the third is a second size so the
  // paging is not a fact about 14pt alone: ~347 distinct 24pt boxes fit a page at
  // scale 2.0, so 900 of them cannot be one item.
  let cells : Array[(Double, Double, Int32, Int32)] = [
    (14.0, 1.0, 1600, 1),
    (14.0, 2.0, 1600, 2),
    (24.0, 2.0, 900, 2),
  ]
  for cell in cells {
    let (size, scale, glyphs, least_items) = cell
    let builder = StringBuilder(size_hint=glyphs)
    for index in 0.. @core.DrawCommand {
  @core.DrawText(
    @core.TextRun::new(
      text~,
      frame=@core.Rect::new(x=0.0, y=0.0, width=side, height=side),
      font=@core.FontSpec::new(size~),
      color~,
      align=@core.TextStart,
    ),
  )
}

///|
/// The colour half of the row, through the same real provider.
///
/// `moui_metal_text_fragment` multiplies the atlas sample by the run colour, so
/// a run tinted pure red can only light a green channel if the glyph arrived
/// with its own pixels. The mirrored half (pure green run, red channel lit)
/// fails together with it, which is the point: a provider that hands back
/// monochrome coverage for an emoji is caught by both, and a solid bar is caught
/// by neither claim because each names a channel the run colour zeroes.
///
/// Two samples, because a single-codepoint emoji and a ZWJ sequence reach the
/// atlas through different paths — the sequence is one composite glyph the
/// provider folds the carets over.
fn metal_emoji_smoke(text_engine~ : NativeTextEngine) -> Unit {
  for sample in ["🙂", "👩‍💻"] {
    let red = @core.Color::rgba(r=1.0, g=0.0, b=0.0)
    let green = @core.Color::rgba(r=0.0, g=1.0, b=0.0)
    for size in [24.0, 32.0, 48.0] {
      let side = (size * 1.5).to_int()
      let sized = metal_emoji_run(sample, red, size~, side=size * 1.5)
      let sized_green = metal_emoji_run(sample, green, size~, side=size * 1.5)
      let sized_control = metal_emoji_run(sample, red, size~, side=size * 1.5)
      let at_size = metal_smoke_ink(
        width=side,
        height=side,
        commands=[sized],
        text_engine~,
      )
      let mirror = metal_smoke_ink(
        width=side,
        height=side,
        commands=[sized_green],
        text_engine~,
      )
      let zero = metal_smoke_ink(
        width=side,
        height=side,
        commands=[sized_control],
        text_engine=native_noop_text_engine(),
      )
      let sized_report = metal_frame_report(
        commands=[sized],
        width=side.to_double(),
        height=side.to_double(),
        text_engine~,
      )
      println(
        "MoUI metal text smoke emoji=\{sample} size=\{size.to_string()}pt inked=\{at_size.inked} green=\{at_size.green} red-from-green-run=\{mirror.red} control=\{zero.inked} dropped=\{sized_report.text_dropped_glyphs}",
      )
      if zero.inked != 0 {
        abort(
          "metal text smoke: the noop engine must paint no emoji at any size",
        )
      }
      if at_size.inked == 0 || sized_report.text_dropped_glyphs != 0 {
        abort("metal text smoke: an emoji size painted nothing or was dropped")
      }
      if at_size.green == 0 || mirror.red == 0 {
        abort(
          "metal text smoke: emoji ink carries no channel the run colour cannot produce, at a size that asked for colour",
        )
      }
    }
    // The same claim at a Retina device scale, which is the case a MacBook
    // actually draws and that the proof pass could not express until it took a
    // scale itself.
    let retina_side = 64
    let retina = metal_smoke_ink(
      width=retina_side,
      height=retina_side,
      commands=[metal_emoji_run(sample, red, size=48.0, side=64.0)],
      text_engine~,
      scale_factor=2.0,
    )
    let retina_control = metal_smoke_ink(
      width=retina_side,
      height=retina_side,
      commands=[metal_emoji_run(sample, red, size=48.0, side=64.0)],
      text_engine=native_noop_text_engine(),
      scale_factor=2.0,
    )
    println(
      "MoUI metal text smoke emoji=\{sample} scale=2 inked=\{retina.inked} green=\{retina.green} control=\{retina_control.inked}",
    )
    if retina_control.inked != 0 {
      abort(
        "metal text smoke: a noop engine paints no emoji at scale 2.0 either",
      )
    }
    if retina.inked == 0 || retina.green == 0 {
      abort(
        "metal text smoke: the colour glyph did not survive the device-scale raster",
      )
    }
    // The same colour claim through a layer composite, so the pixel that proves
    // the provider's colour survived is now read off a group's own target rather
    // than the main pass: a route that only took the colour branch on the main
    // pass, or re-tinted inside the group, lands red where green is due.
    let grouped : Array[@core.DrawCommand] = [
      @core.PushLayer(@core.LayerSpec::new()),
      metal_emoji_run(sample, red, size=48.0, side=64.0),
      @core.PopLayer,
    ]
    let in_group = metal_smoke_ink(
      width=64,
      height=64,
      commands=grouped,
      text_engine~,
    )
    let group_control = metal_smoke_ink(
      width=64,
      height=64,
      commands=grouped,
      text_engine=native_noop_text_engine(),
    )
    let group_report = metal_frame_report(
      commands=grouped,
      width=64.0,
      height=64.0,
      text_engine~,
    )
    println(
      "MoUI metal text smoke emoji=\{sample} in-layer inked=\{in_group.inked} green=\{in_group.green} control=\{group_control.inked} layers=\{group_report.layers} dropped=\{group_report.text_dropped_glyphs}",
    )
    if group_control.inked != 0 {
      abort(
        "metal text smoke: a noop engine paints nothing inside a layer either",
      )
    }
    if in_group.inked == 0 || in_group.green == 0 {
      abort(
        "metal text smoke: the colour glyph did not survive the group's own composite",
      )
    }
    if group_report.layers != 1 || group_report.text_dropped_glyphs != 0 {
      abort("metal text smoke: the grouped emoji frame reports no single pass")
    }
    let red_run = metal_smoke_ink(
      width=48,
      height=48,
      commands=[metal_emoji_run(sample, red)],
      text_engine~,
    )
    let green_run = metal_smoke_ink(
      width=48,
      height=48,
      commands=[metal_emoji_run(sample, green)],
      text_engine~,
    )
    let control = metal_smoke_ink(
      width=48,
      height=48,
      commands=[metal_emoji_run(sample, red)],
      text_engine=native_noop_text_engine(),
    )
    let report = metal_frame_report(
      commands=[metal_emoji_run(sample, @core.Color::white())],
      width=48.0,
      height=48.0,
      text_engine~,
    )
    println(
      "MoUI metal text smoke emoji=\{sample} inked=\{red_run.inked} green-channel=\{red_run.green} red-channel-from-green-run=\{green_run.red} control=\{control.inked} dropped=\{report.text_dropped_glyphs}",
    )
    if control.inked != 0 {
      abort("metal text smoke: the noop engine must paint no emoji either")
    }
    if red_run.inked == 0 ||
      report.text_dropped_glyphs != 0 ||
      report.text_runs_dropped != 0 {
      abort("metal text smoke: the emoji run painted nothing or was dropped")
    }
    if red_run.green == 0 || green_run.red == 0 {
      abort(
        "metal text smoke: emoji ink carries no channel the run colour cannot produce",
      )
    }
  }
}

///|
priv struct MetalSmokeInk {
  inked : Int32
  /// Pixels lighting the green channel past the ink threshold. A run colour
  /// with `g = 0` cannot produce one.
  green : Int32
  /// The mirror of `green`, for the run tinted pure green.
  red : Int32
}

///|
fn metal_smoke_ink(
  width~ : Int32,
  height~ : Int32,
  commands~ : Array[@core.DrawCommand],
  text_engine~ : NativeTextEngine,
  scale_factor~ : Double = 1.0,
) -> MetalSmokeInk {
  let pixels = match
    metal_proof_pixels(
      width~,
      height~,
      commands~,
      clear=@core.Color::black(),
      text_engine~,
      scale_factor~,
    ) {
    Some(pixels) => pixels
    None => abort("metal text smoke needs a Metal device")
  }
  let device_width = (width.to_double() * scale_factor).to_int()
  let device_height = (height.to_double() * scale_factor).to_int()
  let total = device_width * device_height
  let mut inked = 0
  let mut green = 0
  let mut red = 0
  for index in 0.. 40 || channel_green > 40 || channel_blue > 40 {
      inked = inked + 1
    }
    if channel_green > 40 {
      green = green + 1
    }
    if channel_red > 40 {
      red = red + 1
    }
  }
  MetalSmokeInk::{ inked, green, red, }
}