;; map.sx — Phase 11 Data.Map: weight-balanced BST in pure SX.
;;
;; Algorithm: Adams's weight-balanced tree (the same family as Haskell's
;; Data.Map). Each node tracks its size; rotations maintain the invariant
;;
;;     size(small-side) * delta >= size(large-side)        (delta = 3)
;;
;; with single or double rotations chosen by the gamma ratio (gamma = 2).
;; The size field is an Int and is included so `size`, `lookup`, etc. are
;; O(log n) on both extremes of the tree.
;;
;; Representation:
;;   Empty → ("Map-Empty")
;;   Node  → ("Map-Node" key val left right size)
;;
;; All operations are pure SX — no mutation of nodes once constructed.
;; The user-facing Haskell layer (Phase 11 next iteration) wraps these
;; for `import Data.Map as Map`.

;; ── Constructors ────────────────────────────────────────────
(define hk-map-empty (list "Map-Empty"))

(define
  hk-map-node
  (fn
    (k v l r)
    (list "Map-Node" k v l r (+ 1 (+ (hk-map-size l) (hk-map-size r))))))

;; ── Predicates and accessors ────────────────────────────────
(define hk-map-empty? (fn (m) (and (list? m) (= (first m) "Map-Empty"))))

(define hk-map-node? (fn (m) (and (list? m) (= (first m) "Map-Node"))))

(define
  hk-map-size
  (fn (m) (cond ((hk-map-empty? m) 0) (:else (nth m 5)))))

(define hk-map-key (fn (m) (nth m 1)))
(define hk-map-val (fn (m) (nth m 2)))
(define hk-map-left (fn (m) (nth m 3)))
(define hk-map-right (fn (m) (nth m 4)))

;; ── Weight-balanced rotations ───────────────────────────────
;; delta and gamma per Adams 1992 / Haskell Data.Map.

(define hk-map-delta 3)
(define hk-map-gamma 2)

(define
  hk-map-single-l
  (fn
    (k v l r)
    (let
      ((rk (hk-map-key r))
        (rv (hk-map-val r))
        (rl (hk-map-left r))
        (rr (hk-map-right r)))
      (hk-map-node rk rv (hk-map-node k v l rl) rr))))

(define
  hk-map-single-r
  (fn
    (k v l r)
    (let
      ((lk (hk-map-key l))
        (lv (hk-map-val l))
        (ll (hk-map-left l))
        (lr (hk-map-right l)))
      (hk-map-node lk lv ll (hk-map-node k v lr r)))))

(define
  hk-map-double-l
  (fn
    (k v l r)
    (let
      ((rk (hk-map-key r))
        (rv (hk-map-val r))
        (rl (hk-map-left r))
        (rr (hk-map-right r))
        (rlk (hk-map-key (hk-map-left r)))
        (rlv (hk-map-val (hk-map-left r)))
        (rll (hk-map-left (hk-map-left r)))
        (rlr (hk-map-right (hk-map-left r))))
      (hk-map-node
        rlk
        rlv
        (hk-map-node k v l rll)
        (hk-map-node rk rv rlr rr)))))

(define
  hk-map-double-r
  (fn
    (k v l r)
    (let
      ((lk (hk-map-key l))
        (lv (hk-map-val l))
        (ll (hk-map-left l))
        (lr (hk-map-right l))
        (lrk (hk-map-key (hk-map-right l)))
        (lrv (hk-map-val (hk-map-right l)))
        (lrl (hk-map-left (hk-map-right l)))
        (lrr (hk-map-right (hk-map-right l))))
      (hk-map-node
        lrk
        lrv
        (hk-map-node lk lv ll lrl)
        (hk-map-node k v lrr r)))))

;; ── Balanced node constructor ──────────────────────────────
;; Use this in place of hk-map-node when one side may have grown
;; or shrunk by one and we need to restore the weight invariant.
(define
  hk-map-balance
  (fn
    (k v l r)
    (let
      ((sl (hk-map-size l)) (sr (hk-map-size r)))
      (cond
        ((<= (+ sl sr) 1) (hk-map-node k v l r))
        ((> sr (* hk-map-delta sl))
          (let
            ((rl (hk-map-left r)) (rr (hk-map-right r)))
            (cond
              ((< (hk-map-size rl) (* hk-map-gamma (hk-map-size rr)))
                (hk-map-single-l k v l r))
              (:else (hk-map-double-l k v l r)))))
        ((> sl (* hk-map-delta sr))
          (let
            ((ll (hk-map-left l)) (lr (hk-map-right l)))
            (cond
              ((< (hk-map-size lr) (* hk-map-gamma (hk-map-size ll)))
                (hk-map-single-r k v l r))
              (:else (hk-map-double-r k v l r)))))
        (:else (hk-map-node k v l r))))))

(define
  hk-map-singleton
  (fn (k v) (hk-map-node k v hk-map-empty hk-map-empty)))

