;; Infinite structures + Prelude tests. The lazy `:` operator builds
;; cons cells with thunked head/tail so recursive list-defining
;; functions terminate when only a finite prefix is consumed.

(define
  hk-prog-val
  (fn
    (src name)
    (hk-deep-force (get (hk-eval-program (hk-core src)) name))))

(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))))

(define
  hk-eval-list
  (fn (src) (hk-as-list (hk-eval-expr-source src))))

;; ── Prelude basics ──
(hk-test "head of literal" (hk-eval-expr-source "head [1, 2, 3]") 1)
(hk-test
  "tail of literal"
  (hk-eval-list "tail [1, 2, 3]")
  (list 2 3))
(hk-test "length" (hk-eval-expr-source "length [10, 20, 30, 40]") 4)
(hk-test "length empty" (hk-eval-expr-source "length []") 0)
(hk-test
  "map with section"
  (hk-eval-list "map (+ 1) [1, 2, 3]")
  (list 2 3 4))
(hk-test
  "filter"
  (hk-eval-list "filter (\\x -> x > 2) [1, 2, 3, 4, 5]")
  (list 3 4 5))
(hk-test
  "drop"
  (hk-eval-list "drop 2 [10, 20, 30, 40]")
  (list 30 40))
(hk-test "fst" (hk-eval-expr-source "fst (7, 9)") 7)
(hk-test "snd" (hk-eval-expr-source "snd (7, 9)") 9)
(hk-test
  "zipWith"
  (hk-eval-list "zipWith plus [1, 2, 3] [10, 20, 30]")
  (list 11 22 33))

;; ── Infinite structures ──
(hk-test
  "take from repeat"
  (hk-eval-list "take 5 (repeat 7)")
  (list 7 7 7 7 7))
(hk-test
  "take 0 from repeat returns empty"
  (hk-eval-list "take 0 (repeat 7)")
  (list))
(hk-test
  "take from iterate"
  (hk-eval-list "take 5 (iterate (\\x -> x + 1) 0)")
  (list 0 1 2 3 4))
(hk-test
  "iterate with multiplication"
  (hk-eval-list "take 4 (iterate (\\x -> x * 2) 1)")
  (list 1 2 4 8))
(hk-test
  "head of repeat"
  (hk-eval-expr-source "head (repeat 99)")
  99)

;; ── Fibonacci stream ──
(hk-test
  "first 10 Fibonacci numbers"
  (hk-eval-list "take 10 fibs")
  (list 0 1 1 2 3 5 8 13 21 34))
(hk-test
  "fib at position 8"
  (hk-eval-expr-source "head (drop 8 fibs)")
  21)

;; ── Building infinite structures in user code ──
(hk-test
  "user-defined infinite ones"
  (hk-prog-val
    "ones = 1 : ones\nresult = take 6 ones"
    "result")
  (list ":" 1 (list ":" 1 (list ":" 1 (list ":" 1 (list ":" 1 (list ":" 1 (list "[]"))))))))

(hk-test
  "user-defined nats"
  (hk-prog-val
    "nats = naturalsFrom 1\nnaturalsFrom n = n : naturalsFrom (n + 1)\nresult = take 5 nats"
    "result")
  (list ":" 1 (list ":" 2 (list ":" 3 (list ":" 4 (list ":" 5 (list "[]")))))))

;; ── Range syntax ──
(hk-test
  "finite range [1..5]"
  (hk-eval-list "[1..5]")
  (list 1 2 3 4 5))
(hk-test
  "empty range when from > to"
  (hk-eval-list "[10..3]")
  (list))
(hk-test
  "stepped range"
  (hk-eval-list "[1, 3..10]")
  (list 1 3 5 7 9))
(hk-test
  "open range — head"
  (hk-eval-expr-source "head [1..]")
  1)
(hk-test
  "open range — drop then head"
  (hk-eval-expr-source "head (drop 99 [1..])")
  100)
(hk-test
  "open range — take 5"
  (hk-eval-list "take 5 [10..]")
  (list 10 11 12 13 14))

;; ── Composing Prelude functions ──
(hk-test
  "map then filter"
  (hk-eval-list
    "filter (\\x -> x > 5) (map (\\x -> x * 2) [1, 2, 3, 4])")
  (list 6 8))

(hk-test
  "sum-via-foldless"
  (hk-prog-val
    "mySum [] = 0\nmySum (x:xs) = x + mySum xs\nresult = mySum (take 5 (iterate (\\x -> x + 1) 1))"
    "result")
  15)

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