                                     "/topics" :route9
                                     "/bookmarks/followers" :test/route10
                                     "/devices" {"" :route15
-                                                "/bulk" :test/route21
+                                                #_#_"/bulk" :test/route21
                                                 ["/" :client-id] :test/route35
                                                 ["/" :client-id "/reset-password"] :test/route49}
                                     "/device-errors" :test/route22

;; Perf tests
;;

(def opensensors-routes
  [["/v2/whoami" :test/route1]
   ["/v2/users/:user-id/datasets" :test/route2]
   ["/v2/public/projects/:project-id/datasets" :test/route3]
   ["/v1/public/topics/:topic" :test/route4]
   ["/v1/users/:user-id/orgs/:org-id" :test/route5]
   ["/v1/search/topics/:term" :test/route6]
   ["/v1/users/:user-id/invitations" :test/route7]
   ["/v1/orgs/:org-id/devices/:batch/:type" :test/route8]
   ["/v1/users/:user-id/topics" :test/route9]
   ["/v1/users/:user-id/bookmarks/followers" :test/route10]
   ["/v2/datasets/:dataset-id" :test/route11]
   ["/v1/orgs/:org-id/usage-stats" :test/route12]
   ["/v1/orgs/:org-id/devices/:client-id" :test/route13]
   ["/v1/messages/user/:user-id" :test/route14]
   ["/v1/users/:user-id/devices" :test/route15]
   ["/v1/public/users/:user-id" :test/route16]
   ["/v1/orgs/:org-id/errors" :test/route17]
   ["/v1/public/orgs/:org-id" :test/route18]
   ["/v1/orgs/:org-id/invitations" :test/route19]
   ["/v2/public/messages/dataset/bulk" :test/route20]
   ["/v1/users/:user-id/devices/bulk" :test/route21]
   ["/v1/users/:user-id/device-errors" :test/route22]
   ["/v2/login" :test/route23]
   ["/v1/users/:user-id/usage-stats" :test/route24]
   ["/v2/users/:user-id/devices" :test/route25]
   ["/v1/users/:user-id/claim-device/:client-id" :test/route26]
   ["/v2/public/projects/:project-id" :test/route27]
   ["/v2/public/datasets/:dataset-id" :test/route28]
   ["/v2/users/:user-id/topics/bulk" :test/route29]
   ["/v1/messages/device/:client-id" :test/route30]
   ["/v1/users/:user-id/owned-orgs" :test/route31]
   ["/v1/topics/:topic" :test/route32]
   ["/v1/users/:user-id/bookmark/:topic" :test/route33]
   ["/v1/orgs/:org-id/members/:user-id" :test/route34]
   ["/v1/users/:user-id/devices/:client-id" :test/route35]
   ["/v1/users/:user-id" :test/route36]
   ["/v1/orgs/:org-id/devices" :test/route37]
   ["/v1/orgs/:org-id/members" :test/route38]
   ["/v1/orgs/:org-id/members/invitation-data/:user-id" :test/route39]
   ["/v2/orgs/:org-id/topics" :test/route40]
   ["/v1/whoami" :test/route41]
   ["/v1/orgs/:org-id" :test/route42]
   ["/v1/users/:user-id/api-key" :test/route43]
   ["/v2/schemas" :test/route44]
   ["/v2/users/:user-id/topics" :test/route45]
   ["/v1/orgs/:org-id/confirm-membership/:token" :test/route46]
   ["/v2/topics/:topic" :test/route47]
   ["/v1/messages/topic/:topic" :test/route48]
   ["/v1/users/:user-id/devices/:client-id/reset-password" :test/route49]
   ["/v2/topics" :test/route50]
   ["/v1/login" :test/route51]
   ["/v1/users/:user-id/orgs" :test/route52]
   ["/v2/public/messages/dataset/:dataset-id" :test/route53]
   ["/v1/topics" :test/route54]
   ["/v1/orgs" :test/route55]
   ["/v1/users/:user-id/bookmarks" :test/route56]
   ["/v1/orgs/:org-id/topics" :test/route57]])

