; Fieldtest series-step1.2 — financial-indexing off-by-one at the wrap
; boundary + len-vs-total_count bookkeeping.
;
; Task: "keep the last 3 event codes seen on a stream; after the whole
; stream, dump the surviving window oldest-first, then report how many
; events were seen in total." This is the classic 'ring of last N' task.
;
; The interesting part is the DUMP: index 0 is the newest, so to print
; oldest-first I walk i from (len - 1) down to 0. After the buffer has
; wrapped more than once (total >> lookback), the financial index must
; still map correctly onto the underlying slot — this is the wrap-boundary
; off-by-one trap the axis calls out.
;
; total_count is the monotone "events ever seen" (does NOT saturate);
; len is the live window size (saturates at lookback=3). The task needs
; BOTH: len to bound the dump walk, total_count for the summary.
;
; Stream of 7 events: 10 20 30 40 50 60 70  (lookback 3)
;   After all 7 pushes the window holds the newest 3: 50 60 70.
;   Dumped oldest-first: 50, 60, 70.
;   total_count = 7, len = 3.
; Expected stdout (one per line): 50 60 70 then "total=" path -> 7 and 3.
; Concretely the lines are: 50  60  70  7  3

(module series-step1_2_last_n_events

  (data IntList
    (ctor INil)
    (ctor ICons (con Int) (con IntList)))

  ; Push every element of the list into the series, returning the series.
  (fn fill
    (type (fn-type
      (params (own (con Series (con Int))) (own (con IntList)))
      (ret (own (con Series (con Int))))))
    (params s input)
    (body
      (match input
        (case (pat-ctor INil) s)
        (case (pat-ctor ICons v rest)
          (tail-app fill (app Series.push s v) rest)))))

  ; Print the live window oldest-first: walk i from (len-1) down to 0.
  ; index 0 = newest, index (len-1) = oldest live element.
  (fn dump_step
    (type (fn-type
      (params (borrow (con Series (con Int))) (own (con Int)))
      (ret (own (con Unit))) (effects IO)))
    (params s i)
    (body
      (if (app lt i 0)
        (do io/print_str "")
        (seq
          (seq (app print (app Series.at s i)) (do io/print_str "\n"))
          (tail-app dump_step s (app - i 1))))))

  (fn main
    (type (fn-type (params) (ret (own (con Unit))) (effects IO)))
    (params)
    (body
      (let s0 (new Series (con Int) 3)
        (let s (app fill s0
                 (term-ctor IntList ICons 10
                 (term-ctor IntList ICons 20
                 (term-ctor IntList ICons 30
                 (term-ctor IntList ICons 40
                 (term-ctor IntList ICons 50
                 (term-ctor IntList ICons 60
                 (term-ctor IntList ICons 70
                 (term-ctor IntList INil)))))))))
          (seq
            (app dump_step s (app - (app Series.len s) 1))
            (seq
              (seq (app print (app Series.total_count s)) (do io/print_str "\n"))
              (seq (app print (app Series.len s)) (do io/print_str "\n")))))))))