(define
  hk-map-insert
  (fn
    (k v m)
    (cond
      ((hk-map-empty? m) (hk-map-singleton k v))
      (:else
        (let
          ((mk (hk-map-key m)))
          (cond
            ((< k mk)
              (hk-map-balance
                mk
                (hk-map-val m)
                (hk-map-insert k v (hk-map-left m))
                (hk-map-right m)))
            ((> k mk)
              (hk-map-balance
                mk
                (hk-map-val m)
                (hk-map-left m)
                (hk-map-insert k v (hk-map-right m))))
            (:else (hk-map-node k v (hk-map-left m) (hk-map-right m)))))))))

(define
  hk-map-lookup
  (fn
    (k m)
    (cond
      ((hk-map-empty? m) (list "Nothing"))
      (:else
        (let
          ((mk (hk-map-key m)))
          (cond
            ((< k mk) (hk-map-lookup k (hk-map-left m)))
            ((> k mk) (hk-map-lookup k (hk-map-right m)))
            (:else (list "Just" (hk-map-val m)))))))))

(define
  hk-map-member
  (fn
    (k m)
    (cond
      ((hk-map-empty? m) false)
      (:else
        (let
          ((mk (hk-map-key m)))
          (cond
            ((< k mk) (hk-map-member k (hk-map-left m)))
            ((> k mk) (hk-map-member k (hk-map-right m)))
            (:else true)))))))

(define hk-map-null hk-map-empty?)

(define
  hk-map-find-min
  (fn
    (m)
    (cond
      ((hk-map-empty? (hk-map-left m))
        (list (hk-map-key m) (hk-map-val m)))
      (:else (hk-map-find-min (hk-map-left m))))))

(define
  hk-map-delete-min
  (fn
    (m)
    (cond
      ((hk-map-empty? (hk-map-left m)) (hk-map-right m))
      (:else
        (hk-map-balance
          (hk-map-key m)
          (hk-map-val m)
          (hk-map-delete-min (hk-map-left m))
          (hk-map-right m))))))

(define
  hk-map-find-max
  (fn
    (m)
    (cond
      ((hk-map-empty? (hk-map-right m))
        (list (hk-map-key m) (hk-map-val m)))
      (:else (hk-map-find-max (hk-map-right m))))))

(define
  hk-map-delete-max
  (fn
    (m)
    (cond
      ((hk-map-empty? (hk-map-right m)) (hk-map-left m))
      (:else
        (hk-map-balance
          (hk-map-key m)
          (hk-map-val m)
          (hk-map-left m)
          (hk-map-delete-max (hk-map-right m)))))))

(define
  hk-map-glue
  (fn
    (l r)
    (cond
      ((hk-map-empty? l) r)
      ((hk-map-empty? r) l)
      ((> (hk-map-size l) (hk-map-size r))
        (let
          ((mp (hk-map-find-max l)))
          (hk-map-balance (first mp) (nth mp 1) (hk-map-delete-max l) r)))
      (:else
        (let
          ((mp (hk-map-find-min r)))
          (hk-map-balance (first mp) (nth mp 1) l (hk-map-delete-min r)))))))

(define
  hk-map-delete
  (fn
    (k m)
    (cond
      ((hk-map-empty? m) m)
      (:else
        (let
          ((mk (hk-map-key m)))
          (cond
            ((< k mk)
              (hk-map-balance
                mk
                (hk-map-val m)
                (hk-map-delete k (hk-map-left m))
                (hk-map-right m)))
            ((> k mk)
              (hk-map-balance
                mk
                (hk-map-val m)
                (hk-map-left m)
                (hk-map-delete k (hk-map-right m))))
            (:else (hk-map-glue (hk-map-left m) (hk-map-right m)))))))))

(define
  hk-map-from-list
  (fn
    (pairs)
    (reduce
      (fn (acc p) (hk-map-insert (first p) (nth p 1) acc))
      hk-map-empty
      pairs)))

(define
  hk-map-to-asc-list
  (fn
    (m)
    (cond
      ((hk-map-empty? m) (list))
      (:else
        (append
          (hk-map-to-asc-list (hk-map-left m))
          (cons
            (list (hk-map-key m) (hk-map-val m))
            (hk-map-to-asc-list (hk-map-right m))))))))

(define hk-map-to-list hk-map-to-asc-list)

(define
  hk-map-keys
  (fn
    (m)
    (cond
      ((hk-map-empty? m) (list))
      (:else
        (append
          (hk-map-keys (hk-map-left m))
          (cons (hk-map-key m) (hk-map-keys (hk-map-right m))))))))

(define
  hk-map-elems
  (fn
    (m)
    (cond
      ((hk-map-empty? m) (list))
      (:else
        (append
          (hk-map-elems (hk-map-left m))
          (cons (hk-map-val m) (hk-map-elems (hk-map-right m))))))))

