(ns auto-ap.views.components.typeahead
  (:require [reagent.core :as r]
            [reagent.ratom :as ra]
            [clojure.string :as str]))

(defn get-valid-matches [matches not-found-description not-found-value text]
  (let [valid-matches (take 5 (for [[[id t :as match] i] (map vector  matches (range))
                                    :when (str/includes? (or (some-> t .toLowerCase) "") (or (some-> text .toLowerCase) ""))]
                                match))
        valid-matches (if (and not-found-description text)
                        (concat valid-matches [[:not-found (not-found-description text) (not-found-value text)]])
                        valid-matches)]
    valid-matches))

(defn typeahead [{:keys [matches on-change field text-field value class not-found-description
                         not-found-value auto-focus]}]
  (let [text (r/atom (or (second (first (filter #(= (first %) value) matches))) ""))
        highlighted (r/atom nil)
        selected (r/atom (first (first (filter #(= (first %) value) matches))))
        select (fn [[id text-description text-value]]
                 (reset! selected  id)
                 (reset! text text-description)
                 (when on-change
                   (if (= :not-found id)
                     (on-change nil text-description text-value)
                     (on-change id text-description (or text-value text-description)))))]
    (r/create-class
     {:reagent-render (fn [{:keys [matches on-change field text-field value class not-found-description]}]
                        (let [text @text
                              valid-matches (get-valid-matches matches not-found-description not-found-value text)]
                          [:div.typeahead
                           (if @selected
                             ^{:key "typeahead"} [:div.input {:class class
                                          :tab-index "0"
                                          :on-key-up (fn [e]
                                                       (if (= 8 (.-keyCode e))
                                                         (do
                                                           (select [nil "" nil])
                                                           true)
                                                         false))}
                              [:div.control
                               [:div.tags.has-addons
                                [:span.tag text]
                                [:a.tag.is-delete {:on-click (fn [] (select [nil "" nil]))}]]]]
                             ^{:key "typeahead"} [:input.input {:type "text"
                                            :class class
                                            :value text
                                            :auto-focus auto-focus
                                            :on-blur (fn [e]
                                                       (cond @selected
                                                             nil 

                                                             (#{"" nil} text)
                                                             nil

                                                             @highlighted
                                                             (do (select @highlighted)
                                                                 true)

                                                             :else
                                                             (do (select [nil ""])
                                                                 true)))
                                            :on-key-down (fn [e]
                                                         (condp = (.-keyCode e)
                                                           ; up
                                                           38 (do
                                                                (when-let [new-match (->> valid-matches
                                                                                          (take-while #(not= % @highlighted))
                                                                                          (last))]
                                                                  (reset! highlighted new-match))
                                                                true)
                                                           ;; dwon
                                                           40 (do
                                                                (when-let [new-match (->> valid-matches
                                                                                (drop-while #(not= % @highlighted))
                                                                                (drop 1)
                                                                                (first))]
                                                                  (reset! highlighted new-match))
                                                                  true)
                                                           13 (do (.preventDefault e)
                                                               (when @highlighted
                                                                 
                                                                 (select @highlighted)
                                                                 false))
                                                           true))
                                            :on-change (fn [e]
                                                         (let [new-matches (get-valid-matches matches not-found-description not-found-value (.. e -target -value))]
                                                           (reset! highlighted (first new-matches)))
                                                         (select [nil (.. e -target -value)]))}])
                           (cond
                             (and (seq text)
                                  (not @selected)
                                  (seq valid-matches))
                             (let [[h] @highlighted]
                               [:div.typeahead-menu
                                [:ul
                                 (for [[id t :as match] valid-matches]
                                   ^{:key id} [:li.typeahead-suggestion {:class (if (= id h)
                                                                                  "typeahead-highlighted")
                                                                         :on-mouse-down #(do (select match))} t])]])

                             :else
                             nil)]))})))
