(ns auto-ap.routes.ezcater-xls
  (:require
   [auto-ap.datomic :refer [audit-transact conn]]
   [auto-ap.logging :as alog]
   [clojure.data.json :as json]
   [auto-ap.parse.excel :as excel]
   [auto-ap.parse :as parse]
   [amazonica.aws.lambda :as lambda]
   [config.core :refer [env]]
   [auto-ap.shared-views.admin.side-bar :refer [admin-side-bar]]
   [auto-ap.ssr-routes :as ssr-routes]
   [auto-ap.ssr.ui :refer [base-page]]
   [auto-ap.ssr.utils :refer [html-response]]
   [auto-ap.time :as atime]
   [bidi.bidi :as bidi]
   [clj-time.coerce :as coerce]
   [clojure.java.io :as io]
   [com.brunobonacci.mulog :as mu]
   [datomic.api :as dc]
   [hiccup2.core :as hiccup]
   [amazonica.aws.s3 :as s3]
   [auto-ap.ssr.components :as com]))

(defn fmt-amount [a]
  (with-precision 2
    (some-> a
            bigdec
            (.setScale 2 java.math.RoundingMode/HALF_UP)
            (double))))

(defn rows->maps [rows]
  (let [[headers & rows] rows]
    (for [r rows]
      (into {}
            (map vector headers r)))))

(defn map->sales-order [r clients]
  (println r)
  (let [order-number (get r "Order Number")
        event-date   (get r "Event Date")
        store-name   (get r "Store Name")
        adjustments (some-> (get r "Adjustments") not-empty (Double/parseDouble))
        tax (some-> (get r "Sales Tax") not-empty (Double/parseDouble))
        food-total (some-> (get r "Food Total") not-empty (Double/parseDouble))
        commission (some-> (get r "Commission") not-empty (Double/parseDouble))
        fee (some-> (get r "Payment Transaction Fee") not-empty (Double/parseDouble))
        tip (some-> (get r "Tip") not-empty (Double/parseDouble))
        caterer-name (get r "Caterer Name")
        client (some->> caterer-name
                        not-empty
                        (parse/exact-match clients))
        client-id (:db/id client)
        location (first (:client/locations client))
        event-date (some-> (excel/xls-date->date event-date)
                           coerce/to-date-time
                           atime/as-local-time
                           coerce/to-date )]
    (cond (and event-date client-id location ) 
          [:order #:sales-order
           {:date           event-date
            :external-id    (str "ezcater/order/" client-id "-" location "-" order-number)
            :client         client-id
            :location       location
            :reference-link (str order-number)
            :line-items     [#:order-line-item
                             {:external-id (str "ezcater/order/" client-id "-" location "-" order-number "-" 0)
                              :item-name   "EZCater Catering"
                              :category    "EZCater Catering"
                              :discount    (fmt-amount (or adjustments 0.0))
                              :tax         (fmt-amount tax)
                              :total       (fmt-amount (+ food-total
                                                          tax))}]

            :charges        [#:charge
                             {:type-name   "CARD"
                              :date        event-date
                              :client      client-id
                              :location    location
                              :external-id (str "ezcater/charge/" client-id "-" location "-" order-number "-" 0)
                              :processor   :ccp-processor/ezcater
                              :total       (fmt-amount (+ food-total
                                                          tax
                                                          tip))
                              :tip         (fmt-amount tip)}]
            :total          (fmt-amount (+ food-total
                                           tax
                                           (or adjustments 0.0)))
            :discount       (fmt-amount (or adjustments 0.0))
            :service-charge (fmt-amount (+ fee commission))
            :tax            (fmt-amount tax)
            :tip            (fmt-amount tip)
            :returns        0.0
            :vendor         :vendor/ccp-ezcater}]

      caterer-name
      (do 
        (alog/warn ::missing-client
                   :order order-number
                   :store-name store-name 
                   :caterer-name caterer-name)
        [:missing caterer-name])

      :else
      nil)))

(defn stream->sales-orders [s]
  (let [clients (map first (dc/q '[:find (pull ?c [:client/code
                                                   :db/id
                                                   :client/feature-flags
                                                   {:client/location-matches [:location-match/matches :location-match/location]}
                                                   :client/name
                                                   :client/matches
                                                   :client/locations])
                                   :where [?c :client/code]]
                                 (dc/db conn)))
        object (str "/ezcater-xls/" (str (java.util.UUID/randomUUID)))]
    (mu/log ::writing-temp-xls
            :location object)
    (s3/put-object {:bucket-name (:data-bucket env) 
                    :key object
                    :input-stream s})
    (into []
          (->> (excel/extract-sheet-details (:data-bucket env) object)
               rows->maps
               (map #(map->sales-order % clients))
               (filter identity)))))

(defn import-stuff []
  (with-open [s (io/input-stream "/home/brycecovert/Downloads/test_2023-04-01_2023-04-30_2023-05-04.xlsx")]
    (stream->sales-orders s)))

(defn page* []
  [:div.mt-4
   (com/card {}
             [:div.px-4.py-3.space-y-4.flex.flex-col
              [:h1.text-2xl.mb-3.font-bold "EZCater XLS Import"]
              [:p.text-sm.italic
               "Please go to "
               (com/link {:href "https://www.ezcater.com/ez_manage/reports/new" :target "_blank"} "EZCater's report page")
               " to generate a new report. Then drop it below."]
              [:div#page-notification.notification.block {:style {:display "none"}}]
              [:form.bg-blue-100.border-2.border-dashed.rounded-lg.border-blue-300.p-4.max-w-md.w-md.text-center.cursor-pointer
               {:action (bidi/path-for ssr-routes/only-routes
                                       :admin-ezcater-xls)
                :method "POST"
                :id     "ezcater"}
               "Drop the ezcater xls here."]
              [:script
               (hiccup/raw
                "
    ezcater_dropzone = new Dropzone (\"#ezcater\", {
      success: function (file, response) {
        document.getElementById(\"page-notification\").innerHTML = response;
        document.getElementById(\"page-notification\").style[\"display\"] = \"block\";
        },
      acceptedFiles: '.xls,.xlsx',
      disablePreviews: true
    });")]])])

(defn upload-xls [{:keys [identity] :as request}]
  
  (let [file (or (get (:params request) :file)
                 (get (:params request) "file"))]
    (mu/log ::uploading-file
            :file file)
    (with-open [s (io/input-stream (:tempfile file))]
      (try 
        (let [parse-results (stream->sales-orders s)
              new-orders (->> parse-results
                              (filter (comp #{:order} first))
                              (map last))

              missing-location (->> parse-results
                                    (filter (comp #{:missing} first))
                                    (map last))]
          (audit-transact new-orders identity)
          (html-response [:div (format "Successfully imported %d orders." (count new-orders))
                          (when (seq missing-location)
                            [:div "Missing the following locations"
                             [:ul.ul
                              (for [ml (into #{} missing-location)]
                                [:li ml])]])]))
        (catch Exception e
          (alog/error ::import-error
                    :error e)
          (html-response [:div (.getMessage e)]))))))

(defn page [{:keys [matched-route request-method] :as request}]
  (mu/log ::method
          :method request-method)
  (if (= :post request-method)
    (upload-xls request)
    (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-ezcater-xls)
                             :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-ezcater-xls)}
                                 "EZCater XLS Import"])
               (page*))

     "Invoice Glimpse")))

