             [metabase.driver :as driver]))
 
 
-(def tile-size 256)
-(def pixel-origin (float (/ tile-size 2)))
-(def pixel-per-lon-degree (float (/ tile-size 360.0)))
-(def pixel-per-lon-radian (float (/ tile-size (* 2 java.lang.Math/PI))))
+(def ^:const tile-size 256)
+(def ^:const pixel-origin (float (/ tile-size 2)))
+(def ^:const pixel-per-lon-degree (float (/ tile-size 360.0)))
+(def ^:const pixel-per-lon-radian (float (/ tile-size (* 2 java.lang.Math/PI))))
 
 (defn- radians->degrees [rad]
   (/ rad (float (/ java.lang.Math/PI 180))))

(defn- tile-lat-lon
  "Get the Latitude & Longitude of the upper left corner of a given tile"
  [x y zoom]
  (let [num-tiles (bit-shift-left 1 zoom)
        corner-x (float (/ (* x tile-size) num-tiles))
        corner-y (float (/ (* y tile-size) num-tiles))
        lon (float (/ (- corner-x pixel-origin) pixel-per-lon-degree))
        lat-radians (/ (- corner-y pixel-origin) (* pixel-per-lon-radian -1))
        lat (radians->degrees (- (* 2 (java.lang.Math/atan (java.lang.Math/exp lat-radians)))
                                   (/ java.lang.Math/PI 2)))]
    {:lat lat
     :lon lon}))


        {bot-rt-lat :lat bot-rt-lon :lon} (tile-lat-lon (+ x 1) (+ y 1) zoom)
        inside-filter ["INSIDE", lat-field-id, lon-field-id, top-lt-lat, top-lt-lon, bot-rt-lat, bot-rt-lon]]
    (update-in details [:filter]
      #(match %
        ["AND" & _]              (conj % inside-filter)
        [(_ :guard string?) & _] (conj ["AND"] % inside-filter)
        :else                    inside-filter))))


(defn- extract-points
  "Takes in a dataset query result object and pulls out the Latitude/Longitude pairs into nested `java.util.ArrayLists`.
   This is specific to the way we plan to feed data into `com.metabase.corvus.api.tiles.GoogleMapPinsOverlay`."
  [{{:keys [rows cols]} :data}]
  (try
    (if-not (> (count rows) 0)
      ;; if we have no rows then return an empty list of points
      (java.util.ArrayList. [])
      ;; otherwise we go over the data, pull out the lat/lon columns, and convert them to ArrayLists
      (let [find-col-idx (fn [special-type]
                           (->> (map-indexed (fn [idx itm] (when (= special-type (:special_type itm)) idx)) cols)
                                (filter identity)
                                first))
            lat-col-idx (find-col-idx "latitude")
            lon-col-idx (find-col-idx "longitude")]
        (->> (map (fn [row] (java.util.ArrayList. [(nth row lat-col-idx) (nth row lon-col-idx)])) rows)
             (java.util.ArrayList.))))
    (catch Throwable e
      (log/debug "CAUGHT EXCEPTION IN EXTRACT-POINTS (WHY?): " e))))


(defendpoint GET "/:zoom/:x/:y/:lat-field/:lon-field/:lat-col-idx/:lon-col-idx/"
  "This endpoints provides an image with the appropriate pins rendered given a json query.
   We evaluate the query and find the set of lat/lon pairs which are relevant and then render the appropriate ones.
   It's expected that to render a full map view several calls will be made to this endpoint in parallel."
  [zoom x y lat-field lon-field lat-col-idx lon-col-idx query :as request]
  {zoom        String->Integer
   x           String->Integer
   y           String->Integer
   lat-field   String->Integer
   lon-field   String->Integer
   lat-col-idx String->Integer
   lon-col-idx String->Integer
   query       String->Dict}
  (let [updated-query (assoc query :query (query-with-inside-filter (:query query) lat-field lon-field x y zoom))
        result (driver/dataset-query updated-query {:executed_by *current-user-id*
                                                    :synchronously true})
