-- tools/garmin/summary_line.rail — one tab-separated line per FIT activity.
-- Pulls session (global=18) totals: date, sport, duration, distance, avg/max
-- HR, ascent, kcal, max speed. Designed for shell-loop aggregation.
--
-- Usage:
--   ./rail_native run tools/garmin/summary_line.rail <fit_path>

import "stdlib/fit.rail"
import "stdlib/fmt.rail"

-- 0 sport  1 dist_cm  2 timer_ms  3 avg_hr  4 max_hr
-- 5 ascent  6 descent  7 kcal  8 max_spd_mmps  9 num_laps
-- 10 t_start  11 t_end
sl_new _ =
  let s = arr_new 16 0
  let _ = arr_set s 0 (0 - 1)
  s

session_obs s schema buf rec_off nf arch j =
  if j >= nf then 0
  else
    let fdef = schema_field_def schema j
    let sz = schema_field_size schema j
    let bt = schema_field_type schema j
    let foff = rec_off + schema_field_offset schema j
    let dec = fit_decode_field buf foff sz bt arch
    let kind = arr_get dec 0
    let v = arr_get dec 1
    let _ = if fdef == 5 && kind == 0 then arr_set s 0 v
            else if fdef == 9 && kind == 0 then arr_set s 1 v
            else if fdef == 8 && kind == 0 then arr_set s 2 v
            else if fdef == 16 && kind == 0 && v != 255 then arr_set s 3 v
            else if fdef == 17 && kind == 0 && v != 255 then arr_set s 4 v
            else if fdef == 22 && kind == 0 && v != 65535 then arr_set s 5 v
            else if fdef == 23 && kind == 0 && v != 65535 then arr_set s 6 v
            else if fdef == 11 && kind == 0 && v != 65535 then arr_set s 7 v
            else if fdef == 14 && kind == 0 && v != 65535 then arr_set s 8 v
            else if fdef == 125 && kind == 0 && v != 4294967295 then arr_set s 8 v
            else if fdef == 25 && kind == 0 then arr_set s 9 v
            else if fdef == 2 && kind == 0 then arr_set s 10 v
            else if fdef == 253 && kind == 0 then arr_set s 11 v
            else 0
    session_obs s schema buf rec_off nf arch (j + 1)

walk fit table s cursor =
  let buf = fit_buf fit
  let endp = fit_data_end fit
  if cursor >= endp then 0
  else
    let h = arr_get buf cursor
    let after_hdr = cursor + 1
    if bit_and h 128 != 0 then 0
    else
      let local_id = bit_and h 15
      if bit_and h 64 != 0 then
        let has_dev = bit_and (shr h 5) 1
        let dr = parse_def buf after_hdr has_dev
        let schema = arr_get dr 0
        let after = arr_get dr 1
        let _ = arr_set table local_id schema
        walk fit table s after
      else
        let schema = arr_get table local_id
        if schema == 0 then 0
        else
          let body = schema_total schema
          let g = schema_global schema
          let nf = schema_nfields schema
          let arch = schema_arch schema
          let _ = if g == 18 then session_obs s schema buf after_hdr nf arch 0 else 0
          walk fit table s (after_hdr + body)

sport_short n =
  if n == 1 then "run"
  else if n == 2 then "bike"
  else if n == 5 then "swim"
  else if n == 11 then "walk"
  else if n == 17 then "hike"
  else if n == 0 then "gen"
  else cat ["s", show n]

main =
  let argv = args
  let path = if length argv >= 2 then head (tail argv) else ""
  if length (chars path) == 0 then 1
  else
    let fit = fit_load path
    if fit_valid fit == 0 then
      let _ = print (cat ["-\tinvalid\t", path])
      0
    else
      let table = arr_new 16 0
      let s = sl_new 0
      let _ = walk fit table s (fit_data_off fit)
      let dist = arr_get s 1
      let timer_ms = arr_get s 2
      let timer_s = timer_ms / 1000
      let h = timer_s / 3600
      let m = (timer_s / 60) - h * 60
      let sec = timer_s - (timer_s / 60) * 60
      let dur = if h > 0 then cat [show h, ":", zero_pad m 2, ":", zero_pad sec 2]
                else cat ["0:", zero_pad m 2, ":", zero_pad sec 2]
      let max_kmh_x100 = arr_get s 8 * 36 / 100
      let mk_int = max_kmh_x100 / 100
      let mk_frac = max_kmh_x100 - mk_int * 100
      let t_end = arr_get s 11
      let date_str = if t_end > 0 then fit_fmt_unix_utc (fit_unix_of t_end) else "-"
      let km_int = dist / 100000
      let km_frac = (dist / 1000) - km_int * 100
      let _ = print (cat [
        date_str, "\t",
        rpad (sport_short (arr_get s 0)) 4, "\t",
        dur, "\t",
        lpad (cat [show km_int, ".", zero_pad km_frac 2]) 6, " km\t",
        lpad (show (arr_get s 3)) 3, "\t",
        lpad (show (arr_get s 4)) 3, "\t",
        lpad (show (arr_get s 5)) 4, " m\t",
        lpad (show (arr_get s 7)) 4, " kcal\t",
        lpad (cat [show mk_int, ".", zero_pad mk_frac 2]) 5, " km/h"])
      0
