(ns eval.eval
  (:require [lumo.repl]
            [cljs.js :as cljs]
            [cljs.analyzer :as ana]
            [cljs.tools.reader :as r]
            [cljs.tagged-literals :as tags]
            [rewrite-clj.zip :as z]
            [lumo.core])
  (:import [goog.string StringBuffer]))

(def net (js/require "net"))
(def fs (js/require "fs"))

(defn readfile [path]
  (.toString (.readFileSync fs path)))

;; ==== tree navigation

(defonce zloc (atom nil))

(defn init-zloc [path]
  (let [s (readfile path)
        tz (z/of-string s)]
    (reset! zloc tz)
    :set))

(defn next-and-return []
  (swap! zloc z/next)
  (let [node (-> @zloc z/node)]
    {:sexpr (-> @zloc z/sexpr)
     :meta (meta node)}))

;; ===== eval ctx

(def eval-opts
  {:ns 'cljs.user
   :context :expr
   :def-emits-var true
   :static-fns true
   :verbose true
   :fn-invoke-direct true})

(defn eval-str [source,cb]
  (let [sb (StringBuffer.)
        normal-print cljs.core/*print-fn*]
    (binding [cljs/*eval-fn* #'lumo.repl/caching-node-eval
              cljs/*load-fn* #'lumo.repl/load
              cljs.core/*print-fn* (fn [x] (.append sb x))]
      (cljs/eval-str
        lumo.repl/st
        source
        "source name"
        eval-opts
        (fn [result]
          (binding [cljs.core/*print-fn* normal-print]
            (cb (assoc result :out (str sb)))))))))

(defn respond [data conn id]
  (binding [*out* ""]
    (eval-str (:src data)
      (fn [eval-result]
        (println eval-result)
        (let [response-str 
              (js/JSON.stringify 
                (clj->js [id 
                          (update-in eval-result [:value :sexpr] str)]))]
          (println "JSON RES" response-str)
          (.write conn response-str))))))

(defn handler [conn]
  (println "connection")
  (.on conn "data"
       (fn [x] 
         (println "GOT" x)
         (try
           (let [[id msg] (js->clj (js/JSON.parse x) :keywordize-keys true)]
            (println "parsed to" id msg)
            (println (type id))
            ; (let [res (js/JSON.stringify (clj->js [id "hello back"]))]
              ; (println res)
              ; (.write conn (str res "\n")))
            (when (:src msg)
              (respond msg conn id)))
           (catch js/Error e (println "ZUP")))))) 

(defonce server (atom nil))

(defn start-rpc-server []
  (println "starting rpc")
  (let [port 3000
        s (reset! server (.createServer net handler))
        _ (.listen @server port)]))



