;; Extension — snapshot cache over op-log replay. The cache is transparent:
;; cached reads equal full replays.

(st-bootstrap-classes!)
(content-bootstrap-blocks!)
(content-bootstrap-doc!)

(define B (persist/open))
(define h (mk-heading "h" 1 "T"))
(define p (mk-text "p" "Body"))
(define img (mk-image "img" "/c.png" "cat"))

(content/commit! B "post" (op-insert h nil) 1)
(content/commit! B "post" (op-insert p "h") 2)
(content/commit! B "post" (op-insert img "h") 3)
(content/commit! B "post" (op-update "p" "text" "Edited") 4)

;; ── no snapshot yet: cached == full replay ──
(content-test
  "no snapshot head-cached == head"
  (doc-ids (content/head-cached B "post"))
  (doc-ids (content/head B "post")))
(content-test
  "has-snapshot? false initially"
  (content/has-snapshot? B "post")
  false)
(content-test
  "snapshot-seq 0 initially"
  (content/snapshot-seq B "post")
  0)

;; ── take a snapshot at seq 4 ──
(content-test "snapshot returns seq" (content/snapshot! B "post") 4)
(content-test "has-snapshot? true" (content/has-snapshot? B "post") true)
(content-test "snapshot-seq is 4" (content/snapshot-seq B "post") 4)

;; cached head equals full head right after snapshot
(content-test
  "head-cached == head after snap"
  (doc-ids (content/head-cached B "post"))
  (list "h" "img" "p"))
(content-test
  "head-cached p value"
  (str (blk-send (doc-find (content/head-cached B "post") "p") "text"))
  "Edited")

;; ── commit more after the snapshot; cached head replays only the tail ──
(content/commit! B "post" (op-delete "img") 5)
(content/commit! B "post" (op-insert (mk-text "q" "New") "p") 6)
(content-test
  "head-cached reflects post-snapshot ops"
  (doc-ids (content/head-cached B "post"))
  (doc-ids (content/head B "post")))
(content-test
  "head-cached order"
  (doc-ids (content/head-cached B "post"))
  (list "h" "p" "q"))

;; ── at-cached transparency across versions ──
(content-test
  "at-cached seq2 (before snap) == at"
  (doc-ids (content/at-cached B "post" 2))
  (doc-ids (content/at B "post" 2)))
(content-test
  "at-cached seq5 (after snap) == at"
  (doc-ids (content/at-cached B "post" 5))
  (doc-ids (content/at B "post" 5)))
(content-test
  "at-cached seq6 == at"
  (doc-ids (content/at-cached B "post" 6))
  (doc-ids (content/at B "post" 6)))
(content-test
  "at-cached seq4 == snapshot version"
  (doc-ids (content/at-cached B "post" 4))
  (list "h" "img" "p"))

;; ── re-snapshot moves the cache forward ──
(content-test "re-snapshot seq" (content/snapshot! B "post") 6)
(content-test
  "head-cached still correct after resnap"
  (doc-ids (content/head-cached B "post"))
  (list "h" "p" "q"))

;; ── drop snapshot falls back to full replay, same result ──
(content/drop-snapshot! B "post")
(content-test "snapshot dropped" (content/has-snapshot? B "post") false)
(content-test
  "head-cached == head after drop"
  (doc-ids (content/head-cached B "post"))
  (doc-ids (content/head B "post")))

;; ── snapshot of empty / fresh doc ──
(content-test
  "snapshot empty doc seq 0"
  (content/snapshot! B "empty")
  0)
(content-test
  "head-cached empty"
  (doc-ids (content/head-cached B "empty"))
  (list))
