   (:require [futura.atomic :as atomic]
             [buddy.core.nonce :as nonce]
             [buddy.core.codecs :as codecs]
-            [catacumba.core :as ct])
+            [catacumba.impl.handlers :as handlers]
+            [catacumba.impl.context :as context])
   (:import clojure.lang.IAtom
            clojure.lang.IDeref
            clojure.lang.Counted

(defn- context->session
  [context {:keys [storage cookie-name]
            :or {cookie-name default-cookie-name}}]
  (let [cookies (ct/get-cookies context)
        cookie (get cookies (keyword cookie-name) nil)
        sid (:value cookie)]
    (if sid
      (let [data (load-data storage sid)]
        [sid (session sid data)])
      (let [sid (codecs/bytes->safebase64 (nonce/random-nonce 48))]
        [sid (session sid)]))))

(defn- patch-vary-headers
  [response])


(defn session-handler
  [{:keys [storage cookie-name]
    :or {storage :inmemory cookie-name default-cookie-name}
    :as options}]
  (let [storage (lookup-storage storage)
        options (assoc options :storage storage)]
    (fn [context]
      (let [[sid session] (context->session context options)]
        (ct/before-send context (fn [^ResponseMetaData response]
                                  (cond
                                    (empty? session)
                                    (let [cookie (-> (make-cookie sid options)
                                                     (assoc :max-age 0))]
                                      (ct/set-cookies! context {cookie-name cookie}))

                                    (modified? session)
                                    (let [cookie (make-cookie sid options)]
                                      (persist-data storage sid @session)
                                      (patch-vary-headers response)
                                      (ct/set-cookies! context {cookie-name cookie}))

                                    (accessed? session)
                                    (patch-vary-headers response))))
        (ct/delegate context {:session session})))))

  (^:private modified? [_] "Check if session is modified"))

(defprotocol ISessionStorage
  (^:private read-session [_ key] "")
  (^:private write-session [_ key data] "")
  (^:private delete-session [_ key] ""))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Types
