// Copyright 2026 Leo Cheng
// SPDX-License-Identifier: Apache-2.0

///|
/// One colour, followed from the text that spells it to the numbers a terminal
/// can send, through every space this library converts between.
fn main {
  let text = "#0891b2"
  let color = match @moonrgba.Color::decode_opt(text) {
    Some(color) => color
    None => {
      println("not a colour: " + text)
      return
    }
  }
  println("read        " + text)
  println("as oklch    " + color.encode(format=@moonrgba.Format::Oklch))
  println("writes      " + color.encode())
  println("hex         " + color.encode(format=@moonrgba.Format::Hex))
  println("name        " + color.encode(format=@moonrgba.Format::Named))
  println("")

  // Every space, in the order a palette usually goes.
  let spaces : Array[@moonrgba.Space] = [
    @moonrgba.Space::Srgb,
    @moonrgba.Space::SrgbLinear,
    @moonrgba.Space::Hsl,
    @moonrgba.Space::Hsv,
    @moonrgba.Space::Hwb,
    @moonrgba.Space::Lab,
    @moonrgba.Space::Lch,
    @moonrgba.Space::Oklab,
    @moonrgba.Space::Oklch,
    @moonrgba.Space::XyzD65,
    @moonrgba.Space::XyzD50,
    @moonrgba.Space::DisplayP3,
    @moonrgba.Space::Rec2020,
    @moonrgba.Space::A98Rgb,
    @moonrgba.Space::ProPhoto,
    @moonrgba.Space::YCbCr(@moonrgba.Luma::Bt709),
  ]
  for space in spaces {
    println(pad(space.code(), 14) + color.to_space(space).encode())
  }
  // HSV and YCbCr are spaces without a CSS syntax, so the two rows above are
  // sRGB: writing them under their own names would produce a string no reader
  // accepts.
  println("")

  // The same colour on a wider display: outside sRGB, so it needs a decision.
  let p3 = @moonrgba.Color::display_p3(0.0, 0.8, 0.7)
  println("display-p3  " + p3.encode())
  println("in sRGB?    " + p3.in_gamut(space=@moonrgba.Space::Srgb).to_string())
  println("clipped     " + p3.clip(space=@moonrgba.Space::Srgb).encode())
  println("mapped      " + p3.to_gamut(space=@moonrgba.Space::Srgb).encode())
  println("")

  // Contrast against white and black, under both measures.
  let white = @moonrgba.Color::white()
  let black = @moonrgba.Color::black()
  println(
    "on white    WCAG " +
    round(color.contrast(white)) +
    "  APCA " +
    round(color.apca(white)),
  )
  println(
    "on black    WCAG " +
    round(color.contrast(black)) +
    "  APCA " +
    round(color.apca(black)),
  )
  println("")

  // How far apart two colours are, under each measure.
  let other = @moonrgba.Color::rgb(200, 90, 120)
  println("against     " + other.encode())
  for
    measure in [
      @moonrgba.Delta::E76,
      @moonrgba.Delta::E94,
      @moonrgba.Delta::E2000,
      @moonrgba.Delta::Ok,
    ] {
    println(pad("\{measure}", 10) + round(color.delta_e(other, delta=measure)))
  }
  println("")

  // The terminal: the nearest slot in each palette.
  let slot = color.to_ansi256()
  println("ansi 256    " + slot.to_string() + "  " + slot.color().encode())
  println("ansi 16     " + color.to_ansi16().to_string())
  let (r, g, b) = color.rgb8()
  println(
    "true colour " + r.to_string() + ", " + g.to_string() + ", " + b.to_string(),
  )
}

///|
/// A number as a person reads it rather than as a machine prints it.
fn round(value : Double) -> String {
  let text = (@math.round(value * 100.0) / 100.0).to_string()
  text
}

///|
fn pad(text : String, width : Int32) -> String {
  if text.length() >= width {
    return text
  }
  let out = StringBuilder()
  out.write_string(text)
  for _ in 0..<(width - text.length()) {
    out.write_char(' ')
  }
  out.to_string()
}