(ns auto-ap.ssr.dashboard 
  (:require [auto-ap.client-routes :as client-routes]
            [auto-ap.datomic :refer [conn]]
            [auto-ap.graphql.ledger :refer [get-profit-and-loss-raw]]
            [auto-ap.graphql.utils :refer [<-graphql]]
            [auto-ap.ledger.reports :as r]
            [auto-ap.routes.dashboard :as d-routes]
            [auto-ap.routes.invoice :as i-routes]
            [auto-ap.routes.utils :refer [wrap-admin
                                          wrap-client-redirect-unauthenticated]]
            [auto-ap.ssr-routes :as ssr-routes]
            [auto-ap.ssr.company.reports.expense :refer [expense-breakdown-card]]
            [auto-ap.ssr.components :as com]
            [auto-ap.ssr.hiccup-helper :as hh]
            [auto-ap.ssr.hx :as hx]
            [auto-ap.ssr.svg :as svg]
            [auto-ap.ssr.ui :refer [base-page]]
            [auto-ap.ssr.utils :refer [apply-middleware-to-all-handlers
                                       html-response]]
            [auto-ap.time :as atime]
            [bidi.bidi :as bidi]
            [cemerick.url :as url]
            [clj-time.coerce :as coerce]
            [clj-time.core :as time]
            [datomic.api :as dc]
            [hiccup.util :as hu]))

