;; lib/commerce/cart.sx — cart as an ordered list of line items.
;;
;; A cart is a native list of lines; a line is (list sku variant qty).
;; All operations are pure: they return a new cart, never mutate. Line
;; order is insertion order (stable) so totals are reproducible.
;;
;; cart-lineo is the relational view — because a line *is* a (sku variant qty)
;; tuple, membero queries the cart directly, forward or backward.

(define empty-cart (list))

(define make-line (fn (sku variant qty) (list sku variant qty)))
(define line-sku (fn (l) (nth l 0)))
(define line-variant (fn (l) (nth l 1)))
(define line-qty (fn (l) (nth l 2)))

(define
  same-line?
  (fn
    (l sku variant)
    (and (= (line-sku l) sku) (= (line-variant l) variant))))

(define
  cart-qty
  (fn
    (cart sku variant)
    (let
      ((m (filter (fn (l) (same-line? l sku variant)) cart)))
      (if (empty? m) 0 (line-qty (first m))))))

(define
  cart-remove
  (fn
    (cart sku variant)
    (filter (fn (l) (not (same-line? l sku variant))) cart)))

;; Add qty units; merges into an existing (sku,variant) line in place,
;; otherwise appends a new line at the end.
(define
  cart-add
  (fn
    (cart sku variant qty)
    (let
      ((existing (cart-qty cart sku variant)))
      (if
        (= existing 0)
        (append cart (list (make-line sku variant qty)))
        (map
          (fn
            (l)
            (if
              (same-line? l sku variant)
              (make-line sku variant (+ existing qty))
              l))
          cart)))))

;; Set the absolute quantity; qty <= 0 removes the line.
(define
  cart-set-qty
  (fn
    (cart sku variant qty)
    (if
      (<= qty 0)
      (cart-remove cart sku variant)
      (if
        (= (cart-qty cart sku variant) 0)
        (append cart (list (make-line sku variant qty)))
        (map
          (fn
            (l)
            (if (same-line? l sku variant) (make-line sku variant qty) l))
          cart)))))

(define cart-empty? (fn (cart) (empty? cart)))
(define cart-lines (fn (cart) cart))
(define cart-skus (fn (cart) (map line-sku cart)))

;; Total number of units across all lines.
(define
  cart-count
  (fn (cart) (reduce (fn (acc l) (+ acc (line-qty l))) 0 cart)))

;; Relational view of cart lines.
(define
  cart-lineo
  (fn (cart sku variant qty) (membero (list sku variant qty) cart)))
