 (ns promesa.core
   (:refer-clojure :exclude [delay spread some])
   (:require [cats.core :as m]
-            [cats.context :as mctx]
-            [cats.protocols :as cats]
-            [promesa.protocols :as proto]
+            [cats.context :as mc]
+            [cats.protocols :as mp]
+            [promesa.protocols :as p]
             [org.bluebird]))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Implementation
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(declare promise-monad)
+(declare promise-context)
 
 (extend-type js/Promise
-  cats/Context
-  (get-context [_] promise-monad)
-
-  cats/Extract
-  (extract [it]
-    (.value it))
-
-  IDeref
-  (-deref [it]
-    (.value it))
-
-  proto/IPromise
+  mp/Context
+  (-get-context [_] promise-context)
+
+  mp/Extract
+  (-extract [it]
+    (if (.isRejected it)
+      (.cause it)
+      (.value it)))
+
+  p/IPromise
   (-then [it cb]
     (.then it cb))
 

                  type)]
       (.catch it type cb))))

  (-finally [it cb]
    (.finally it cb))

  proto/IState
  (-resolved? [it]
    (.isFulfilled it))
  (-rejected? [it]
    (.isRejected it))
  (-pending? [it]
    (.isPending it))
  (-value [it]
    (.value it))
  (-reason [it]
    (.reason it)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Public Api

(defn promise?
  "Returns true if `p` is a primise instance."
  [p]
  (satisfies? p/IPromise p))

(defn resolved?
  "Returns true if promise `p` is already fulfilled."
  [p]
  (p/-resolved? p))

(defn fulfilled?
  "Convenience alias for the `resolved?` predicate."
  [p]
  (p/-resolved? p))

(defn rejected?
  "Returns true if promise `p` is already rejected."
  [p]
  (p/-rejected? p))

(defn pending?
  "Returns true if promise `p` is stil pending."
  [p]
  (not (p/-done? p)))

(defn done?
  "Returns true if promise `p` is already done."
  [p]
  (p/-done? p))

;; Chain operations

(defn then
  "A chain helper for promises."
  [p callback]
  (p/-then p callback))

(defn chain
  "A variadic chain operation."
  [p & funcs]
  (reduce #(then %1 %2) p funcs))

(defn catch
  "Catch all promise chain helper."
  ([p callback]
   (p/-catch p callback))
  ([p type callback]
   (p/-catch p type callback)))

;; Helpers

