;; Phase 4 — federated documents: trust-gated peer ops + concurrent-external-
;; edit conflict resolution via the CRDT.

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

(define same? (fn (a b) (= (get a :elements) (get b :elements))))

;; base shared document, then a local edit
(define
  base
  (crdt-insert
    (crdt-insert
      (crdt-empty)
      "h"
      "heading"
      (crdt-pos 1 0)
      (list (list "level" 1) (list "text" "T"))
      1
      0)
    "p"
    "text"
    (crdt-pos 2 0)
    (list (list "text" "Body"))
    1
    0))
(define local (crdt-update base "p" "text" "local" 5 1))

;; ── provenance ──
(content-test
  "authored tags author"
  (get (content/authored (crdt-op-delete "h") "ed") :author)
  "ed")
(content-test
  "signed tags sig"
  (get (content/signed (crdt-op-delete "h") "ed" "sig1") :sig)
  "sig1")
(content-test "trusted? yes" (content/trusted? (list "ed" "al") "ed") true)
(content-test "trusted? no" (content/trusted? (list "ed") "mal") false)

;; peer ops: ed is trusted, mal is not
(define
  peer-ops
  (list
    (content/authored
      (crdt-op-update "p" "text" "peer-ed" 7 2)
      "ed")
    (content/authored
      (crdt-op-insert
        "x"
        "text"
        (crdt-pos 3 0)
        (list (list "text" "X"))
        8
        2)
      "ed")
    (content/authored (crdt-op-delete "h") "mal")))

(define res (content/merge-peer local (list "ed") peer-ops))

;; ── trust gate: only ed's ops applied ──
(content-test "accepted count" (len (content/accepted res)) 2)
(content-test "rejected count" (len (content/rejected res)) 1)
(content-test
  "rejected is mal's"
  (get (first (content/rejected res)) :author)
  "mal")

;; ── resulting document ──
(define rdoc (crdt-materialize "d" (content/peer-state res)))
(content-test "untrusted delete blocked: h survives" (doc-has? rdoc "h") true)
(content-test "trusted insert applied: x present" (doc-has? rdoc "x") true)
(content-test "result order" (doc-ids rdoc) (list "h" "p" "x"))
(content-test
  "trusted edit wins (ts7 > ts5)"
  (str (blk-send (doc-find rdoc "p") "text"))
  "peer-ed")

;; ── order-independence of accepted peer ops ──
(define res-rev (content/merge-peer local (list "ed") (reverse peer-ops)))
(content-test
  "peer merge order-independent"
  (same? (content/peer-state res) (content/peer-state res-rev))
  true)

;; ── trust = nobody → nothing applied, state unchanged ──
(define res0 (content/merge-peer local (list) peer-ops))
(content-test
  "no trust accepts none"
  (len (content/accepted res0))
  0)
(content-test
  "no trust rejects all"
  (len (content/rejected res0))
  3)
(content-test
  "no trust state unchanged"
  (same? (content/peer-state res0) local)
  true)

;; ── pluggable predicate gate (acl-on-sx hook) ──
(define
  res-pred
  (content/merge-peer-with
    local
    (fn (op) (= (get op :author) "ed"))
    peer-ops))
(content-test
  "predicate gate == list gate"
  (same? (content/peer-state res-pred) (content/peer-state res))
  true)

;; ── conflict on concurrent external edit: local vs external, same field ──
;; external (peer) state edits p concurrently with a later ts; CRDT reconciles.
(define
  external
  (crdt-update base "p" "text" "external" 9 2))
(content-test
  "conflict LWW deterministic"
  (str
    (blk-send
      (doc-find (crdt-materialize "d" (crdt-merge local external)) "p")
      "text"))
  "external")
(content-test
  "conflict merge commutes"
  (same? (crdt-merge local external) (crdt-merge external local))
  true)
(content-test
  "conflict merge idempotent"
  (same?
    (crdt-merge (crdt-merge local external) external)
    (crdt-merge local external))
  true)

;; concurrent external edit with LOWER ts loses to local
(define
  external-old
  (crdt-update base "p" "text" "stale" 3 2))
(content-test
  "older external loses to local"
  (str
    (blk-send
      (doc-find (crdt-materialize "d" (crdt-merge local external-old)) "p")
      "text"))
  "local")
