 (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))
 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(def ^{:no-doc true}
  promise-monad
  (reify
    cats/Functor
    (fmap [mn f mv]
      (then mv f))

    cats/Applicative
    (pure [_ v]
      (promise v))

    (fapply [_ pf pv]
      (spread (all [pf pv])
              (fn [f v]
                (f v))))

    cats/Monad
    (mreturn [_ v]
      (promise v))

    (mbind [mn mv f]
      (let [ctx mctx/*context*]
        (then mv (fn [v]
                    (m/with-monad ctx
                      (f v))))))))


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

  p/IState
  (-resolved? [it]
    (.isFulfilled it))

  (-rejected? [it]
    (.isRejected it))

  (-done? [it]
    (not (.isPending it))))

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