(ns auto-ap.ssr.admin.history
  (:require
   [auto-ap.datomic :refer [conn]]
   [auto-ap.logging :as alog]
   [auto-ap.ssr.ui :refer [base-page]]
   [auto-ap.ssr.utils :refer [html-response]]
   [auto-ap.time :as atime]
   [clj-time.coerce :as coerce]
   [clojure.string :as str]
   [datomic.api :as dc]
   [auto-ap.ssr.components :as com]
   [auto-ap.ssr-routes :as ssr-routes]
   [bidi.bidi :as bidi]))

(defn tx-rows->changes [history]
  (->> history 
       (group-by (fn [[a _ t]]
                   [a t]))
       (map (fn [[[a t] changes]]
              (let [changes (-> (reduce
                                 (fn [acc [_ v _ added]]
                                   (if added
                                     (assoc acc :added v)
                                     (assoc acc :removed v)))
                                 {}
                                 changes))]
                [t a changes])))))

(defn format-value [v]
  (cond (inst? v)
        (-> v
            coerce/to-date-time
            atime/localize
            (atime/unparse atime/normal-date))

        (nil? v)
        [:em "(none)"]

        (and (integer? v)
             (> v 1000000))
        [:span
         (com/link
          {:href "#"
           :hx-get (str "/admin/history/" v)
           :hx-swap "innerHTML"
           :hx-push-url "true"
           :hx-select "#history-table"
           :hx-target "#history-table"}
          v)
         " ["
         (com/link
          {:href "#"
           :hx-get     (str "/admin/history/inspect/" v)
           :hx-swap    "innerHTML"
           :hx-target  "#inspector"
           :hx-trigger "click"}
          "snapshot") "]"]

        :else
        (pr-str v)))


(defn inspect [{{:keys [entity-id]} :params  :as request}]
  (alog/info ::inspect
             :request request)
  (try
    (let [entity-id (Long/parseLong entity-id)
          data (dc/pull (dc/db conn)
                        '[*]
                        entity-id)]

      (html-response
       [:section.py-3.sm:py-5.max-w-lg
        (com/card {:class "p-2"}
                  [:div {:style {:display "inline-block"}}
                   [:h1.title "Snapshot of "
                    entity-id]
                   [:ul
                    (for [[k v] data]
                      [:li [:strong k] ":" (format-value v)])]])]))
    (catch NumberFormatException _
      (html-response
       [:div.notification.is-danger.is-light
        "Cannot parse the entity-id " entity-id ". It should be a number."]))))

(defn result-table [{:keys [entity-id]}]
  (try
    (let [history           (->>
                             (dc/q '[:find ?a2 ?v (pull ?tx [:db/txInstant :audit/user :db/id]) ?ad
                                     :in $ $$ ?i
                                     :where
                                     [$$ ?i ?a ?v ?tx ?ad]
                                     [$ ?a :db/ident ?a2]]
                                   (dc/db conn)
                                   (dc/history (dc/db conn))
                                   entity-id)
                             tx-rows->changes
                             (sort-by (comp :db/id first))
                             vec)
          best-guess-entity (or (->> history
                                     (group-by
                                      (comp
                                       namespace
                                       second))
                                     (map (fn [[k v]]
                                            [k v]))
                                     (sort-by second)
                                     last
                                     first)
                                "?")]
      (com/data-grid-card {:id             "history-table"
                           :title          (format "History for %s: %d" (str/capitalize best-guess-entity) entity-id)
                           :route          :history-table
                           :paginate? false
                           :total          (count history)
                           :subtitle nil
                           :action-buttons nil
                           :rows           (for [[tx a c] history]
                                             (com/data-grid-row
                                              {}
                                              (com/data-grid-cell {} [:div [:div (some-> (:db/txInstant tx)
                                                                                         coerce/to-date-time
                                                                                         atime/localize
                                                                                         (atime/unparse atime/standard-time))]
                                                                      [:div.tag (:db/id tx)]])
                                              (com/data-grid-cell {} (str (:audit/user tx)))
                                              (com/data-grid-cell {} (namespace a) ": " (name a))

                                              (com/data-grid-cell {}
                                                                  (com/pill {:color :red}
                                                                            (format-value (:removed c))))
                                              (com/data-grid-cell {}
                                                                  [:div.tag.is-primary.is-light
                                                                   [:span
                                                                    (format-value (:added c))]])))
                           :headers
                           [(com/data-grid-header {}
                                                  "Date")
                            (com/data-grid-header {}
                                                  "User")
                            (com/data-grid-header {}
                                                  "Field")
                            (com/data-grid-header {}
                                                  "From")
                            (com/data-grid-header {}
                                                  "To")]}))
    (catch NumberFormatException e
      (throw e))))

(defn search-box [{:keys [entity-id]}]
  [:div.mt-4
   [:form.flex.gap-2 {"hx-target" "#history-table"
                      "hx-get"   (bidi/path-for ssr-routes/only-routes
                                                 :admin-history)
                      "hx-select" "#history-table"
                      "hx-swap" "innerHTML"
                      "hx-push-url" "true"}
    (com/text-input {:name "entity-id" :placeholder "Entity Id" :value entity-id
                     :style {:width "300px"}})
    (com/button {:color :primary}
                "DIG")]])

(defn page [{:keys [matched-route route-params query-params] :as request}]
  (let [entity-id         (or (some-> query-params (get "entity-id") Long/parseLong)
                              (some-> route-params (get :entity-id) Long/parseLong))]
    (base-page request
               (com/page {:nav com/admin-aside-nav
                          :client-selection (:client-selection request)
                          :client (:client request)
                          :clients (:clients request)
                          :identity (:identity request)
                          :request request
                          :app-params {:hx-get     (bidi/path-for ssr-routes/only-routes
                                                                  :admin-history)
                                       :hx-trigger "clientSelected from:body"
                                       :hx-select "#app-contents"
                                       :hx-swap    "outerHTML swap:300ms"}}
                         (com/breadcrumbs {}
                                          [:a {:href (bidi/path-for ssr-routes/only-routes
                                                                    :admin)}
                                           "Admin"]
                                          [:a {:href (bidi/path-for ssr-routes/only-routes
                                                                    :admin-history)}
                                           "History"])
                         (search-box {:entity-id entity-id})
                         [:div.flex.gap-4.flex-col.lg:flex-row
                          (if entity-id
                            (result-table {:entity-id entity-id})
                            [:div#history-table])
                          [:div#inspector]
                          ])
               "History")))