(defn bank-accounts-card [request]
  (html-response 
   (com/card {:class "h-full"}
             [:div.p-4.h-full
              [:h1.text-2xl.font-bold "Bank Accounts"]
              [:div (hx/htmx-transition-appear {:class "h-full overflow-scroll" })
               (for [c (:valid-trimmed-client-ids request)
                     b (:client/bank-accounts (dc/pull (dc/db conn) '[{:client/bank-accounts

                                                                       [:bank-account/current-balance
                                                                        {[:bank-account/type :xform iol-ion.query/ident] [:db/ident]}

                                                                        [:bank-account/current-balance-synced :xform clj-time.coerce/from-date]
                                                                        :bank-account/name
                                                                        {:bank-account/intuit-bank-account [:intuit-bank-account/current-balance
                                                                                                            [:intuit-bank-account/last-synced :xform clj-time.coerce/from-date]]}
                                                                        {:bank-account/yodlee-account [:yodlee-account/available-balance
                                                                                                       :yodlee-account/pending-balance
                                                                                                       [:yodlee-account/last-synced :xform clj-time.coerce/from-date]]}
                                                                        {:bank-account/plaid-account [:plaid-account/balance
                                                                                                      [:plaid-account/last-synced :xform clj-time.coerce/from-date]]}]}]
                                                       c))
                     :when (not= :bank-account-type/cash (:bank-account/type b))]
                 [:div.flex.flex-col.p-4.border-b-2.border-gray-200
                  [:div.font-bold.text-gray-700 (:client/name c)]
                  [:div (:bank-account/name b)]
                  [:div.grid.grid-cols-3.gap-x-2.items-baseline
                   [:div "Ledger Balance"]
                   [:div.text-right (format "$%,.2f" (or (:bank-account/current-balance b) 0.0))]
                   [:div.text-xs.text-gray-400.text-right (some-> (:bank-account/current-balance-synced b)
                                                                  (atime/unparse-local atime/standard-time)
                                                                  (#(str "Synced " %)))]

                   (when-let [n (cond (-> b :bank-account/intuit-bank-account)
                                      "Intuit"
                                      (-> b :bank-account/yodlee-account)
                                      "Yodlee"
                                      (-> b :bank-account/plaid-account)
                                      "Plaid"
                                      :else
                                      nil)]
                     (list
                      [:div (str n " Balance")]
                      [:div.text-right (format "$%,.2f" (or (-> b :bank-account/intuit-bank-account :intuit-bank-account/current-balance)
                                                            (-> b :bank-account/yodlee-account :yodlee-account/available-balance)
                                                            (-> b :bank-account/plaid-account :plaid-account/balance)
                                                            0.0))]
                      

                      [:div.text-xs.text-gray-400.text-right (or (some-> (:bank-account/intuit-bank-account b)
                                                                         (:intuit-bank-account/last-synced)
                                                                         (atime/unparse-local atime/standard-time)
                                                                         (#(str "Synced " %)))
                                                                 (some-> (:bank-account/yodlee-account b)
                                                                         (:yodlee-account/last-synced)
                                                                         (atime/unparse-local atime/standard-time)
                                                                         (#(str "Synced " %)))
                                                                 (some-> (:bank-account/plaid-account b)
                                                                         (:plaid-account/last-synced)
                                                                         (atime/unparse-local atime/standard-time)
                                                                         (#(str "Synced " %))))]
                      (when-let [pending-balance (-> b :bank-account/yodlee-account :yodlee-account/pending-balance)]
                        (list 
                         [:div (str n " Pending Txs")]
                         [:div.text-right (format "$%,.2f" pending-balance)]))
                      [:div.inline-flex.justify-end.text-xs.text-gray-400.it]))
                   #_[:div.inline-flex.justify-between.items-baseline]]])]])))

(defn sales-chart-card [request]
  (html-response 
   (let [ totals
         (->> (dc/q '[:find ?sd (sum ?total)
                      :with ?e
                      :in $ [?clients ?start-date ?end-date]
                      :where [(iol-ion.query/scan-sales-orders $ ?clients ?start-date ?end-date) [[?e _ ?sort-default] ...]]
                      [?e :sales-order/date ?d]
                      [(iol-ion.query/iso-date ?d) ?sd]
                      [?e :sales-order/total ?total]]
                    (dc/db conn)
                    [(:valid-trimmed-client-ids request)
                     (coerce/to-date (time/with-time-at-start-of-day (time/plus (time/now) (time/days -14))))
                     (coerce/to-date (time/with-time-at-start-of-day (time/plus (time/now) (time/days 1))))])
              (sort-by first))]
     (com/card {:class "w-full h-full p-4"}
               [:h1.text-2xl.font-bold.text-slate-700 "Gross sales, last 14 days"]
               [:div.w-full.h-full
                [:canvas.w-full.h-full.p-8 {:x-data (hx/json {:chart nil
                                                              :labels (map first totals)
                                                              :data (map second totals)})
                                            :x-init 
                                            "new Chart($el, {
                        type: 'bar',
                        data: {
                          labels: labels,
                          datasets: [{
                            label: 'Gross sales',
                            data: data,
                            borderWidth: 1
                          }]
                        },
                        options: {
                          responsive: true,
                           maintainAspectRatio: false,
                          scales: {
                            y: {
                              beginAtZero: true
                            }
                          }
                        }
                      });"}]]))))

(defn expense-pie-card [request]
  (html-response 
   (let [ totals
         (->> (dc/q '[:find ?an (sum ?amt)
                      :with ?iea
                      :in $ [?clients ?start-date ?end-date]
                      :where [(iol-ion.query/scan-invoices $ ?clients ?start-date ?end-date) [[?e _ ?sort-default] ...]]
                      [?e :invoice/total ?total]
                      [?e :invoice/expense-accounts ?iea]
                      [?iea :invoice-expense-account/account ?ea]
                      [?iea :invoice-expense-account/amount ?amt]
                      [?ea :account/name ?an]]
                    (dc/db conn)
                    [(:valid-trimmed-client-ids request)
                     (coerce/to-date (time/with-time-at-start-of-day (time/plus (time/now) (time/months -1))))
                     (coerce/to-date (time/plus (time/with-time-at-start-of-day (time/now)) (time/days 1)))])
              (sort-by last)
              (reverse)
              (take 5))]
     (com/card {:class "w-full h-full p-4"}
               [:h1.text-2xl.font-bold.text-slate-700
                "Expenses, last month"]
               [:div.w-full.h-full
                [:canvas.w-full.h-full.p-8 {:x-data (hx/json {:chart nil
                                                              :labels (map first totals)
                                                              :data (map second totals)})
                                            :x-init " new Chart($el, {
                        type: 'pie',
                        data: {
                          labels: labels,
                          datasets: [{
                            label: 'Total invoices',
                            data: data,
                            borderWidth: 1
                          }]
                        },
                        options: {
                          responsive: true,
                           maintainAspectRatio: false,
                          
                        }
                      });"}]]))))

(defn pnl-card [request]
  (html-response 
   (com/card {:class "w-full h-full p-4"} 
             [:h1.text-2xl.font-bold.text-gray-700
              "Profit and Loss, last month" ]
             (let [ data (<-graphql (get-profit-and-loss-raw (:valid-trimmed-client-ids request)
                                                             [{:start (time/plus (time/now) (time/months -1))
                                                               :end (time/now)}]))
                   data (r/->PNLData {} (:accounts (first (:periods data))) {})
                   sales (r/aggregate-accounts (r/filter-categories  data [ :sales]))
                   expenses (r/aggregate-accounts (r/filter-categories  data [ :cogs :payroll :controllable :fixed-overhead  :ownership-controllable ]))]
               (list 
                #_(when (not= (count all-clients) (count clients))
                    )
                [:canvas.w-full.h-full.p-8 {:x-data (hx/json {:chart nil
                                                              :labels [(format "Income $%,.2f" sales) (format "Expenses $%,.2f" expenses)]
                                                              :data [sales expenses]})
                                            :x-init
                                            "new Chart($el, {
                        type: 'bar',
                        data: {
                          labels: labels,
                          datasets: [{
                            label: 'Dollars',
                            data: data,
                            borderWidth: 1
                          }]
                        },
                        options: {
                          responsive: true,
                            indexAxis: 'y',
                           maintainAspectRatio: false,
                          scales: {
                            x: {
                              beginAtZero: true
                            }
                          }
                        }
                      });"}]
                [:div 
                 "Income: " (format "$%,.2f" sales)]
                [:div 
                 "Expenses: " (format "$%,.2f" expenses)])))))
(defn tasks-card [request]
  (html-response 
   (com/card {:class "w-full h-full p-4"}
             [:h1.text-2xl.font-bold.text-gray-700
              "Tasks"]
             [:div (hx/htmx-transition-appear {:class "space-y-2"})
              (let [[unpaid-invoice-count unpaid-invoice-amount]
                    (first (dc/q '[:find (count ?e) (sum ?ab)
                                   :in $ [?clients ?start-date ?end-date]
                                   :where [(iol-ion.query/scan-invoices $ ?clients ?start-date ?end-date) [[?e _ ?sort-default] ...]]
                                   [?e :invoice/status :invoice-status/unpaid]
                                   [?e :invoice/outstanding-balance ?ab]]
                                 (dc/db conn)
                                 [(:valid-trimmed-client-ids request)
                                  (coerce/to-date (time/with-time-at-start-of-day (time/plus (time/now) (time/years -1))))
                                  nil]))
                    
                    [uncategorized-transaction-count uncategorized-transaction-amount]
                    (first (dc/q '[:find (count ?e) (sum ?am)
                                   :in $ [?clients ?start-date ?end-date]
                                   :where [(iol-ion.query/scan-transactions $ ?clients ?start-date ?end-date) [[?e _ ?sort-default] ...]]
                                   [?e :transaction/approval-status :transaction-approval-status/requires-feedback]
                                   [?e :transaction/amount ?am]]
                                 (dc/db conn)
                                 [(:valid-trimmed-client-ids request)
                                  (coerce/to-date (time/with-time-at-start-of-day (time/plus (time/now) (time/years -1))))
                                  nil]))]
                (list 
                 (when (not= 0 (or unpaid-invoice-count 0))
                   [:div.bg-gray-50.rounded.p-4
                    [:span "You have " (str unpaid-invoice-count) " unpaid invoices with an outstanding balance of " (format "$%,.2f" unpaid-invoice-amount) ". " ]
                    
                    (com/link {:href (hu/url (bidi.bidi/path-for ssr-routes/only-routes ::i-routes/unpaid-page)
                                             {:date-range "year"})
                               }
                              
                              "Pay now")
                    ])
                 (when (not= 0 (or uncategorized-transaction-count 0))
                   [:div.bg-gray-50.rounded.p-4
                    [:span "You have " (str uncategorized-transaction-count) " transactions needing your feedback.  "  ]
                    
                    (com/link {:href (str (bidi.bidi/path-for client-routes/routes :requires-feedback-transactions)
                                          "?date-range="
                                          (url/url-encode (pr-str {:start (atime/unparse-local (time/plus (time/now) (time/years -1)) atime/iso-date) :end (atime/unparse-local (time/now) atime/iso-date)}))) }
                              
                              "Review now")])))])))

(defn stub-card [params & children]
  (com/card (-> params
                (dissoc :title)
                (update :class #(hh/add-class (or % "") "w-full h-full p-4 space-y-2"))
                (assoc :hx-swap "outerHTML"))
            [:h1.text-2xl.font-bold.text-gray-700
             (:title params)]
            [:div.w-full.h-full.flex.justify-center.items-center
             [:div.htmx-indicator (svg/spinner {:class "inline w-32 h-32 text-green-500"})]]))

(defn- page-contents [request]
    [:div.mb-8
     [:div {:class "grid grid-cols-1 lg:grid-cols-2 2xl:grid-cols-3 gap-4  mb-8"}
      [:div.h-96 (stub-card {:title "Expenses"
                        :hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/expense-card)
                        :hx-trigger "load"} )]
      [:div.h-96
       (stub-card {:title "Tasks"
                        :hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/tasks-card)
                        :hx-trigger "load"} )]
      [:div {:class " row-span-2 h-[49rem]"}
(stub-card {:title "Bank Accounts"
                        :hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/bank-accounts-card)
                        :hx-trigger "load"} )
       ]
      
      [:div.h-96
       (stub-card {:title "Gross Sales, last 14 days"
                   :hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/sales-card)
                   :hx-trigger "load"})
       ]
      [:div.h-96
       (stub-card {:title "Profit and Loss, last month"
                   :hx-get (bidi.bidi/path-for ssr-routes/only-routes ::d-routes/pnl-card)
                   :hx-trigger "load"}) ]
      [:div.col-span-2.h-96
       (stub-card {:title "Expense breakdown"
                        :hx-get (bidi.bidi/path-for ssr-routes/only-routes :company-expense-report-breakdown-card)
                        :hx-trigger "load"} )]
      [:div]] ])

(defn page [request]
  (base-page
   request
   (com/page {:nav              com/main-aside-nav
              :client-selection (:client-selection request)
              :clients          (:clients request)
              :client           (:client request)
              :identity         (:identity request)
              :app-params {:hx-get     (bidi/path-for ssr-routes/only-routes
                                                      ::d-routes/page)
                           :hx-trigger "clientSelected from:body"
                           :hx-select "#app-contents"
                           :hx-swap    "outerHTML swap:300ms"}

              :request request}
             (com/breadcrumbs {}
                              [:a {:href (bidi/path-for ssr-routes/only-routes ::d-routes/page)}
                               "Dashboard"])
             (when (:clients-trimmed? request)
               [:div.bg-yellow-100.rounded-lg.p-4.my-2.text-yellow-900.border-1 "Warning: These reports are only for twenty of the selected customers. Please select a specific customer to see more detail."])
             (page-contents request))
   "Dashboard"))

(def key->handler
    ( apply-middleware-to-all-handlers
     {::d-routes/page page
      ::d-routes/expense-card expense-pie-card
      ::d-routes/pnl-card pnl-card
      ::d-routes/sales-card sales-chart-card
      ::d-routes/bank-accounts-card bank-accounts-card
      ::d-routes/tasks-card tasks-card }
     (fn [h]
       (wrap-client-redirect-unauthenticated (wrap-admin h)))))