;; String / Char tests — Phase 7 items 1-4.
;;
;; Covers:
;;   hk-str? / hk-str-head / hk-str-tail / hk-str-null?   (runtime helpers)
;;   chr / ord / toUpper / toLower                          (builtins in eval)
;;   cons-pattern on strings via match.sx                   (":"-intercept)
;;   empty-list pattern on strings via match.sx             ("[]"-intercept)

;; ── hk-str? predicate ────────────────────────────────────────────────────
(hk-test "hk-str? native string" (hk-str? "hello") true)

(hk-test "hk-str? empty string" (hk-str? "") true)

(hk-test "hk-str? view dict" (hk-str? {:hk-off 1 :hk-str "hi"}) true)

(hk-test "hk-str? rejects number" (hk-str? 42) false)

;; ── hk-str-null? predicate ───────────────────────────────────────────────
(hk-test "hk-str-null? empty string" (hk-str-null? "") true)

(hk-test "hk-str-null? non-empty" (hk-str-null? "a") false)

(hk-test "hk-str-null? exhausted view" (hk-str-null? {:hk-off 2 :hk-str "hi"}) true)

(hk-test "hk-str-null? live view" (hk-str-null? {:hk-off 1 :hk-str "hi"}) false)

;; ── hk-str-head ──────────────────────────────────────────────────────────
(hk-test "hk-str-head native string" (hk-str-head "hello") 104)

(hk-test "hk-str-head view at offset" (hk-str-head {:hk-off 1 :hk-str "hello"}) 101)

;; ── hk-str-tail ──────────────────────────────────────────────────────────
(hk-test "hk-str-tail of single char is nil" (hk-str-tail "h") (list "[]"))

(hk-test
  "hk-str-tail of two-char string is live view"
  (hk-str-null? (hk-str-tail "hi"))
  false)

(hk-test
  "hk-str-tail head of tail of hi is i"
  (hk-str-head (hk-str-tail "hi"))
  105)

;; ── chr / ord ────────────────────────────────────────────────────────────
(hk-test "chr 65 = A" (hk-eval-expr-source "chr 65") "A")

(hk-test "chr 104 = h" (hk-eval-expr-source "chr 104") "h")

(hk-test "ord char literal 'A' = 65" (hk-eval-expr-source "ord 'A'") 65)

(hk-test "ord char literal 'a' = 97" (hk-eval-expr-source "ord 'a'") 97)

(hk-test
  "ord of head string = char code"
  (hk-eval-expr-source "ord (head \"hello\")")
  104)

;; ── toUpper / toLower ────────────────────────────────────────────────────
(hk-test "toUpper 97 = 65 (a->A)" (hk-eval-expr-source "toUpper 97") 65)

(hk-test
  "toUpper 65 = 65 (already upper)"
  (hk-eval-expr-source "toUpper 65")
  65)

(hk-test
  "toUpper 48 = 48 (digit unchanged)"
  (hk-eval-expr-source "toUpper 48")
  48)

(hk-test "toLower 65 = 97 (A->a)" (hk-eval-expr-source "toLower 65") 97)

(hk-test
  "toLower 97 = 97 (already lower)"
  (hk-eval-expr-source "toLower 97")
  97)

(hk-test
  "toLower 48 = 48 (digit unchanged)"
  (hk-eval-expr-source "toLower 48")
  48)

;; ── Pattern matching on strings ──────────────────────────────────────────
(hk-test
  "cons pattern: head of hello = 104"
  (hk-eval-expr-source "case \"hello\" of { (x:_) -> x }")
  104)

(hk-test
  "cons pattern: tail is traversable"
  (hk-eval-expr-source "case \"hi\" of { (_:xs) -> case xs of { (y:_) -> y } }")
  105)

(hk-test
  "empty list pattern matches empty string"
  (hk-eval-expr-source "case \"\" of { [] -> True; _ -> False }")
  (list "True"))

(hk-test
  "empty list pattern fails on non-empty"
  (hk-eval-expr-source "case \"a\" of { [] -> True; _ -> False }")
  (list "False"))

(hk-test
  "cons pattern fails on empty string"
  (hk-eval-expr-source "case \"\" of { (_:_) -> True; _ -> False }")
  (list "False"))

;; ── Haskell programs using string traversal ──────────────────────────────
(hk-test
  "null prelude on empty string"
  (hk-eval-expr-source "null \"\"")
  (list "True"))

(hk-test
  "null prelude on non-empty string"
  (hk-eval-expr-source "null \"abc\"")
  (list "False"))

(hk-test
  "length of string via cons recursion"
  (hk-eval-expr-source "let { f [] = 0; f (_:xs) = 1 + f xs } in f \"hello\"")
  5)

(hk-test
  "map ord over string gives char codes"
  (hk-deep-force (hk-eval-expr-source "map ord \"abc\""))
  (list ":" 97 (list ":" 98 (list ":" 99 (list "[]")))))

(hk-test
  "map toUpper over char codes then chr"
  (hk-eval-expr-source "chr (toUpper (ord (head \"abc\")))")
  "A")

(hk-test
  "head then ord using prelude head"
  (hk-eval-expr-source "ord (head \"hello\")")
  104)
