; Phase 3 — snapshots + replay. Headline: snapshot + tail == full replay.

(define snap-count (fn (acc e) (+ acc 1)))

(persist-test
  "no snapshot loads fresh seed state"
  (persist/snapshot-load (persist/open) "feed" 0)
  {:value 0 :seq 0})
(persist-test
  "snapshot-exists? false initially"
  (persist/snapshot-exists? (persist/open) "feed")
  false)
(persist-test
  "checkpoint stores a snapshot"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (persist/checkpoint b "s" "snap" snap-count 0)
      (persist/snapshot-exists? b "snap")))
  true)
(persist-test
  "checkpoint value equals full projection"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (persist/append b "s" "x" 0 {})
      (persist/append b "s" "x" 0 {})
      (persist/project-value
        (persist/checkpoint b "s" "snap" snap-count 0))))
  3)
(persist-test
  "checkpoint records the last seq"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (persist/append b "s" "x" 0 {})
      (persist/project-seq
        (persist/checkpoint b "s" "snap" snap-count 0))))
  2)
(persist-test
  "replay after checkpoint only folds the tail"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (persist/append b "s" "x" 0 {})
      (persist/checkpoint b "s" "snap" snap-count 0)
      (persist/append b "s" "x" 0 {})
      (persist/project-value
        (persist/replay b "s" "snap" snap-count 0))))
  3)
(persist-test
  "snapshot + tail == full replay (value)"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (persist/append b "s" "x" 0 {})
      (persist/checkpoint b "s" "snap" snap-count 0)
      (persist/append b "s" "x" 0 {})
      (persist/append b "s" "x" 0 {})
      (equal?
        (persist/project-value
          (persist/replay b "s" "snap" snap-count 0))
        (persist/project-fold b "s" snap-count 0))))
  true)
(persist-test
  "snapshot + tail == full replay (whole state)"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (persist/checkpoint b "s" "snap" snap-count 0)
      (persist/append b "s" "x" 0 {})
      (persist/append b "s" "x" 0 {})
      (equal?
        (persist/replay b "s" "snap" snap-count 0)
        (persist/project b "s" snap-count 0))))
  true)
(persist-test
  "replay determinism: two replays from same snapshot agree"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (persist/checkpoint b "s" "snap" snap-count 0)
      (persist/append b "s" "x" 0 {})
      (equal?
        (persist/replay b "s" "snap" snap-count 0)
        (persist/replay b "s" "snap" snap-count 0))))
  true)
(persist-test
  "re-checkpoint advances the snapshot"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (persist/checkpoint b "s" "snap" snap-count 0)
      (persist/append b "s" "x" 0 {})
      (persist/checkpoint b "s" "snap" snap-count 0)
      (persist/project-seq (persist/snapshot-load b "snap" 0))))
  2)
(persist-test
  "snapshots are keyed independently"
  (let
    ((b (persist/open)))
    (begin
      (persist/append b "s" "x" 0 {})
      (persist/checkpoint b "s" "a" snap-count 0)
      (persist/snapshot-exists? b "b")))
  false)
