 (s/def :fig-opt/http-server-root string?)
 (s/def :fig-opt/server-port      integer?)
 (s/def :fig-opt/server-ip        string?)
-(s/def :fig-opt/builds           (s/+ :fig-opt/build-config))
+(s/def :fig-opt/builds           (s/* :fig-opt/build-config))
 
 
 (s/def :project-top/figwheel (strict-keys

                                       :fig-opt/server-port
                                       :fig-opt/server-ip]
                              :req-un [:fig-opt/builds]))

(comment
  




(s/def :fig-opt/housers1 string?)
(s/def :fig-opt/housers2 string?)
(s/def :fig-opt/housers3 string?)

(s/def :fig-opt/house (strict-keys
                       :opt-un [:fig-opt/housers1 
                                :fig-opt/housers2 
                                :fig-opt/housers3
                                :fig-opt/car1]))

(s/def :fig-opt/car1 string?)
(s/def :fig-opt/car2 string?)
(s/def :fig-opt/car3 string?)

(s/def :fig-opt/car (strict-keys
                      :opt-un [:fig-opt/car1
                               :fig-opt/car2
                               :fig-opt/car3]))

(s/def :fig-opt/real (strict-keys
                      :opt-un [:fig-opt/car
                               :fig-opt/house]))

;; this is really rough
(defn seq-spec? [k]
  {:pre [(keyword? k)]}
  (s/regex? (spec-from-registry k)))

(defn map-spec? [k]
  {:pre [(keyword? k)]}
  (prn k)
  (#{'strict-keys 'keys}
   (let [d (s/describe k)]
     (and (sequential? d) (first d)))))

(defn get-keys [k]
  (->> k
       s/describe
       rest
       (apply parse-keys-args)))

;; we are dealing with a datatype
;; a list of paths Monoid
;; mempty   []
;; mappend  cons
;; mconcat  concat

;; its also join and intersection
;; join         set/union
;; intersection set/intersection

;; we need to cons a value to the head of each of the lists
;; map-cons v list-of-paths 

;;


(def empty-path-set #{})
(def consable-empty-path-set #{[]})

;; f -> PathSet -> PathSet
(defn path-set-fmap [f path-set]
  (into #{} (mapv f path-set)))

(defn consable-path-set [path-set]
  (or (not-empty path-set) consable-empty-path-set))

(defn path-set-cons [v path-set]
  (path-set-fmap #(cons v %) (consable-path-set path-set)))

;; [PathSet] -> PathSet 
(defn path-set-join [list-of-path-sets]
  (apply set/union list-of-path-sets))

;; [PathSet] -> PathSet
(defn path-set-intersect [list-of-path-sets]
  (apply set/intersection list-of-path-sets))



(defn key-paths [desc]
  {:pre [(sequential? desc)]}
  (let [{:keys [known-keys k->s]} (apply parse-keys-args (rest desc))]
    (path-set-join
     (map #(path-set-cons (hash-map :ky % :ky-spec (k->s %)) (poss-path (k->s %)))
      known-keys))))

;; DecribeKeyedVals -> [DecribeVal]
(defn desc-keyed-vals [desc]
  (vals (apply hash-map (rest desc))))

;; DescribeVals -> [DescribeVal] 
(def desc-vals rest)


(defn poss-path [desc]
  #_(prn desc)
  (if (and
       (keyword? desc)
       (spec-from-registry desc))
    (poss-path (s/describe desc))
    (condp = (and (sequential? desc)
                  (first desc))
      'keys (key-paths desc)
      'strict-keys (key-paths desc)
      'or    (path-set-join (map poss-path (desc-keyed-vals desc)))
      ;; this is really the intersection paths
      'and   (path-set-intersect (map poss-path (desc-vals desc)))

      '*     (path-set-cons ::int-key (poss-path (second desc)))
      '+     (path-set-cons ::int-key (poss-path (second desc)))
      '?     (path-set-cons ::int-key (poss-path (second desc)))
      'alt   (path-set-cons ::int-key
                            (path-set-join (map poss-path (desc-keyed-vals desc))))

      
      ;; cat is a splicing operation something without a numeric path is going to get one consed on
      
      
      
      
      ;; 'cat   
      ;; else
      empty-path-set

      )))


;; regex NOTE
;; so every regex has an ::int-key because they index into a sequence
;; 

;; all compond regex operators are splicing, meaning that they strip the :int-key off
;; of the sub expression if they are regex
;; this is the equivalent of concatenation something that was a sublist becomes part of the
;; super list

(re-matches #"((r+)*)?" "rrrrrrrr")

(s/valid? (s/alt :hey even?
                 :ouch even?) [4])

(s/conform (s/cat :a even? :b (s/or :odd odd?
                                    :even even?)) [4 3])


(poss-path (s/describe (s/or :hi (s/or :hey :fig-opt/real)
                                    :bye (s/or :son :fig-opt/car)
                                    :lei (s/or :son :fig-opt/house))))

(poss-path (s/describe (s/and ;:hi (s/or :hey :fig-opt/real)
                             (s/or :son :fig-opt/car)
                             (s/or :son :fig-opt/house))))

(= (poss-path (s/describe (s/and :fig-opt/house)))
   (poss-path (s/describe (s/or :son :fig-opt/house))))

#_(poss-path (s/describe :fig-opt/real))

(defn possible-paths [rk]
  (cond (map-spec? rk)
        (when-let [{:keys [known-keys keys->specs]} (not-empty (get-keys rk))]
          (prn known-keys)
          (mapcat (fn [k]
                  (map #(cons k %)
                       (or (not-empty (possible-paths (keys->specs k)))
                           [[]])))
               known-keys))))

(comment
  (seq-spec? :fig-opt/builds)
  (s/describe :fig-opt/builds)
  
  (possible-paths :fig-opt/car)


  )


(s/def :build-config/id (s/or :string string? :keyword keyword?))
(s/def :build-config/source-paths (s/+ string?))
(s/def :build-config/assert #(or (true? %) (false? %)))
