(ns auto-ap.ssr.pos.tenders
  (:require
   [auto-ap.datomic
    :refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query
            pull-many query2]]
   [auto-ap.query-params :as query-params :refer [wrap-copy-qp-pqp]]
   [auto-ap.ssr-routes :as ssr-routes]
   [auto-ap.ssr.components :as com]
   [auto-ap.ssr.grid-page-helper :as helper :refer [wrap-apply-sort]]
   [auto-ap.ssr.pos.common
    :refer [date-range-field* processor-field* total-field*]]
   [auto-ap.ssr.svg :as svg]
   [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers clj-date-schema
                              default-grid-fields-schema ref->enum-schema
                              wrap-merge-prior-hx wrap-schema-enforce]]
   [auto-ap.time :as atime]
   [bidi.bidi :as bidi]
   [clj-time.coerce :as c]
   [datomic.api :as dc]
   [malli.core :as mc]))

;; always should be fast

(defn filters [request]
  [:form {"hx-trigger" "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
          "hx-get" (bidi/path-for ssr-routes/only-routes
                                  :pos-tender-table)
          "hx-target" "#tender-table"
          "hx-indicator" "#tender-table"
          #_#_:hx-disabled-elt "find fieldset"}

   [:fieldset.space-y-6 
    (date-range-field* request)
    (processor-field* request)
    (total-field* request)]])

(def query-schema (mc/schema
                   [:maybe
                    (into [:map {:date-range [:date-range :start-date :end-date]}
                           [:total-gte {:optional true} [:maybe :double]]
                           [:total-lte {:optional true} [:maybe :double]]
                           [:start-date {:optional true}
                            [:maybe clj-date-schema]]
                           [:end-date {:optional true}
                            [:maybe clj-date-schema]]
                           [:client {:optional true :default nil} [:maybe  [:entity-map {:pull [:db/id :client/name]}]]]
                           [:processor {:optional true} [:maybe (ref->enum-schema "ccp-processor")]]]
                          default-grid-fields-schema)]))

(def default-read '[:db/id
                    :charge/reference-link
                    :charge/total
                    :charge/tip
                    [:charge/date :xform clj-time.coerce/from-date]
                    {:charge/client                                 [:client/name :db/id :client/code]
                     [:charge/processor :xform iol-ion.query/ident] [:db/ident]
                     :expected-deposit/_charges                     [:expected-deposit/date :db/id]}])

(defn fetch-ids [db request]
  (let [query-params (:query-params request)
        query (cond-> {:query {:find  []
                               :in    ['$ '[?clients ?start-date ?end-date]]
                               :where '[[(iol-ion.query/scan-charges $ ?clients ?start-date ?end-date) [[?e _ ?sort-default] ...]]]}
                       :args  [db [(:trimmed-clients request)
                                   (some-> (:start-date query-params) c/to-date)
                                   (some-> (:end-date query-params) c/to-date)]]}
                (:sort query-params) (add-sorter-fields {"client" ['[?e :charge/client ?c]
                                                                   '[?c :client/name ?sort-client]]
                                                         "date" ['[?e :charge/date ?sort-date]]
                                                         "total" ['[?e :charge/total ?sort-total]]
                                                         "tip" ['[?e :charge/tip ?sort-tip]]
                                                         "processor" ['[?e :charge/processor ?p]
                                                                      '[?p :db/ident ?p2]
                                                                      '[(name ?p2) ?sort-processor]]}
                                                        query-params)

                (:exact-match-id query-params)
                (merge-query {:query {:in ['?e]
                                      :where []}
                              :args [(:exact-match-id query-params)]})

                (:total-gte query-params) 
                (merge-query {:query {:in ['?total-gte]
                                      :where ['[?e :charge/total ?a]
                                              '[(>= ?a ?total-gte)]]}
                              :args [(:total-gte query-params)]})

                (:total-lte query-params) 
                (merge-query {:query {:in ['?total-lte]
                                      :where ['[?e :charge/total ?a]
                                              '[(<= ?a ?total-lte)]]}
                              :args [(:total-lte query-params)]})

                (:processor query-params)
                (merge-query {:query {:in    '[?processor]
                                      :where ['[?e :charge/processor ?processor]]}
                              :args  [(:processor query-params)]})


                true
                (merge-query {:query {:find ['?sort-default '?e]}}))]
    
    (cond->> (query2 query)
      true (apply-sort-3 query-params)
      true (apply-pagination query-params))))

(defn hydrate-results [ids db _]
  (let [results (->> (pull-many db default-read ids)
                     (group-by :db/id))
        charges (->> ids
                     (map results)
                     (map first))]
    charges))

(defn fetch-page [request]
  (let [db                                           (dc/db conn)
        {ids-to-retrieve :ids matching-count :count} (fetch-ids db request)]

    [(->> (hydrate-results ids-to-retrieve db request))
     matching-count]))

(def grid-page
  (helper/build
    {:id                 "tender-table"
     :nav                com/main-aside-nav
     :page-specific-nav  filters
     :fetch-page         fetch-page
     :oob-render
     (fn [request]
       [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)])
     :breadcrumbs        [[:a {:href (bidi/path-for ssr-routes/only-routes
                                                    :company)}
                           "POS"]

                          [:a {:href (bidi/path-for ssr-routes/only-routes
                                                    :pos-tenders)}
                           "Tenders"]]
     :title       "Tenders"
     :entity-name "Tender"
                 :query-schema query-schema
     :route       :pos-tender-table
     :row-buttons (fn [request e]
                    (when (:charge/reference-link e)
                      [(com/a-icon-button {:href (:charge/reference-link e)}
                                          svg/external-link)]))
     :headers     [{:key      "client"
                    :name     "Client"
                    :sort-key "client"
                    :hide?    (fn [request]
                                (= (count (:clients request)) 1))
                    :render   #(-> % :charge/client :client/code)}
                   {:key      "date"
                    :name     "Date"
                    :sort-key "date"
                    :render   #(atime/unparse-local (:charge/date %) atime/standard-time)}
                   {:key      "total"
                    :name     "Total"
                    :sort-key "total"
                    :render   #(some->> % :charge/total (format "$%.2f"))}
                   {:key      "processor"
                    :name     "Processor"
                    :sort-key "processor"
                    :render   (fn [sales-order]
                                (when (:charge/processor sales-order)
                                  (com/pill {:color :primary }
                                            (name (:charge/processor sales-order)))))}
                   {:key      "tip"
                    :name     "Tip"
                    :sort-key "tip"
                    :render   #(some->> % :charge/tip (format "$%.2f"))}
                   {:key    "links"
                    :name   "Links"
                    :render (fn [entity]
                              (when-let [expected-deposit-id (some->> entity :expected-deposit/_charges first :db/id)]
                                [:a {:href     (str (bidi/path-for ssr-routes/only-routes
                                                                   :pos-expected-deposits)
                                                    "?exact-match-id=" expected-deposit-id)
                                     :hx-boost "true"}
                                 (com/pill {:color :secondary} "expected deposit")]))}]}))


(def row* (partial helper/row* grid-page))
(def table* (partial helper/table* grid-page))

(def key->handler
  (apply-middleware-to-all-handlers
   {:pos-tenders       (helper/page-route grid-page)
    :pos-tender-table (helper/table-route grid-page)}
   (fn [h]
     (-> h
         (wrap-copy-qp-pqp)
         (wrap-apply-sort grid-page)
         (wrap-merge-prior-hx)
         (wrap-schema-enforce :query-schema query-schema)
         (wrap-schema-enforce :hx-schema query-schema)))))
