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

///|
/// Every face of the library in one page: encode, decode, the bytes variants,
/// the lossy one, streaming, and what a failure tells you.
///
/// `main raise` only because some of the calls below are declared to fail and
/// this page never hands them anything malformed; the last section shows the
/// handling a real program would do.
fn main raise {
  let raw = b"moonbase"

  // The same eight bytes in every encoding, in the order the table lists them.
  println(@base2.encode(raw[:]))
  println(@base8.encode(raw[:]))
  println(@base10.encode(raw[:]))
  println(@base16.encode(raw[:]))
  println(@base32.encode(raw[:]))
  println(@base36.encode(raw[:]))
  println(@base45.encode(raw[:]))
  println(@base58.encode(raw[:]))
  println(@base62.encode(raw[:]))
  println(@base64.encode(raw[:]))
  println(@base85.encode(raw[:]))

  // Two spellings of the same bytes, one padded and one not.
  println(@base64.encode(raw[:], kind=@base64.Url, padding=false))
  println(@base16.encode(raw[:], kind=@base16.Upper))

  // The variants that matter to a person reading the string rather than a
  // machine parsing it: Crockford drops the letters that look like digits, and
  // z-base-32 puts the letters a word needs at the cheap end of the alphabet.
  println(@base32.encode(raw[:], kind=@base32.Crockford))
  println(@base32.encode(raw[:], kind=@base32.Z))
  println(@base58.encode(raw[:], kind=@base58.Ripple))

  // base85 is three encodings that happen to share a width.
  println(@base85.encode(b"\x00\xff\x01\xfe"[:], kind=@base85.Z85))
  println(@base85.encode(b"\x00\x00\x00\x00"[:], kind=@base85.Ascii85))

  // A certificate fingerprint is hexadecimal with colons; the lossy decoder
  // reads it back without being told about them.
  let print = @base16.encode_colons(b"\xab\xcd\xef"[:])
  println(print)
  println(@base16.encode(@base16.decode_lossy(print)[:]))

  // A base58 address keeps its leading zero bytes as leading ones, and a
  // Bitcoin address is that plus four bytes of double SHA-256.
  println(@base58.encode(b"\x00\x00\x01"[:]))
  println(
    @base58.encode_check(
      @base16.decode("00010966776006953D5567439E5E39F86A0D273BEE")[:],
    ),
  )

  // Numbers, where leading zeros have no meaning, and the big ones that do not
  // fit an Int at all.
  println(@base36.encode_int(123456789))
  println(@base62.encode_int(123456789))
  println(
    @moonbase.encode_big(
      @bigint.BigInt::from_int(123456789),
      @moonbase.Alphabet::of("0123456789abcdef"),
    ),
  )

  // Any positional system at all, given its digits. Crockford's base32 leaves
  // out the letters a human confuses with digits.
  let crockford = @moonbase.Alphabet::of("0123456789ABCDEFGHJKMNPQRSTVWXYZ")
  println(@moonbase.encode(raw[:], crockford))

  // A stream hands over what is already decided and keeps the rest, so a split
  // anywhere gives the same answer as one call.
  let sink = @base64.sink()
  sink.write(b"moon"[:])
  sink.write(b"base"[:])
  println(sink.finish())
  let source = @base64.source()
  source.write("bW9vbm")
  println(@base64.encode(source.drain()))
  source.write("Jhc2U=")
  println(@base64.encode(source.finish()))

  // bech32 folds its prefix into the checksum, and the two variants never
  // overlap; multibase writes the encoding's name in front of the string.
  println(@bech32.encode("moonbase", raw[:]))
  println(@multibase.encode(raw[:], base=@multibase.Base58Btc))
  println(@multibase.name(@multibase.detect("zKJfFLz7PRba").unwrap()))

  // A failure says what was wrong and where, rather than just "no".
  try @base64.decode("Zm*vYg==") catch {
    failure =>
      match failure {
        Bad(at~, char~) =>
          println("bad character " + char.to_string() + " at " + at.to_string())
        Truncated(at~) => println("truncated at " + at.to_string())
        Padding(at~) => println("misplaced padding at " + at.to_string())
        Checksum(at~) => println("bad checksum at " + at.to_string())
      }
  } noraise {
    _ => println("decoded")
  }
}