;; content-on-sx — document metadata (title / slug / tags).
;;
;; CtDoc carries optional metadata alongside its blocks (ivars declared in
;; doc.sx). Reads go through message dispatch; setters are copy-on-write
;; (functional st-iv-set!), consistent with the immutable document model.
;;
;; Requires (loaded by harness): block.sx, doc.sx.

;; ── reads ──
(define doc-title (fn (doc) (st-send doc "title" (list))))
(define doc-slug (fn (doc) (st-send doc "slug" (list))))
(define
  doc-tags
  (fn
    (doc)
    (let ((t (st-send doc "tags" (list)))) (if (= t nil) (list) t))))

(define doc-meta (fn (doc) {:slug (doc-slug doc) :id (doc-id doc) :title (doc-title doc) :tags (doc-tags doc)}))

;; ── copy-on-write setters ──
(define doc-with-title (fn (doc title) (st-iv-set! doc "title" title)))
(define doc-with-slug (fn (doc slug) (st-iv-set! doc "slug" slug)))
(define doc-with-tags (fn (doc tags) (st-iv-set! doc "tags" tags)))

(define
  doc-add-tag
  (fn (doc tag) (doc-with-tags doc (append (doc-tags doc) (list tag)))))

;; set several at once: meta is a dict with optional :title :slug :tags
(define
  doc-with-meta
  (fn
    (doc meta)
    (let
      ((d1 (if (has-key? meta :title) (doc-with-title doc (get meta :title)) doc)))
      (let
        ((d2 (if (has-key? meta :slug) (doc-with-slug d1 (get meta :slug)) d1)))
        (if (has-key? meta :tags) (doc-with-tags d2 (get meta :tags)) d2)))))

;; constructor with metadata
(define
  doc-new-meta
  (fn (id blocks meta) (doc-with-meta (doc-new id blocks) meta)))

;; ── content/* facade aliases ──
(define content/title doc-title)
(define content/slug doc-slug)
(define content/tags doc-tags)
(define content/meta doc-meta)
(define content/with-title doc-with-title)
(define content/with-slug doc-with-slug)
(define content/with-tags doc-with-tags)
(define content/with-meta doc-with-meta)
