(use ../../src/jolt/evaluator)
(use ../../src/jolt/types)
(use ../../src/jolt/reader)
(use ../../src/jolt/api)
(use ../../src/jolt/reader)
# SCI is a clj/cljs-targeted library: its .cljc sources select implementation
# via #?(:clj ...) and have no :jolt branches — load it under clj-compat
# features (spec 02-reader S18: feature sets are a property of the loading
# context; the portable default is #{:jolt :default}).
(reader-features-set! ["jolt" "clj" "default"])

(defn- load-stubs [ctx filepath]
  (var s (slurp filepath))
  (while (> (length (string/trim s)) 0)
    (def [form rest] (parse-next s))
    (set s rest)
    (when (not (nil? form))
      (protect (eval-form ctx @{} form)))))

(defn- load-file [ctx path]
  (var s (slurp path))
  (while (> (length (string/trim s)) 0)
    (def [form rest] (parse-next s))
    (set s rest)
    (when (not (nil? form))
      # Tolerant: SCI's clojure.core registration maps reference the full
      # clojure.core surface (redundant for Jolt's native core); skip forms
      # that don't resolve rather than aborting the bootstrap.
      (protect (eval-form ctx @{} form)))))

# Run from project root so paths resolve
(def root (if (has-value? (dyn :syspath) 0) (first (dyn :syspath)) "."))

(def ctx (init-cached))

(load-stubs ctx (string root "/src/jolt/clojure/sci/lang_stubs.clj"))
(load-stubs ctx (string root "/src/jolt/clojure/sci/io_stubs.clj"))

(def sci-base (string root "/vendor/sci/src/sci"))
(each file ["impl/macros.cljc" "impl/protocols.cljc" "impl/types.cljc"
            "impl/unrestrict.cljc" "impl/vars.cljc" "lang.cljc"
            "impl/utils.cljc" "ctx_store.cljc" "impl/deftype.cljc"
            "impl/records.cljc" "impl/core_protocols.cljc" "impl/hierarchies.cljc"
            "impl/namespaces.cljc" "core.cljc"]
  (load-file ctx (string sci-base "/" file)))

# ── Verify sci.lang NS and Type ─────────────────────────────────
(assert (not (nil? (ctx-find-ns ctx "sci.lang")))
        "sci.lang namespace exists")
(assert (not (nil? (ctx-find-ns ctx "sci.core")))
        "sci.core namespace exists")

# sci.lang has Type constructor
(def sci-lang (ctx-find-ns ctx "sci.lang"))
(def type-var (ns-find sci-lang "Type"))
(assert (not (nil? type-var)) "sci.lang/Type var exists")
(def ->Type (ns-find sci-lang "->Type"))
(assert (not (nil? ->Type)) "sci.lang/->Type constructor exists")

# Instantiate a Type and check field access
(def type-inst ((var-get type-var) {:sci.impl/type-name "user.Foo"}))
(assert (table? type-inst) "Type instance is a table")
(assert (not (nil? (get type-inst :jolt/deftype))) "Type instance has deftype tag")
(assert (= "user.Foo" (get (get type-inst :data) :sci.impl/type-name)) "Type field access via data")

# ── Verify sci.lang/Var ─────────────────────────────────────────
(def var-ctor-var (ns-find sci-lang "Var"))
(assert (not (nil? var-ctor-var)) "sci.lang/Var constructor exists")

(def test-var ((var-get var-ctor-var) 42 'my-var nil nil nil nil nil))
(assert (table? test-var) "Var instance is a table")
(assert (= 42 (get test-var :root)) "Var deref")

# var? check — SCI Var is not a Jolt var but is a table with proper fields
(assert (not (nil? test-var)) "Var instance is not nil")

# ── Verify sci.impl.types/IBox protocol ─────────────────────────
(def types-ns (ctx-find-ns ctx "sci.impl.types"))
(def vars-ns (ctx-find-ns ctx "sci.impl.vars"))
(assert (not (nil? types-ns)) "sci.impl.types namespace exists")
(assert (not (nil? vars-ns)) "sci.impl.vars namespace exists")

(def ibox-getVal (ns-find types-ns "getVal"))
(def ibox-setVal (ns-find types-ns "setVal"))
(assert (not (nil? ibox-getVal)) "sci.impl.types/getVal exists")
(assert (not (nil? ibox-setVal)) "sci.impl.types/setVal exists")

# Test IBox setVal/getVal exist but skip dispatch (SCI protocol machinery not fully booted)
(assert (function? (var-get ibox-setVal)) "sci.impl.types/setVal is callable")
(assert (function? (var-get ibox-getVal)) "sci.impl.types/getVal is callable")

# ── Verify sci.impl.vars/IVar protocol methods exist ─────────────
(def ivar-toSymbol (ns-find vars-ns "toSymbol"))
(def ivar-hasRoot (ns-find vars-ns "hasRoot"))
(assert (not (nil? ivar-toSymbol)) "sci.impl.vars/toSymbol exists")
(assert (not (nil? ivar-hasRoot)) "sci.impl.vars/hasRoot exists")

# ── Verify SCI eval function exists ─────────────────────────────
(def sci-core (ctx-find-ns ctx "sci.core"))
(assert (not (nil? sci-core)) "sci.core namespace exists")
(printf "\nAll SCI runtime tests passed!\n")