(def opensensors-bidi-routes
  ["/" {"v1/" {"public/" {["topics/" :topic] :test/route4

              "topics" [:test/route50]}}))

(def opensensors-compojure-api-routes
  (routes
    (context "/v1" []
             (context "/public" []
                      (ANY "/topics/:topic" [] {:name :test/route4} handler)
                      (ANY "/users/:user-id" [] {:name :test/route16} handler)
                      (ANY "/orgs/:org-id" [] {:name :test/route18} handler))
             (context "/users/:user-id" []
                      (ANY "/orgs/:org-id" [] {:name :test/route5} handler)
                      (ANY "/invitations" [] {:name :test/route7} handler)
                      (ANY "/topics" [] {:name :test/route9} handler)
                      (ANY "/bookmarks/followers" [] {:name :test/route10} handler)
                      (context "/devices" []
                               (ANY "/" [] {:name :test/route15} handler)
                               #_(ANY "/bulk" [] {:name :test/route21} handler)
                               (ANY "/:client-id" [] {:name :test/route35} handler)
                               (ANY "/:client-id/reset-password" [] {:name :test/route49} handler))
                      (ANY "/device-errors" [] {:name :test/route22} handler)
                      (ANY "/usage-stats" [] {:name :test/route24} handler)
                      (ANY "/claim-device/:client-id" [] {:name :test/route26} handler)
                      (ANY "/owned-orgs" [] {:name :test/route31} handler)
                      (ANY "/bookmark/:topic" [] {:name :test/route33} handler)
                      (ANY "/" [] {:name :test/route36} handler)
                      (ANY "/orgs" [] {:name :test/route52} handler)
                      (ANY "/api-key" [] {:name :test/route43} handler)
                      (ANY "/bookmarks" [] {:name :test/route56} handler))
             (ANY "/search/topics/:term" [] {:name :test/route6} handler)
             (context "/orgs" []
                      (ANY "/" [] {:name :test/route55} handler)
                      (context "/:org-id" []
                               (context "/devices" []
                                        (ANY "/" [] {:name :test/route37} handler)
                                        (ANY "/:device-id" [] {:name :test/route13} handler)
                                        #_(ANY "/:batch/:type" [] {:name :test/route8} handler))
                               (ANY "/usage-stats" [] {:name :test/route12} handler)
                               (ANY "/invitations" [] {:name :test/route19} handler)
                               (context "/members" []
                                        (ANY "/:user-id" [] {:name :test/route34} handler)
                                        (ANY "/" [] {:name :test/route38} handler)
                                        #_(ANY "/invitation-data/:user-id" [] {:name :test/route39} handler))
                               (ANY "/errors" [] {:name :test/route17} handler)
                               (ANY "/" [] {:name :test/route42} handler)
                               (ANY "/confirm-membership/:token" [] {:name :test/route46} handler)
                               (ANY "/topics" [] {:name :test/route57} handler)))
             (context "/messages" []
                      (ANY "/user/:user-id" [] {:name :test/route14} handler)
                      (ANY "/device/:client-id" [] {:name :test/route30} handler)
                      (ANY "/topic/:topic" [] {:name :test/route48} handler))
             (context "/topics" []
                      (ANY "/:topic" [] {:name :test/route32} handler)
                      (ANY "/" [] {:name :test/route54} handler))
             (ANY "/whoami" [] {:name :test/route41} handler)
             (ANY "/login" [] {:name :test/route51} handler))
    (context "/v2" []
             (ANY "/whoami" [] {:name :test/route1} handler)
             (context "/users/:user-id" []
                      (ANY "/datasets" [] {:name :test/route2} handler)
                      (ANY "/devices" [] {:name :test/route25} handler)
                      (context "/topics" []
                               (ANY "/bulk" [] {:name :test/route29} handler)
                               (ANY "/" [] {:name :test/route54} handler))
                      (ANY "/" [] {:name :test/route45} handler))
             (context "/public" []
                      (context "/projects/:project-id" []
                               (ANY "/datasets" [] {:name :test/route3} handler)
                               (ANY "/" [] {:name :test/route27} handler))
                      (ANY "/messages/dataset/bulk" [] {:name :test/route20} handler)
                      (ANY "/datasets/:dataset-id" [] {:name :test/route28} handler)
                      (ANY "/messages/dataset/:dataset-id" [] {:name :test/route53} handler))
             (ANY "/datasets/:dataset-id" [] {:name :test/route11} handler)
             (ANY "/login" [] {:name :test/route23} handler)
             (ANY "/orgs/:org-id/topics" [] {:name :test/route40} handler)
             (ANY "/schemas" [] {:name :test/route44} handler)
             (ANY "/topics/:topic" [] {:name :test/route47} handler)
             (ANY "/topics" [] {:name :test/route50} handler))))

(def opensensors-pedestal-routes
  (map-tree/router
    (table/table-routes
      [["/v2/whoami" :get handler :route-name :test/route1]
       ["/v2/users/:user-id/datasets" :get handler :route-name :test/route2]
       ["/v2/public/projects/:project-id/datasets" :get handler :route-name :test/route3]
       ["/v1/public/topics/:topic" :get handler :route-name :test/route4]
       ["/v1/users/:user-id/orgs/:org-id" :get handler :route-name :test/route5]
       ["/v1/search/topics/:term" :get handler :route-name :test/route6]
       ["/v1/users/:user-id/invitations" :get handler :route-name :test/route7]
       #_["/v1/orgs/:org-id/devices/:batch/:type" :get handler :route-name :test/route8]
       ["/v1/users/:user-id/topics" :get handler :route-name :test/route9]
       ["/v1/users/:user-id/bookmarks/followers" :get handler :route-name :test/route10]
       ["/v2/datasets/:dataset-id" :get handler :route-name :test/route11]
       ["/v1/orgs/:org-id/usage-stats" :get handler :route-name :test/route12]
       ["/v1/orgs/:org-id/devices/:client-id" :get handler :route-name :test/route13]
       ["/v1/messages/user/:user-id" :get handler :route-name :test/route14]
       ["/v1/users/:user-id/devices" :get handler :route-name :test/route15]
       ["/v1/public/users/:user-id" :get handler :route-name :test/route16]
       ["/v1/orgs/:org-id/errors" :get handler :route-name :test/route17]
       ["/v1/public/orgs/:org-id" :get handler :route-name :test/route18]
       ["/v1/orgs/:org-id/invitations" :get handler :route-name :test/route19]
       ["/v2/public/messages/dataset/bulk" :get handler :route-name :test/route20]
       #_["/v1/users/:user-id/devices/bulk" :get handler :route-name :test/route21]
       ["/v1/users/:user-id/device-errors" :get handler :route-name :test/route22]
       ["/v2/login" :get handler :route-name :test/route23]
       ["/v1/users/:user-id/usage-stats" :get handler :route-name :test/route24]
       ["/v2/users/:user-id/devices" :get handler :route-name :test/route25]
       ["/v1/users/:user-id/claim-device/:client-id" :get handler :route-name :test/route26]
       ["/v2/public/projects/:project-id" :get handler :route-name :test/route27]
       ["/v2/public/datasets/:dataset-id" :get handler :route-name :test/route28]
       ["/v2/users/:user-id/topics/bulk" :get handler :route-name :test/route29]
       ["/v1/messages/device/:client-id" :get handler :route-name :test/route30]
       ["/v1/users/:user-id/owned-orgs" :get handler :route-name :test/route31]
       ["/v1/topics/:topic" :get handler :route-name :test/route32]
       ["/v1/users/:user-id/bookmark/:topic" :get handler :route-name :test/route33]
       ["/v1/orgs/:org-id/members/:user-id" :get handler :route-name :test/route34]
       ["/v1/users/:user-id/devices/:client-id" :get handler :route-name :test/route35]
       ["/v1/users/:user-id" :get handler :route-name :test/route36]
       ["/v1/orgs/:org-id/devices" :get handler :route-name :test/route37]
       ["/v1/orgs/:org-id/members" :get handler :route-name :test/route38]
       #_["/v1/orgs/:org-id/members/invitation-data/:user-id" :get handler :route-name :test/route39]
       ["/v2/orgs/:org-id/topics" :get handler :route-name :test/route40]
       ["/v1/whoami" :get handler :route-name :test/route41]
       ["/v1/orgs/:org-id" :get handler :route-name :test/route42]
       ["/v1/users/:user-id/api-key" :get handler :route-name :test/route43]
       ["/v2/schemas" :get handler :route-name :test/route44]
       ["/v2/users/:user-id/topics" :get handler :route-name :test/route45]
       ["/v1/orgs/:org-id/confirm-membership/:token" :get handler :route-name :test/route46]
       ["/v2/topics/:topic" :get handler :route-name :test/route47]
       ["/v1/messages/topic/:topic" :get handler :route-name :test/route48]
       ["/v1/users/:user-id/devices/:client-id/reset-password" :get handler :route-name :test/route49]
       ["/v2/topics" :get handler :route-name :test/route50]
       ["/v1/login" :get handler :route-name :test/route51]
       ["/v1/users/:user-id/orgs" :get handler :route-name :test/route52]
       ["/v2/public/messages/dataset/:dataset-id" :get handler :route-name :test/route53]
       ["/v1/topics" :get handler :route-name :test/route54]
       ["/v1/orgs" :get handler :route-name :test/route55]
       ["/v1/users/:user-id/bookmarks" :get handler :route-name :test/route56]
       ["/v1/orgs/:org-id/topics" :get handler :route-name :test/route57]])))

(comment
  (pedestal/find-route
    (map-tree/router
      (table/table-routes
        [["/v1/orgs/:org-id/members/:user-id" :get (constantly "") :route-name :test/route34]
         ["/v1/orgs/:org-id/members/invitation-data/:user-id" :get (constantly "") :route-name :test/route39]]))
    {:path-info "/v1/orgs/0/members/invitation-data/1" :request-method :get})

  (require '[io.pedestal.http.route.definition.table :as table])
  (require '[io.pedestal.http.route.map-tree :as map-tree])
  (require '[io.pedestal.http.route.router :as pedestal])

  (pedestal/find-route
    (map-tree/router
      (table/table-routes
        [["/:a" :get (constantly "") :route-name ::ping]
         ["/evil/ping" :get (constantly "") :route-name ::evil-ping]]))
    {:path-info "/evil/ping" :request-method :get}))

(doseq [route (valid-urls (reitit/router opensensors-routes))]
  (let [match (pedestal/find-route opensensors-pedestal-routes {:path-info route :request-method :get})]
    (if-not match
      (println route))))

(comment
  (bench opensensors-routes false)
  (bench opensensors-routes true))

(comment

  (doseq [route (valid-urls (reitit/router opensensors-routes))]
    (let [app (ring/ring-handler (reitit/router opensensors-routes))
          match (app {:uri route :request-method :get})]
      (if-not match
        (println route))))

  (doseq [route (valid-urls (reitit/router opensensors-routes))]
    (let [match (bidi/match-route opensensors-bidi-routes route)]
      (if-not match
        (println route))))

  (doseq [route (valid-urls (reitit/router opensensors-routes))]
    (let [match (ataraxy/matches opensensors-ataraxy-routes {:uri route})]
      (if-not match
        (println route))))

  (doseq [route (valid-urls (reitit/router opensensors-routes))]
    (let [match (opensensors-compojure-api-routes {:uri route :request-method :get})]
      (if-not match
        (println route))))

  (doseq [route (valid-urls (reitit/router opensensors-routes))]
    (let [match (pedestal/find-route opensensors-pedestal-routes {:path-info route :request-method :get})]
      (if-not match
        (println route)))))

(defn bench! [routes name f]
  (System/gc)
  (println)
  (suite name)
  (println)
  (let [times (for [[path time] (bench-routes routes f)]
                (do
                  (println (format "%7s" time) "\t" path)
                  time))]
    (title (str "average: " (int (/ (reduce + times) (count times)))))))

(defn bench-all! []
  (let [routes opensensors-routes
        router (reitit/router routes)
        reitit-f #(reitit/match-by-path router %)
        reitit-ring-f (let [app (ring/ring-handler (reitit/router opensensors-routes))]
                        #(app {:uri % :request-method :get}))
        bidi-f #(bidi/match-route opensensors-bidi-routes %)
        ataraxy-f #(ataraxy/matches opensensors-ataraxy-routes {:uri %})
        compojure-api-f #(opensensors-compojure-api-routes {:uri % :request-method :get})
        pedestal-f #(pedestal/find-route opensensors-pedestal-routes {:path-info % :request-method :get})]

    (bench! routes "reitit" reitit-f)                       ;;  2538ns    10%
    (bench! routes "pedestal" pedestal-f)                   ;;  2737ns    11%
    (bench! routes "reitit-ring" reitit-ring-f)             ;;  2845ns    11%
    (bench! routes "compojure-api" compojure-api-f)         ;; 10215ns    41%
    (bench! routes "bidi" bidi-f)                           ;; 19298ns    77%
    (bench! routes "ataraxy" ataraxy-f)                     ;; 24950ns   100%

    ))

(comment
  (bench-all!))
