;; map.sx — Phase 11 Data.Map unit tests.
;;
;; Tests both the SX-level `hk-map-*` helpers and the Haskell-level
;; `Map.*` aliases bound by the import handler.

(define
  hk-as-list
  (fn
    (xs)
    (cond
      ((and (list? xs) (= (first xs) "[]")) (list))
      ((and (list? xs) (= (first xs) ":"))
        (cons (nth xs 1) (hk-as-list (nth xs 2))))
      (:else xs))))

;; ── SX-level (direct hk-map-*) ───────────────────────────────
(hk-test
  "hk-map-empty: size 0, null true"
  (list (hk-map-size hk-map-empty) (hk-map-null hk-map-empty))
  (list 0 true))

(hk-test
  "hk-map-singleton: lookup hit"
  (let
    ((m (hk-map-singleton 5 "five")))
    (list (hk-map-size m) (hk-map-lookup 5 m)))
  (list 1 (list "Just" "five")))

(hk-test
  "hk-map-insert: lookup hit on inserted"
  (let ((m (hk-map-insert 1 "a" hk-map-empty))) (hk-map-lookup 1 m))
  (list "Just" "a"))

(hk-test
  "hk-map-lookup: miss returns Nothing"
  (hk-map-lookup 99 (hk-map-singleton 1 "a"))
  (list "Nothing"))

(hk-test
  "hk-map-insert: overwrites existing key"
  (let
    ((m (hk-map-insert 1 "second" (hk-map-insert 1 "first" hk-map-empty))))
    (hk-map-lookup 1 m))
  (list "Just" "second"))

(hk-test
  "hk-map-delete: removes key"
  (let
    ((m (hk-map-insert 2 "b" (hk-map-insert 1 "a" hk-map-empty))))
    (let
      ((m2 (hk-map-delete 1 m)))
      (list (hk-map-size m2) (hk-map-lookup 1 m2) (hk-map-lookup 2 m2))))
  (list 1 (list "Nothing") (list "Just" "b")))

(hk-test
  "hk-map-delete: missing key is no-op"
  (let ((m (hk-map-singleton 1 "a"))) (hk-map-size (hk-map-delete 99 m)))
  1)

(hk-test
  "hk-map-member: true on existing"
  (hk-map-member 1 (hk-map-singleton 1 "a"))
  true)

(hk-test
  "hk-map-member: false on missing"
  (hk-map-member 99 (hk-map-singleton 1 "a"))
  false)

(hk-test
  "hk-map-from-list: builds map; keys sorted"
  (hk-map-keys
    (hk-map-from-list
      (list (list 3 "c") (list 1 "a") (list 5 "e") (list 2 "b"))))
  (list 1 2 3 5))

(hk-test
  "hk-map-from-list: duplicates — last wins"
  (hk-map-lookup
    1
    (hk-map-from-list (list (list 1 "first") (list 1 "second"))))
  (list "Just" "second"))

(hk-test
  "hk-map-to-asc-list: ordered traversal"
  (hk-map-to-asc-list
    (hk-map-from-list (list (list 3 "c") (list 1 "a") (list 2 "b"))))
  (list (list 1 "a") (list 2 "b") (list 3 "c")))

(hk-test
  "hk-map-elems: in key order"
  (hk-map-elems
    (hk-map-from-list (list (list 3 30) (list 1 10) (list 2 20))))
  (list 10 20 30))

(hk-test
  "hk-map-union-with: combines duplicates"
  (hk-map-to-asc-list
    (hk-map-union-with
      (fn (a b) (str a "+" b))
      (hk-map-from-list (list (list 1 "a") (list 2 "b")))
      (hk-map-from-list (list (list 2 "B") (list 3 "c")))))
  (list (list 1 "a") (list 2 "b+B") (list 3 "c")))

(hk-test
  "hk-map-intersection-with: keeps shared keys"
  (hk-map-to-asc-list
    (hk-map-intersection-with
      +
      (hk-map-from-list (list (list 1 10) (list 2 20)))
      (hk-map-from-list (list (list 2 200) (list 3 30)))))
  (list (list 2 220)))

(hk-test
  "hk-map-difference: drops m2 keys"
  (hk-map-keys
    (hk-map-difference
      (hk-map-from-list (list (list 1 "a") (list 2 "b") (list 3 "c")))
      (hk-map-from-list (list (list 2 "x")))))
  (list 1 3))

(hk-test
  "hk-map-foldl-with-key: in-order accumulate"
  (hk-map-foldl-with-key
    (fn (acc k v) (str acc k v))
    ""
    (hk-map-from-list (list (list 3 "c") (list 1 "a") (list 2 "b"))))
  "1a2b3c")

(hk-test
  "hk-map-map-with-key: transforms values"
  (hk-map-to-asc-list
    (hk-map-map-with-key
      (fn (k v) (* k v))
      (hk-map-from-list (list (list 2 10) (list 3 100)))))
  (list (list 2 20) (list 3 300)))

(hk-test
  "hk-map-filter-with-key: keeps matches"
  (hk-map-keys
    (hk-map-filter-with-key
      (fn (k v) (> k 1))
      (hk-map-from-list (list (list 1 "a") (list 2 "b") (list 3 "c")))))
  (list 2 3))

(hk-test
  "hk-map-adjust: applies f to existing"
  (hk-map-lookup
    1
    (hk-map-adjust (fn (v) (* v 10)) 1 (hk-map-singleton 1 5)))
  (list "Just" 50))

(hk-test
  "hk-map-insert-with: combines on existing"
  (hk-map-lookup 1 (hk-map-insert-with + 1 5 (hk-map-singleton 1 10)))
  (list "Just" 15))

(hk-test
  "hk-map-alter: Nothing → delete"
  (hk-map-size
    (hk-map-alter
      (fn (mv) (list "Nothing"))
      1
      (hk-map-from-list (list (list 1 "a") (list 2 "b")))))
  1)

;; ── Haskell-level (Map.*) via import wiring ─────────────────
(hk-test
  "Map.size after Map.insert chain"
  (hk-deep-force
    (hk-run
      "import qualified Data.Map as Map\nmain = Map.size (Map.insert 2 \"b\" (Map.insert 1 \"a\" Map.empty))"))
  2)

(hk-test
  "Map.lookup hit"
  (hk-deep-force
    (hk-run
      "import qualified Data.Map as Map\nmain = Map.lookup 1 (Map.insert 1 \"a\" Map.empty)"))
  (list "Just" "a"))

(hk-test
  "Map.lookup miss"
  (hk-deep-force
    (hk-run
      "import qualified Data.Map as Map\nmain = Map.lookup 99 (Map.insert 1 \"a\" Map.empty)"))
  (list "Nothing"))

(hk-test
  "Map.member true"
  (hk-deep-force
    (hk-run
      "import qualified Data.Map as Map\nmain = Map.member 5 (Map.insert 5 \"x\" Map.empty)"))
  (list "True"))

{:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}
