 (ns cmr.search.data.query-to-elastic
   "Defines protocols and functions to map from a query model to elastic search query"
   (:require [clojurewerkz.elastisch.query :as q]
-            [clojure.string :as s]
+            [clojure.string :as str]
             [cmr.search.models.query :as qm]
             [cmr.search.data.datetime-helper :as h]
             [cmr.common.services.errors :as errors]

  (let [{:keys [concept-type condition keywords]} query
        core-query (condition->elastic condition concept-type)]
    (if-let [keywords (:keywords query)]
      {:function_score {:functions []
                        :query {:filtered {:query (q/match-all)
                                           :filter core-query}}}}
      {:filtered {:query (q/match-all)

  (let [regex (str ".*" keyword ".*")]
    {:regexp {field regex}}))

(defn keyword-term-filter
  "Create a term filter for a given field/value"
  [field keyword]
  {:term {field keyword}})

(defn keyword-exact-match-filter
  "Create a filter that checks for an exact match"
  [field keyword]
  {:term {:field field
          :value keyword}})

(defn keywords->name-filter
  "Create a filter for keyword searches that checks for a loose match on one field or and
  exact match on another"
  [regex-field exact-field keywords boost]
  {:boost_factor boost
   :filter {:or [{:and (map (partial keyword-regexp-filter regex-field) keywords)}
                 {:or (map (partial keyword-exact-match-filter exact-field) keywords)}]}})

(defn science-keywords-or-filter
  "Create an or filter containig the science keyword fields related to keyword searches"
  [keywd]
  (map (fn [field] {:term {(keyword (str (name field) ".lowercase")) keywd}})
       [:category :topic :term :variable-level-1 :variable-level-1 :variable-level3]))

(defn keywords->sk-filter
  "Create a filter for keyword searches that checks science keywords"
  [keywords boost]
  {:boost_factor boost
   :filter {:nested {:path :science-keywords
                     :filter {:or (science-keywords-or-filter (str/join " " keywords))}}}})

(defn keywords->boosted-term-filter
  "Crete a boosted term filter for keyword searches"
  [field keywords boost]
  (let [keyword (str/join " " keywords)]
    {:boost_factor boost
     :filter (keyword-term-filter field keyword)}))

(defn keywords->elastic-filters
  "Create filters for keyword search"
  [keywords]
  [;; entry-title, short-name
   (keywords->name-filter :entry-title.lowercase :short-name.lowercase keywords 1.4)
   ;; project (ECHO campaign)
   (keywords->name-filter :project-ln.lowercase :project-sn.lowercase keywords 1.3)
   ;; platform
   (keywords->name-filter :platform-ln.lowercase :platform-sn.lowercase keywords 1.3)
   ;; TODO - instrument
   ;; need to add long name
   ;; TODO - sensor
   ;; need to add long name
   ;; science keywords
   (keywords->sk-filter keywords 1.2)
   ;; spatial-keyword
   (keywords->boosted-term-filter :spatial-keywords.lowercase keywords 1.1)
   ;; TODO - temporal-keyword
   ])

(defn query->elastic
  "Converts a query model into an elastic search query"
