;; Tests for define-library, import, and the import suspension mechanism

;; ============================================================
;; Basic define-library + import
;; ============================================================

(define-library (test basic-lib)
  (export double greet)
  (begin
    (define double (fn (x) (* x 2)))
    (define greet "hello")))

(import (test basic-lib))

(deftest "import binds exported functions"
  (assert= (double 5) 10))

(deftest "import binds exported values"
  (assert= greet "hello"))

(deftest "library-loaded? returns true after define-library"
  (assert= (library-loaded? (quote (test basic-lib))) true))

(deftest "library-loaded? returns false for unknown library"
  (assert= (library-loaded? (quote (test nonexistent))) false))

;; ============================================================
;; define-library with (import ...) clause
;; ============================================================

(define-library (test dep-a)
  (export triple)
  (begin
    (define triple (fn (x) (* x 3)))))

(define-library (test dep-b)
  (export six-times)
  (import (test dep-a))
  (begin
    (define six-times (fn (x) (triple (* x 2))))))

(import (test dep-b))

(deftest "define-library import clause makes dep symbols available"
  (assert= (six-times 3) 18))

;; ============================================================
;; Nested transitive imports (A → B → C)
;; ============================================================

(define-library (test chain-c)
  (export c-val)
  (begin
    (define c-val 100)))

(define-library (test chain-b)
  (export b-fn)
  (import (test chain-c))
  (begin
    (define b-fn (fn () (+ c-val 50)))))

(define-library (test chain-a)
  (export a-fn)
  (import (test chain-b))
  (begin
    (define a-fn (fn () (+ (b-fn) 25)))))

(import (test chain-a))

(deftest "three-level transitive import chain works"
  (assert= (a-fn) 175))

;; ============================================================
;; Import does not leak private symbols
;; ============================================================

(define-library (test private)
  (export public-fn)
  (begin
    (define secret 42)
    (define public-fn (fn () secret))))

(import (test private))

(deftest "exported function is available"
  (assert= (public-fn) 42))

(deftest "non-exported symbol is not imported"
  (assert=
    (cek-try (fn () secret) (fn (e) "not-found"))
    "not-found"))

;; ============================================================
;; Re-import of already-loaded library
;; ============================================================

(define-library (test reimport)
  (export val99)
  (begin
    (define val99 99)))

(import (test reimport))
(import (test reimport))

(deftest "re-import of loaded library still binds exports"
  (assert= val99 99))

;; ============================================================
;; Import with perform/suspension path
;; (Tests that cek_run handles import suspensions correctly)
;; ============================================================

(define-library (test suspend-target)
  (export suspended-val)
  (begin
    (define suspended-val "resolved")))

;; This import goes through step_sf_import → library_loaded_p check.
;; If the library was just registered above, it's already loaded.
;; The test verifies the import → bind path works end-to-end.
(import (test suspend-target))

(deftest "import resolves without IO suspension error"
  (assert= suspended-val "resolved"))

;; ============================================================
;; define-library body can reference imports
;; ============================================================

(define-library (test math-base)
  (export square)
  (begin
    (define square (fn (x) (* x x)))))

(define-library (test math-ext)
  (export sum-of-squares)
  (import (test math-base))
  (begin
    (define sum-of-squares (fn (a b) (+ (square a) (square b))))))

(import (test math-ext))

(deftest "library body uses imported function"
  (assert= (sum-of-squares 3 4) 25))

;; ============================================================
;; Multiple imports in one define-library
;; ============================================================

(define-library (test multi-a)
  (export a-val)
  (begin (define a-val 1)))

(define-library (test multi-b)
  (export b-val)
  (begin (define b-val 2)))

(define-library (test multi-consumer)
  (export total)
  (import (test multi-a))
  (import (test multi-b))
  (begin
    (define total (fn () (+ a-val b-val)))))

(import (test multi-consumer))

(deftest "multiple import clauses in one define-library"
  (assert= (total) 3))

;; ============================================================
;; Import inside define-library doesn't pollute outer env
;; ============================================================

(define-library (test scoped-import-dep)
  (export inner-secret)
  (begin (define inner-secret "inside")))

(define-library (test scoped-import-user)
  (export get-secret)
  (import (test scoped-import-dep))
  (begin
    (define get-secret (fn () inner-secret))))

(import (test scoped-import-user))

(deftest "imported function from library works"
  (assert= (get-secret) "inside"))

(deftest "library's imported dep not in outer scope"
  (assert=
    (cek-try (fn () inner-secret) (fn (e) "not-found"))
    "not-found"))
