; persist/durable — a backend whose every op crosses the kernel's IO-suspension
; boundary. Each op performs an IO request {:op "persist/..." :args (...)};
; under the real kernel `perform` suspends the CEK machine and the host (file,
; pg, ipfs-ref) services the request and resumes with the result — so the facet
; code above (log/kv/project/snapshot/compaction) never changes. The TRANSPORT
; is injectable: production passes the kernel's perform; tests pass a mock
; servicer over an in-memory disk. Same request shapes either way, so the whole
; existing facet stack runs unchanged on the mock-durable backend.
; Requires: lib/persist/backend.sx.

; request encoders — the exact payloads the durable backend performs
(define persist/req-append (fn (stream event) {:op "persist/append" :args (list stream event)}))
(define persist/req-read (fn (stream) {:op "persist/read" :args (list stream)}))
(define persist/req-last-seq (fn (stream) {:op "persist/last-seq" :args (list stream)}))
(define persist/req-streams (fn () {:op "persist/streams" :args (list)}))
(define persist/req-truncate (fn (stream n) {:op "persist/truncate" :args (list stream n)}))
(define persist/req-kv-get (fn (key) {:op "persist/kv-get" :args (list key)}))
(define persist/req-kv-put (fn (key val) {:op "persist/kv-put" :args (list key val)}))
(define persist/req-kv-delete (fn (key) {:op "persist/kv-delete" :args (list key)}))
(define persist/req-kv-has? (fn (key) {:op "persist/kv-has?" :args (list key)}))
(define persist/req-kv-keys (fn () {:op "persist/kv-keys" :args (list)}))

; a backend parameterized over a transport (req -> response)
(define persist/io-backend (fn (transport) {:truncate-through (fn (stream n) (transport (persist/req-truncate stream n))) :kv-keys (fn () (transport (persist/req-kv-keys))) :read (fn (stream) (transport (persist/req-read stream))) :kv-has? (fn (key) (transport (persist/req-kv-has? key))) :last-seq (fn (stream) (transport (persist/req-last-seq stream))) :streams (fn () (transport (persist/req-streams))) :append (fn (stream event) (transport (persist/req-append stream event))) :kv-delete (fn (key) (transport (persist/req-kv-delete key))) :kv-put (fn (key val) (transport (persist/req-kv-put key val))) :kv-get (fn (key) (transport (persist/req-kv-get key)))}))

; production backend — transport is the kernel's perform (suspends; host resumes)
(define
  persist/durable-backend
  (fn () (persist/io-backend (fn (req) (perform req)))))

; reference host: service one request against a disk (any backend protocol impl).
; This is what a real host plugs into the kernel's IO resolver, and the mock-IO
; harness for tests: it never touches a real disk, just an in-memory backend.
(define
  persist/serve
  (fn
    (disk req)
    (let
      ((op (get req :op)) (args (get req :args)))
      (cond
        ((equal? op "persist/append")
          (persist/backend-append disk (first args) (nth args 1)))
        ((equal? op "persist/read")
          (persist/backend-read disk (first args)))
        ((equal? op "persist/last-seq")
          (persist/backend-last-seq disk (first args)))
        ((equal? op "persist/streams") (persist/backend-streams disk))
        ((equal? op "persist/truncate")
          (persist/backend-truncate disk (first args) (nth args 1)))
        ((equal? op "persist/kv-get")
          (persist/backend-kv-get disk (first args)))
        ((equal? op "persist/kv-put")
          (persist/backend-kv-put disk (first args) (nth args 1)))
        ((equal? op "persist/kv-delete")
          (persist/backend-kv-delete disk (first args)))
        ((equal? op "persist/kv-has?")
          (persist/backend-kv-has? disk (first args)))
        ((equal? op "persist/kv-keys") (persist/backend-kv-keys disk))
        (else (error (str "persist/serve: unknown op " op)))))))

; mock transport: a perform-replacement that services against a disk in-process
(define
  persist/mock-transport
  (fn (disk) (fn (req) (persist/serve disk req))))

; a durable backend wired to a mock disk — exercises the full io-backend path
; (request-encode -> serve -> disk) with no suspension, so the existing facet
; suite runs against it unchanged.
(define
  persist/mock-durable
  (fn (disk) (persist/io-backend (persist/mock-transport disk))))
