/// Instants, offsets and the universal timeline.
///
/// An instant is one point on the timeline; a zone decides how that point is
/// spelled. Two moments written with different offsets can be the same instant,
/// and this file shows how to tell — and how to move between the spellings.
///
///     moon run src/examples/zones

///|
/// The offset of a moment from UTC, in minutes, as a signed number.
fn offset_minutes(m : @moondate.Moment) -> Int32 {
  match m.utcoffset() {
    Some(span) => (span.total_seconds() / 60.0).to_int()
    None => 0
  }
}

///|
fn main raise {
  // The same instant, written three ways. All three texts are different; the
  // moment behind them is not.
  let beijing = @moondate.parse("2026-09-22T14:30:00+08:00")
  let london = @moondate.parse("2026-09-22T07:30:00+01:00")
  let utc = @moondate.parse("2026-09-22T06:30:00Z")

  println(beijing)
  println(london)
  println(utc)
  println("same instant: " + (beijing.epoch() == utc.epoch()).to_string())
  println("")

  // The offsets differ, and `utcoffset` reports them as a span.
  println("beijing " + offset_minutes(beijing).to_string() + " minutes")
  println("london  " + offset_minutes(london).to_string() + " minutes")
  println("utc     " + offset_minutes(utc).to_string() + " minutes")
  println("")

  // `astimezone` rewrites the same instant in another zone. `Utc` is a value, not
  // a name to look up, and an offset is just minutes east.
  let as_utc = beijing.astimezone(@moondate.Utc).unwrap()
  println("in UTC   " + as_utc.to_string())

  let as_india = beijing.astimezone(@moondate.Offset(330)).unwrap()
  println("in +05:30 " + as_india.to_string())

  // Converting does not change the instant, only the spelling — compare the two
  // numbers above and they are the same.
  println(
    "still the same: " + (as_india.epoch() == beijing.epoch()).to_string(),
  )
  println("")

  // The other direction: a count of seconds since 1970, and a zone to read it in.
  let seconds = 1790058600L
  println(
    "from epoch, UTC   " + @moondate.Moment::of_epoch(seconds).to_string(),
  )
  println(
    "from epoch, +08:00 " +
    @moondate.Moment::of_epoch(seconds, zone=@moondate.Offset(480)).to_string(),
  )

  // `timestamp` is the same number as a float, seconds and fraction together,
  // which is what most other systems want.
  println("timestamp " + beijing.timestamp().unwrap().to_string())
  println("")

  // Subtracting two instants gives a span of real elapsed time. This is the only
  // subtraction in the library that needs both sides to sit on the timeline.
  let tomorrow = @moondate.parse("2026-09-23T06:30:00Z")
  let elapsed = tomorrow.diff(beijing).unwrap()
  println(
    "a day later minus beijing = " + elapsed.total_seconds().to_string() + " s",
  )

  // The same instant written with two different offsets subtracts to zero, which
  // is the proof that the offset is spelling and not position.
  let nothing = beijing.diff(london).unwrap()
  println(
    "beijing minus london = " + nothing.total_seconds().to_string() + " s",
  )
  println("")

  // Spans are built from named units, and only the ones you name are counted.
  let ninety = @moondate.Span::new(hours=1, minutes=30)
  println("90 minutes  = " + ninety.total_seconds().to_string() + " s")
  println("backwards   = " + ninety.neg().total_seconds().to_string() + " s")

  // Adding a span moves the instant, not the wall clock: an hour later is an hour
  // later even when the offset differs.
  let later = beijing.plus(ninety)
  println("plus 90 min " + later.to_string())
  println("plus a day  " + beijing.plus(@moondate.day).to_string())
  println("plus a nanosecond " + beijing.plus(@moondate.nanosecond).to_string())
  println("")

  // A span from named units can also be read as days, seconds and nanoseconds,
  // which is how a duration is usually stored.
  let long = @moondate.Span::new(
    days=3,
    hours=4,
    minutes=5,
    seconds=6,
    millis=7,
  )
  let (days, secs, nanos) = long.parts()
  println("days " + days.to_string())
  println("seconds " + secs.to_string())
  println("nanos " + nanos.to_string())
}