   (:require [cljs.nodejs :as node]
             [konserve.core :as k]
             [hasch.core :refer [uuid]]
+            [fressian-cljs.core :as fress]
             [konserve.serializers :as ser]
             [konserve.protocols :refer [PEDNAsyncKeyValueStore -exists? -get-in -update-in -assoc-in -dissoc
                                         PJSONAsyncKeyValueStore -jget-in -jassoc-in -jupdate-in
                                         PBinaryAsyncKeyValueStore -bget -bassoc
                                         -serialize -deserialize]]
+            [cljs-node-io.core :as io :refer [slurp spit]]
             [cljs.core.async :as async :refer (take! <! >! put! close! chan poll!)])
   (:require-macros [cljs.core.async.macros :refer [go go-loop]]))
 

  (-get-in [this key-vec]
    (read-edn folder (first key-vec)))
  (-update-in [this key-vec up-fn]
    (go (write-edn-key folder {:key (first key-vec) :format :edn}))
        (write-edn folder (first key-vec) up-fn))
  (-assoc-in [this key-vec val] (-update-in this key-vec (fn [_] val)))
  (-dissoc [this key]
    (let [fn (uuid key)
          res-ch (chan)]
      (delete-entry folder fn res-ch)
      res-ch)))

(defn new-fs-store
  "Filestore contains a Key and a Data Folder"

        (println err)))))

(defn write-edn-key [folder {:keys [key] :as meta}]
  (let [key       (uuid (first key))
        temp-file (str folder "/meta/" key ".new")
        new-file  (str folder "/meta/" key)
        fd        (.openSync fs new-file "w+")
        _         (.closeSync fs fd)
        ws        (.createWriteStream fs temp-file)
        res-ch (chan)]
    (.on ws "close" #(try (.renameSync fs temp-file new-file)
                          (catch js/Object err
                            (put! res-ch (ex-info "Could not write edn key."
                                                  {:type      :write-edn-key-error
                                                   :key       key
                                                   :exception err}))
                            (close! res-ch))
                          (finally (close! res-ch))))
    (.on ws "error"
         (fn [err]
           (put! res-ch (ex-info "Could not write edn key."
                                 {:type      :write-edn-key-error
                                  :key       key
                                  :exception err}))
           (close! res-ch)))
    (.write ws (js/Uint8Array. (fress/write meta)))
    (.end ws)
    res-ch))

(defn write-edn [folder key up-fn]
  (let [key       (uuid (first key))
        temp-file (str folder "/data/" key ".new")
        new-file  (str folder "/data/" key)
        res-ch    (chan)]
    (if (.existsSync fs new-file)
      (let [rs (.createReadStream fs new-file)]
        (.on rs "data" (fn [chunk]
                         (let [old (fress/read (. chunk -buffer))
                               ws  (.createWriteStream fs temp-file)
                               value     (up-fn old)]
                           (.on ws "finish" #(put! res-ch [old value]))
                           (.on ws "error"
                                (fn [err]
                                  (put! res-ch (ex-info "Could not write edn."
                                                        {:type      :write-edn-error
                                                         :key       key
                                                         :exception err}))
                                  (close! res-ch)))
                           (.write ws (js/Uint8Array. (fress/write value)))
                           (.close ws))))
        (.on rs "close" (fn [] (.renameSync fs temp-file new-file) (close! res-ch)))
        (.on rs "error" (fn [err]
                          (put! res-ch (ex-info "Could not write edn."
                                                {:type      :write-edn-error
                                                 :key       key
                                                 :exception err}))
                          (close! res-ch))))
      (let [fd        (.openSync fs new-file "w+")
            _         (.closeSync fs fd)
            ws        (.createWriteStream fs temp-file)
            value     (up-fn nil)]
        (.on ws "finish" #(put! res-ch [nil value]))
        (.on ws "close" #(try
                           (.renameSync fs temp-file new-file)
                           (catch js/Object err
                             (put! res-ch (ex-info "Could not write edn."
                                                   {:type      :write-edn-error
                                                    :key       key
                                                    :exception err}))
                             (close! res-ch))))
        (.write ws (js/Uint8Array. (fress/write value)))
        (.end ws)))
    res-ch))

(defn write-binary [folder key input]
  (let [res-ch (chan)]
    (try
      (let [fn        (uuid key)
            temp-file (str folder "/data/" fn ".new")
            new-file  (str folder "/data/" fn)
            ws        (.createWriteStream fs temp-file)
            input     (if (js/Buffer.isBuffer input)
                        (let [stream (stream.PassThrough)
                              _      (.end stream input)]
                          stream)
                        (if (instance? stream input)
                          input
                          (throw (js/Error. "Invalid input type"))))]
        (.on ws "finish" #(println "tempfile writing done"))
        (.on ws "close" #(try
                           (.renameSync fs temp-file new-file)
                           (catch js/Object err
                             (put! res-ch (ex-info "Could not write binary."
                                                   {:type      :write-binary-error
                                                    :key       key
                                                    :exception err})))
                           (finally
                             (.unpipe input ws)
                             (put! res-ch true)
                             (close! res-ch))))
        (.pipe input ws))
      (catch js/Object err
        (put! res-ch (ex-info "Could not write binary."
                              {:type      :write-binary-error
                               :key       key
                               :exception err}))
        (close! res-ch)))
    res-ch))

(defn read-edn [path key]
