             [structural-typing.guts.preds.annotated :refer [show-as]]
             [structural-typing.surface.oopsie :as oopsie]
             [structural-typing.guts.mechanics.canonicalizing-types :refer [canonicalize]]
-            [structural-typing.guts.paths.elements :refer [ALL]])
+            [structural-typing.guts.paths.elements :refer [ALL RANGE]])
   (:require [blancas.morph.monads :as e])
   (:use midje.sweet))
 

    (oopsie/explanations oopsies) => [":x should be `pos?`; it is `\"string\"`"]))


(fact "compiling a whole type"
  (fact "Simple case"
    (oopsie/explanations ((subject/compile-type (canonicalize {} [:a])) {}))

      (oopsie/explanations (odd-and-exists {:a "hi"})) => (just "[:a :b] must exist and be non-nil")
      (oopsie/explanations (odd-and-exists {:a {:b 2}})) => (just "[:a :b] should be `odd?`; it is `2`")
      (oopsie/explanations (odd-and-exists {:a {:b 3}})) => empty?))
  
  (fact "multiple paths in the type"
    (let [type-checker (subject/compile-type (canonicalize {} {:color string?
                                                       :point {:x integer?
                                                               :y integer?}}))]
      (oopsie/explanations (type-checker {})) => empty? ; all optional
      (oopsie/explanations (type-checker {:color "green"})) => empty?
      (oopsie/explanations (type-checker {:color 1})) => (just ":color should be `string?`; it is `1`")
      (oopsie/explanations (type-checker {:color "green"
                           :point {:x "1"
                                   :y "2"}}))
      => (just "[:point :x] should be `integer?`; it is `\"1\"`"
               "[:point :y] should be `integer?`; it is `\"2\"`"
               :in-any-order))))




(fact "a path that can't be applied produces an error"
  (fact "ALL"
    (let [type-checker (subject/compile-type (canonicalize {} [[:x ALL :y]]))]
      (type-checker {:x 1}) => (just (contains {:leaf-value nil
                                                :path [:x ALL :y]
                                                :whole-value {:x 1}}))
      (oopsie/explanations (type-checker {:x 1})) => (just "[:x ALL :y] is not a path into `{:x 1}`")
      (oopsie/explanations (type-checker {:x :a})) => (just "[:x ALL :y] is not a path into `{:x :a}`")
      
      (fact "these are fine, though"
        (oopsie/explanations (type-checker {:x [0]})) => (just "[:x 0 :y] must exist and be non-nil")
        (type-checker {:x []}) => empty?)
      
      (fact "A path containing an array complains if prefix doesn't exist"
        (oopsie/explanations (type-checker {})) => (just #":x must exist"))
      
      (fact "an unfortunate side effect of strings being collections"
        (oopsie/explanations (type-checker {:x "string"}))
        => (contains "[:x 0 :y] must exist and be non-nil"))))

  (future-fact "RANGE"
    (let [type-checker (subject/compile-type
                        (canonicalize {} 
                                      {[:a (RANGE 1 4) :b (RANGE 1 5) pos?] even?}))]
      (oopsie/explanations (type-checker {:a [:wrong :wrong
                                              {:b [1  2  2  2  2 1]}
                                              {:b [1 -1 -1 -1 -1 1]}
                                              :wrong]})) => empty?)))

    


    
