(ns auto-ap.views.pages.ledger
  (:require
   [auto-ap.subs :as subs]
   [auto-ap.views.components.layouts :refer [side-bar-layout]]
   [auto-ap.views.pages.data-page :as data-page]
   [auto-ap.views.components.buttons :as buttons]
   [auto-ap.views.pages.ledger.side-bar
    :as side-bar
    :refer [ledger-side-bar]]
   [auto-ap.views.pages.ledger.table :as table]
   [auto-ap.views.utils :refer [with-user date->str standard]]
   [auto-ap.status :as status]
   [cljs-time.core :as time]
   [clojure.set :as set]
   [re-frame.core :as re-frame]
   [reagent.core :as reagent]
   [vimsical.re-frame.fx.track :as track]
   [vimsical.re-frame.cofx.inject :as inject]))

(defn data-params->query-params [params]
  {:start (:start params 0)
   :sort (:sort params)
   :exact-match-id (:exact-match-id params)
   :per-page (:per-page params)
   :vendor-id (:id (:vendor params))
   :date-range (:date-range params)
   :account-id (:id (:account params))
   :location (:location params)
   :bank-account-id (:id (:bank-account params))
   :amount-gte (:amount-gte (:amount-range params))
   :amount-lte (:amount-lte (:amount-range params))})


(re-frame/reg-event-fx
 ::params-change
 [with-user]
 (fn [{:keys [user db]} [_ params]]
   {:graphql {:token user
              :owns-state {:single [::data-page/page ::page]}
              :query-obj {:venia/queries [[:ledger-page
                                           {:filters (data-params->query-params params)}
                                           [[:journal-entries [:id
                                                               :source
                                                               :original-entity
                                                               :amount
                                                               :note
                                                               :cleared-against
                                                               :alternate-description
                                                               [:vendor
                                                                [:name :id]]
                                                               [:client
                                                                [:name :id]]
                                                               [:line-items
                                                                [:id :debit :credit :location :running-balance
                                                                 [:account [:id :name]]]]
                                                               :date]]
                                            :total
                                            :start
                                            :end]]]} 
              :on-success (fn [result]
                            [::data-page/received ::page (set/rename-keys (:ledger-page result)
                                                                          {:journal-entries :data})])}
    :db (dissoc db ::csv-content)}))

(re-frame/reg-sub
 ::csv-content
 (fn [db]
   (::csv-content db)))

(re-frame/reg-event-fx
 ::csv-exported
 (fn [{:keys [db]} [_ csv]]
   {:db (assoc db ::csv-content csv)}))

(re-frame/reg-event-fx
 ::export-csv
 [with-user (re-frame/inject-cofx ::inject/sub [::data-page/params ::page])]
 (fn [{:keys [user db] ::data-page/keys [params]}]
   {:graphql {:token user
              :owns-state {:single [::data-page/page ::page]}
              :query-obj {:venia/queries [[:ledger-csv
                                           {:filters (data-params->query-params params)}
                                           [:csv_content_b64]]]} 
              :on-success (fn [result]
                            [::csv-exported (:csv-content-b64 (:ledger-csv result))])}}))

(re-frame/reg-event-fx
 ::unmounted
 (fn [_ _]
   {:dispatch [::data-page/dispose ::page]
    ::track/dispose {:id ::params}}))

(re-frame/reg-event-fx
 ::mounted
 (fn [{:keys [db]} _]
   {:db (-> db (assoc-in [::data-page/settled-filters ::page :date-range] {:start (date->str (time/plus (time/now) (time/months -1))
                                                                                             standard)})
            (assoc ::csv-content nil))
    ::track/register {:id ::params
                      :subscription [::data-page/params ::page]
                      :event-fn (fn [params] [::params-change params])}}))


(defn action-buttons []
  (let [params @(re-frame/subscribe [::data-page/params ::page])
        csv-content @(re-frame/subscribe [::csv-content])
        is-admin? @(re-frame/subscribe [::subs/is-admin?])
        status @(re-frame/subscribe [::status/single [::data-page/page ::page]])]
    (when is-admin?
      (if csv-content
        [:a {:href     (str "data:attachment/csv;base64," csv-content)
             :target   "_blank"
             :download (str "ledger.csv")}
         "Click here to download"]
        [buttons/event-button {:event [::export-csv]
                               :name "Export"
                               :class (status/class-for status)
                               :disabled (status/disabled-for status)}]))))

(defn ledger-content []
  [:div 
   [:h1.title "Ledger"]
   [table/table {:id        :ledger
                 :data-page ::page
                 :action-buttons [action-buttons]}]])


(defn ledger-page []
  (let [user (re-frame/subscribe [::subs/user])]
    (reagent/create-class
     {:display-name "ledger-page"
      :component-did-mount #(re-frame/dispatch [::mounted])
      :component-will-unmount #(re-frame/dispatch [::unmounted])
      :reagent-render
      (fn []
        (if (not= "manager" (:user/role @user))
          [side-bar-layout
           {:side-bar [ledger-side-bar {:data-page ::page}]
            :main [ledger-content]}]
          [:div "Not authorized"]))})))

