   "Authentication middleware for geschichte."
   (:require [geschichte.platform-log :refer [debug info warn error]]
             [konserve.protocols :refer [IEDNAsyncKeyValueStore -assoc-in -get-in -update-in]]
+            [hasch.core :refer [uuid]]
             [clojure.set :as set]
             [postal.core :refer [send-message]]
             #+clj [clojure.core.async :as async

;;     On your backend server, verify that the code is valid and exchange it for a long-lived token, which is stored in your database and sent back to be stored on the client device as well.
;;     The user is now logged in, and doesn’t have to repeat this process again until their token expires or they want to authenticate on a new device.

(defn meta-published [pub-ch store trusted-hosts credential-fn [new-in out]]
  (let [sessions (atom {})]
    (go-loop [{:keys [metas] :as p} (<! pub-ch)]
      (when p
        (let [nc (<! (new-commits! store metas))]
          (<! (go-loop [auth-count 0]
                (let [not-auth (filter #(not (@sessions (:user %))) nc)]
                  (if (or (@trusted-hosts (:host (meta p)))
                          (empty? not-auth))
                    (do
                      (debug "AUTH" p)
                      (>! new-in (assoc p ::authed true))) ;; annotate authenticated user(s)
                    (do
                      (debug "NOT-AUTH" not-auth)
                      (>! out {:topic ::auth-required :users (set (map :user not-auth))})
                      (swap! sessions
                             (fn [old creds] (reduce #(assoc %1 (:username %2) %2) old creds))
                             (->> (<! (go-loop [p (<! pub-ch)] ;; pass through, maybe use pub?
                                        (if (= (:topic p) ::auth)
                                          p
                                          (do (>! new-in p)
                                              (recur (<! pub-ch))))))
                                  :users
                                  (map (fn [[k v]] (credential-fn {:username k :password v})))
                                  (filter (comp not nil?))))
                      (debug "NEW-SESSIONS" sessions)
                      (when (< auth-count 3)
                        (recur (inc auth-count)))))))))
        (recur (<! pub-ch))))))

(defn auth-required [auth-req-ch auth-fn out]
  (go-loop [{:keys [users] :as a} (<! auth-req-ch)]
    (when a
      (debug "AUTH-REQUIRED:" a)
      (>! out {:topic ::auth
               :users (<! (auth-fn users))})
      (recur (<! auth-req-ch)))))


(defn in-dispatch [{:keys [topic]}]
  (case topic
    :meta-pub :meta-pub
    ::auth-required ::auth-required
    :unrelated))



(comment
  (require '[konserve.store :refer [new-mem-store]])

  (let [in (chan)
        out (chan)
        [new-in new-out] (auth (<!! (new-mem-store (atom {"user@mail.com" {1 {:causal-order {10 []}}}})))
                               (fn [users] (go (zipmap users (repeat "P4ssw0rd"))))
                               (fn [token] (if (= (:password token) "P4ssw0rd")
                                            true
                                            false))
                               (atom #{})
                               [in out])]


    (go-loop [o (<!! out)]
      (when o
        (println "OUT" o)
        (recur (<!! out))))

    (go-loop [o (<!! new-in)]
      (when o
        (println "NEW-IN" o)
        (recur (<!! new-in))))

    (>!! in (with-meta {:topic :meta-pub :metas {"user@mail.com" {1 {:causal-order {10 []
                                                                                    20 [10]}}}
                                                 "eve@mail.com" {1 {:causal-order {20 []}}}}}
              {:host "127.0.0.1"}))
    (>!! in {:topic ::auth :users {"user@mail.com" "Passw0rd" "eve@mail.com" "Password"}})
    (>!! in {:topic ::auth :users {"user@mail.com" "P4ssw0rd" "eve@mail.com" "Passw0rd"}})
    (>!! in {:topic ::auth :users {"eve@mail.com" "Passw0rd"}})
    (>!! in {:topic ::auth :users {"eve@mail.com" "Passw0rd"}})
    (>!! in {:topic ::auth :users {"eve@mail.com" "Passw0rd"}})
    (>!! in {:topic ::auth :users {"eve@mail.com" "Passw0rd"}})
    (>!! in {:topic ::auth :users {"eve@mail.com" "Passw0rd"}})
    (>!! in {:topic ::auth :users {"eve@mail.com" "Passw0rd"}})
    (>!! in {:topic ::auth :users {"eve@mail.com" "Passw0rd"}})
    (>!! in {:topic ::auth :users {"eve@mail.com" "P4ssw0rd"}}))

  (println "\n")


  )