(define
  hk-map-union-with
  (fn
    (f m1 m2)
    (reduce
      (fn
        (acc p)
        (let
          ((k (first p)) (v (nth p 1)))
          (let
            ((look (hk-map-lookup k acc)))
            (cond
              ((= (first look) "Just")
                (hk-map-insert k (f (nth look 1) v) acc))
              (:else (hk-map-insert k v acc))))))
      m1
      (hk-map-to-asc-list m2))))

(define
  hk-map-intersection-with
  (fn
    (f m1 m2)
    (reduce
      (fn
        (acc p)
        (let
          ((k (first p)) (v1 (nth p 1)))
          (let
            ((look (hk-map-lookup k m2)))
            (cond
              ((= (first look) "Just")
                (hk-map-insert k (f v1 (nth look 1)) acc))
              (:else acc)))))
      hk-map-empty
      (hk-map-to-asc-list m1))))

(define
  hk-map-difference
  (fn
    (m1 m2)
    (reduce
      (fn
        (acc p)
        (let
          ((k (first p)) (v (nth p 1)))
          (cond ((hk-map-member k m2) acc) (:else (hk-map-insert k v acc)))))
      hk-map-empty
      (hk-map-to-asc-list m1))))

(define
  hk-map-foldl-with-key
  (fn
    (f acc m)
    (cond
      ((hk-map-empty? m) acc)
      (:else
        (let
          ((acc1 (hk-map-foldl-with-key f acc (hk-map-left m))))
          (let
            ((acc2 (f acc1 (hk-map-key m) (hk-map-val m))))
            (hk-map-foldl-with-key f acc2 (hk-map-right m))))))))

(define
  hk-map-foldr-with-key
  (fn
    (f acc m)
    (cond
      ((hk-map-empty? m) acc)
      (:else
        (let
          ((acc1 (hk-map-foldr-with-key f acc (hk-map-right m))))
          (let
            ((acc2 (f (hk-map-key m) (hk-map-val m) acc1)))
            (hk-map-foldr-with-key f acc2 (hk-map-left m))))))))

(define
  hk-map-map-with-key
  (fn
    (f m)
    (cond
      ((hk-map-empty? m) m)
      (:else
        (list
          "Map-Node"
          (hk-map-key m)
          (f (hk-map-key m) (hk-map-val m))
          (hk-map-map-with-key f (hk-map-left m))
          (hk-map-map-with-key f (hk-map-right m))
          (hk-map-size m))))))

(define
  hk-map-filter-with-key
  (fn
    (p m)
    (hk-map-foldr-with-key
      (fn (k v acc) (cond ((p k v) (hk-map-insert k v acc)) (:else acc)))
      hk-map-empty
      m)))

(define
  hk-map-adjust
  (fn
    (f k m)
    (cond
      ((hk-map-empty? m) m)
      (:else
        (let
          ((mk (hk-map-key m)))
          (cond
            ((< k mk)
              (hk-map-node
                mk
                (hk-map-val m)
                (hk-map-adjust f k (hk-map-left m))
                (hk-map-right m)))
            ((> k mk)
              (hk-map-node
                mk
                (hk-map-val m)
                (hk-map-left m)
                (hk-map-adjust f k (hk-map-right m))))
            (:else
              (hk-map-node
                mk
                (f (hk-map-val m))
                (hk-map-left m)
                (hk-map-right m)))))))))

(define
  hk-map-insert-with
  (fn
    (f k v m)
    (cond
      ((hk-map-empty? m) (hk-map-singleton k v))
      (:else
        (let
          ((mk (hk-map-key m)))
          (cond
            ((< k mk)
              (hk-map-balance
                mk
                (hk-map-val m)
                (hk-map-insert-with f k v (hk-map-left m))
                (hk-map-right m)))
            ((> k mk)
              (hk-map-balance
                mk
                (hk-map-val m)
                (hk-map-left m)
                (hk-map-insert-with f k v (hk-map-right m))))
            (:else
              (hk-map-node
                mk
                (f v (hk-map-val m))
                (hk-map-left m)
                (hk-map-right m)))))))))

(define
  hk-map-insert-with-key
  (fn
    (f k v m)
    (cond
      ((hk-map-empty? m) (hk-map-singleton k v))
      (:else
        (let
          ((mk (hk-map-key m)))
          (cond
            ((< k mk)
              (hk-map-balance
                mk
                (hk-map-val m)
                (hk-map-insert-with-key f k v (hk-map-left m))
                (hk-map-right m)))
            ((> k mk)
              (hk-map-balance
                mk
                (hk-map-val m)
                (hk-map-left m)
                (hk-map-insert-with-key f k v (hk-map-right m))))
            (:else
              (hk-map-node
                mk
                (f k v (hk-map-val m))
                (hk-map-left m)
                (hk-map-right m)))))))))

(define
  hk-map-alter
  (fn
    (f k m)
    (let
      ((look (hk-map-lookup k m)))
      (let
        ((res (f look)))
        (cond
          ((= (first res) "Nothing") (hk-map-delete k m))
          (:else (hk-map-insert k (nth res 1) m)))))))
