(ns auto-ap.ssr.pos.sales-orders
  (:require
   [auto-ap.datomic
    :refer [add-sorter-fields apply-pagination apply-sort-3 conn merge-query
            pull-many query2]]
   [auto-ap.datomic.sales-orders :as d-sales]
   [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]))

(def query-schema (mc/schema
                   [:maybe
                    (into [:map {:date-range [:date-range :start-date :end-date]}
                           [:total-gte {:optional true :default nil} [:maybe :double]]
                           [:total-lte {:optional true :default nil} [: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)]))

(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-sales-table)
          "hx-target"          "#sales-table"
          "hx-indicator"       "#sales-table"
          #_#_:hx-disabled-elt "find fieldset"}

   [:fieldset.space-y-6 
    (date-range-field* request)
    (total-field* request)
    [:div
     (com/field {:label "Payment Method"}
                (com/radio-card {:size    :small
                            :name    "payment-method"
                            :options [{:value   ""
                                       :content "All"}
                                      {:value   "CASH"
                                       :content "Cash"}
                                      {:value   "CARD"
                                       :content "Card"}
                                      {:value   "SQUARE_GIFT_CARD"
                                       :content "Gift Card"}
                                      {:value   "OTHER"
                                       :content "Other"}
                                      ]}))]
    [:div
     (processor-field* request)]

    [:div
     (com/field {:label "Category"}
                (com/text-input {:name        "category"
                                 :class       "hot-filter"
                                 :id          "category"
                                 :hx-preserve "true"
                                 :value       (:category (:query-params request))
                                 :placeholder "Fries"
                                 :size        :small}))]]])

(def default-read '[:db/id
                    :sales-order/external-id,
                    :sales-order/location,
                    [:sales-order/date, :xform clj-time.coerce/from-date]
                    :sales-order/total,
                    :sales-order/tax,
                    :sales-order/tip,
                    :sales-order/line-items,
                    :sales-order/discount,
                    :sales-order/returns,
                    :sales-order/service-charge,
                    :sales-order/vendor,
                    :sales-order/source,
                    :sales-order/reference-link,
                    {:sales-order/client  [:client/name :db/id :client/code]
                     :sales-order/charges [
                                           :charge/type-name,
                                           :charge/total,
                                           :charge/tax,
                                           :charge/tip,
                                           :charge/external-id,
                                           :charge/note,
                                           :charge/date,
                                           :charge/client,
                                           :charge/location,
                                           :charge/reference-link,
                                           {:charge/processor [:db/ident]} {:expected-deposit/_charges [: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-sales-orders $ ?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 :sales-order/client ?c]
                                                                   '[?c :client/name ?sort-client]]
                                                         "date" ['[?e :sales-order/date ?sort-date]]
                                                         "total" ['[?e :sales-order/total ?sort-total]]
                                                         "tax" ['[?e :sales-order/tax ?sort-tax]]
                                                         "tip" ['[?e :sales-order/tip ?sort-tip]]
                                                         "source" ['[?e :sales-order/source ?sort-source]]
                                                         "processor" ['[?e :sales-order/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 :sales-order/total ?a]
                                              '[(>= ?a ?total-gte)]]}
                              :args [(:total-gte query-params)]})

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

                (not-empty (:payment-method query-params))
                (merge-query {:query {:in    ['?type-name]
                                      :where ['[?e :sales-order/charges ?chg]
                                              '[?chg :charge/type-name ?type-name]]}
                              :args  [(:payment-method query-params)]})

                (not-empty (:category query-params))
                (merge-query {:query {:in    ['?category]
                                      :where ['[?e :sales-order/line-items ?li]
                                              '[?li :order-line-item/category ?category]]}
                              :args  [(:category query-params)]})

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


                true
                (merge-query {:query {:find ['?sort-default '?e]}}))]
    (clojure.pprint/pprint (update-in query [:args] #(drop 1 %)))
    (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                 "sales-table"
    :nav                com/main-aside-nav
    :page-specific-nav  filters
    :fetch-page         fetch-page

    :query-schema query-schema
    :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-sales)}
                          "Sales"]]
    :title          "Sales orders"
    :entity-name    "Sales orders"
    :route          :pos-sales-table
    :action-buttons (fn [request]
                      (let [{:keys [total tax]} (d-sales/summarize-orders (:ids (fetch-ids (dc/db conn) request)))]
                        (when (and total tax)
                          [(com/pill {:color :primary}
                                     (format "Total $%.2f" total))
                           (com/pill {:color :secondary}
                                     (format "Tax $%.2f" tax))])))
    :row-buttons    (fn [_ e]
                      (when (:sales-order/reference-link e)
                        [(com/a-icon-button {:href (:sales-order/reference-link e)}
                                            svg/external-link)]))
    :headers        [{:key      "client"
                      :name     "Client"
                      :sort-key "client"
                      :hide?    (fn [args]
                                  (= (count (:clients args)) 1))
                      :render   #(-> % :sales-order/client :client/code)}
                     {:key      "date"
                      :name     "Date"
                      :sort-key "date"
                      :render   #(atime/unparse-local (:sales-order/date %) atime/standard-time)}
                     {:key      "source"
                      :name     "Source"
                      :sort-key "source"
                      :render   (fn [sales-order]
                                  (when (:sales-order/source sales-order)
                                    (com/pill {:color :primary}
                                              (:sales-order/source sales-order))))}
                     {:key      "total"
                      :name     "Total"
                      :sort-key "total"
                      :render   #(some->> % :sales-order/total (format "$%.2f"))}
                     {:key      "tax"
                      :name     "Tax"
                      :sort-key "tax"
                      :render   #(some->> % :sales-order/tax (format "$%.2f"))}
                     {:key      "tip"
                      :name     "Tip"
                      :sort-key "tip"
                      :render   #(some->> % :sales-order/tip (format "$%.2f"))}
                     {:key    "Payment methods"
                      :name   "Payment Methods"
                      :render (fn [sales-order]
                                [:div.flex.space-x-2
                                 (for [payment-method (->> sales-order :sales-order/charges (map :charge/type-name) set)]
                                   (com/pill {:color :primary}
                                             (condp = payment-method
                                               "CASH"             "cash"
                                               ""                 nil
                                               "ALL"              nil
                                               "CARD"             "card"
                                               "SQUARE_GIFT_CARD" "gift card"
                                               "OTHER"            "other"
                                               nil)))])}]}))


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

(def key->handler
  (apply-middleware-to-all-handlers
   {:pos-sales       (helper/page-route grid-page)
    :pos-sales-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)))))
