; Fieldtest series-step1.1 — ring-buffer + financial-indexing + warmup.
;
; Task an LLM author is naturally given: "stream a sequence of Int
; readings into a window of size 3 and, after each push, print the
; maximum of the values currently in the window." This is the canonical
; bounded-buffer streaming task: the window only ever holds the last 3
; readings, so the running max must respect eviction (a large old value
; that has scrolled out of the window must NOT keep winning).
;
; Exercises:
;   - (new Series (con Int) 3) + auto-import (no (import series))
;   - Series.push threading the owned Series through the stream
;   - Series.at with financial indexing (0 = newest) — we scan i in
;     [0, Series.len) so warmup (fewer than 3 elements) is handled by
;     reading only the live count, never a stale slot.
;   - Series.len as the live-count bound (saturates at lookback=3).
;
; Stream: 4, 1, 7, 2, 3, 1
;   after 4      -> window {4}        max 4
;   after 1      -> window {4,1}      max 4
;   after 7      -> window {4,1,7}    max 7
;   after 2      -> window {1,7,2}    max 7   (4 evicted)
;   after 3      -> window {7,2,3}    max 7
;   after 1      -> window {2,3,1}    max 3   (7 evicted)  <-- the eviction proof
; Expected stdout (one per line): 4 4 7 7 7 3

(module series-step1_1_rolling_max

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

  ; Max over the live window: scan indices 0..len, return the largest.
  (fn window_max_step
    (type (fn-type
      (params (borrow (con Series (con Int))) (own (con Int)) (own (con Int)) (own (con Int)))
      (ret (own (con Int)))))
    (params s len i acc)
    (body
      (if (app eq i len)
        acc
        (tail-app window_max_step s len
          (app + i 1)
          (if (app gt (app Series.at s i) acc) (app Series.at s i) acc)))))

  (fn window_max
    (type (fn-type
      (params (borrow (con Series (con Int))))
      (ret (own (con Int)))))
    (params s)
    (body (app window_max_step s (app Series.len s) 0 0)))

  (fn run_stream
    (type (fn-type
      (params (own (con Series (con Int))) (own (con IntList)))
      (ret (own (con Unit))) (effects IO)))
    (params s input)
    (body
      (match input
        (case (pat-ctor INil) (do io/print_str ""))
        (case (pat-ctor ICons v rest)
          (let s_new (app Series.push s v)
            (seq
              (seq (app print (app window_max s_new)) (do io/print_str "\n"))
              (tail-app run_stream s_new rest)))))))

  (fn main
    (type (fn-type (params) (ret (own (con Unit))) (effects IO)))
    (params)
    (body
      (let s (new Series (con Int) 3)
        (app run_stream s
          (term-ctor IntList ICons 4
          (term-ctor IntList ICons 1
          (term-ctor IntList ICons 7
          (term-ctor IntList ICons 2
          (term-ctor IntList ICons 3
          (term-ctor IntList ICons 1
          (term-ctor IntList INil))))))))))))
