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

///|
fn slice(chars : Array[Char], start : Int32, stop : Int32) -> Array[Char] {
  let out : Array[Char] = []
  for i = start; i < stop; i = i + 1 {
    out.push(chars[i])
  }
  out
}

///|
fn chars_to_string(chars : Array[Char]) -> String {
  let sb = StringBuilder()
  for c in chars {
    sb.write_char(c)
  }
  sb.to_string()
}

///|
fn pad_two(n : Int32) -> String {
  let a = if n < 0 { -n } else { n }
  if a < 10 {
    "0" + a.to_string()
  } else {
    a.to_string()
  }
}

///|
/// Format a float the way the official clients do: `+Inf`, `-Inf`, and `NaN` by
/// name; otherwise the shortest decimal that round-trips, with a `.0` on
/// integers and Go's switch to a two-digit exponent once the integer part is
/// longer than six digits (so `1000000.0` is `1e+06`, matching what a
/// Prometheus scrape expects to read).
pub fn format_float(d : Double) -> String {
  let inf = 1.0 / 0.0
  if d != d {
    return "NaN"
  }
  if d == inf {
    return "+Inf"
  }
  if d == 0.0 - inf {
    return "-Inf"
  }
  if d == 0.0 {
    if 1.0 / d < 0.0 {
      return "-0.0"
    }
    return "0.0"
  }
  let s = d.to_string()
  let chars = s.to_array()
  let mut start = 0
  let mut neg = false
  if chars.length() > 0 && chars[0] == '-' {
    neg = true
    start = 1
  }
  let mut epos = -1
  for i = start; i < chars.length(); i = i + 1 {
    if chars[i] == 'e' || chars[i] == 'E' {
      epos = i
      break
    }
  }
  let mut exp10 = 0
  let mant : Array[Char] = if epos >= 0 {
    let mut esign = 1
    let mut j = epos + 1
    if j < chars.length() && (chars[j] == '+' || chars[j] == '-') {
      if chars[j] == '-' {
        esign = -1
      }
      j = j + 1
    }
    let mut ev = 0
    while j < chars.length() {
      ev = ev * 10 + (chars[j].to_int() - '0'.to_int())
      j = j + 1
    }
    exp10 = esign * ev
    slice(chars, start, epos)
  } else {
    slice(chars, start, chars.length())
  }
  let mut dot = -1
  for i = 0; i < mant.length(); i = i + 1 {
    if mant[i] == '.' {
      dot = i
      break
    }
  }
  let int_part : Array[Char] = if dot >= 0 { slice(mant, 0, dot) } else { mant }
  let frac_part : Array[Char] = if dot >= 0 {
    slice(mant, dot + 1, mant.length())
  } else {
    []
  }
  let all : Array[Char] = int_part + frac_part
  let mut firstnz = -1
  for i = 0; i < all.length(); i = i + 1 {
    if all[i] != '0' {
      firstnz = i
      break
    }
  }
  if firstnz < 0 {
    return "0.0"
  }
  let int_len = int_part.length()
  let mut e = 0
  if firstnz < int_len {
    e = int_len - 1 - firstnz
  } else {
    e = -(firstnz - int_len + 1)
  }
  let mut digits = slice(all, firstnz, all.length())
  let mut dend = digits.length()
  while dend > 1 && digits[dend - 1] == '0' {
    dend = dend - 1
  }
  digits = slice(digits, 0, dend)
  e = e + exp10
  let mut out = ""
  if e >= -4 && e <= 15 {
    if e >= 0 {
      let int_digits_n = e + 1
      let mut ip = ""
      for i = 0; i < int_digits_n; i = i + 1 {
        if i < digits.length() {
          ip = ip + digits[i].to_string()
        } else {
          ip = ip + "0"
        }
      }
      let mut fp = ""
      for i = int_digits_n; i < digits.length(); i = i + 1 {
        fp = fp + digits[i].to_string()
      }
      if fp == "" {
        fp = "0"
      }
      out = ip + "." + fp
    } else {
      let mut z = ""
      for i = 0; i < -e - 1; i = i + 1 {
        z = z + "0"
      }
      out = "0." + z + chars_to_string(digits)
    }
  } else {
    let mut m = digits[0].to_string()
    if digits.length() > 1 {
      m = m + "." + chars_to_string(slice(digits, 1, digits.length()))
    }
    let esign = if e >= 0 { "+" } else { "-" }
    out = m + "e" + esign + pad_two(e)
  }
  if !neg {
    let mut dp = -1
    for i = 0; i < out.length(); i = i + 1 {
      if out[i] == '.' {
        dp = i
        break
      }
    }
    if dp > 6 {
      let oc = out.to_array()
      let nodot : Array[Char] = slice(oc, 0, dp) +
        slice(oc, dp + 1, oc.length())
      let mut m2 = nodot[0].to_string() +
        "." +
        chars_to_string(slice(nodot, 1, nodot.length()))
      while m2.length() > 0 && m2[m2.length() - 1] == '0' {
        m2 = m2[0:m2.length() - 1].to_owned()
      }
      if m2.length() > 0 && m2[m2.length() - 1] == '.' {
        m2 = m2[0:m2.length() - 1].to_owned()
      }
      out = m2 + "e+" + pad_two(dp - 1)
    }
  }
  if neg {
    "-" + out
  } else {
    out
  }
}