(ns auto-ap.views.pages.ledger.external-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.pages.ledger.external-ledger-table :as table]
            [auto-ap.views.pages.ledger.side-bar
             :as
             side-bar
             :refer
             [ledger-side-bar]]
            [auto-ap.views.utils :refer [with-user dispatch-event]]
            [auto-ap.status :as status]
            [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]
            [auto-ap.views.components.buttons :as buttons]))

(defn data-params->query-params [params]
  {:start (:start params 0)
   :sort (:sort params)
   :per-page (:per-page params)
   :vendor-id (:id (:vendor params))
   :date-range (:date-range params)
   :account-id (:id (:account params))
   :bank-account-id (:id (:bank-account params))
   :external-id-like (:external-id params)
   :source (:source params)
   :amount-gte (:amount-gte (:amount-range params))
   :amount-lte (:amount-lte (:amount-range params))
   :only-external true})


(re-frame/reg-event-fx
 ::params-change
 [with-user]
 (fn [{:keys [user]} [_ 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
                                                               :external_id
                                                               :source
                                                               :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})])}}))

(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-n [[::data-page/dispose ::page]
                 [::status/dispose-single ::delete-selected]]
    ::track/dispose {:id ::params}}))

(re-frame/reg-event-fx
 ::mounted
 (fn [_ _]
   {::track/register {:id ::params
                      :subscription [::data-page/params ::page]
                      :event-fn (fn [params] [::params-change params])}}))

(re-frame/reg-event-fx
 ::delete-successful
 (fn [_ [_ result params]]
   {:dispatch-n [[::params-change params]
                 [::status/info ::delete-selected (:message (:delete-external-ledger result))]]}))

(re-frame/reg-event-fx
 ::delete-selected
 (fn [cofx [_ params]]
   (let [checked @(re-frame/subscribe [::data-page/checked ::page])
         checked-params (get checked "header")
         specific-ledger-entries (map :id (vals (dissoc checked "header")))]
     {:db (:db cofx)
      :graphql {:token (-> cofx :db :user)
                :owns-state {:single ::delete-selected}
                :query-obj
                {:venia/operation {:operation/type :mutation
                                   :operation/name "DeleteExternalLedger"}
                 :venia/queries [{:query/data
                                  [:delete-external-ledger
                                   {:filters (some-> checked-params data-params->query-params)
                                    :ids specific-ledger-entries}
                                   [:message]]}]}
                :on-success (fn [result]
                              [::delete-successful result params])}})))

(defn action-buttons []
  (println "HERE?")
  (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]])
        checked @(re-frame/subscribe [::data-page/checked ::page])]
    [:div.buttons
     (into [:div.tags] (map (fn [[z {:keys [id external-id]}]]
                              (if (= "header" z)
                                [:span.tag.is-medium {:on-click
                                                      (dispatch-event [::data-page/remove-check ::page "header"])}
                                 "All visible ledger entries"]
                                [:span.tag.is-medium external-id
                                 [:button.delete.is-small {:on-click
                                                           (dispatch-event [::data-page/remove-check ::page id])}]]))
                            checked))
     [:button.button.is-danger {:on-click (dispatch-event [::delete-selected params])
                                :class (status/class-for @(re-frame/subscribe [::status/single ::delete-selected]))
                                :disabled (or (status/disabled-for @(re-frame/subscribe [::status/single ::delete-selected]))
                                              (not (seq checked)))}
      "Delete selected"]
     (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 []
  (let [_ @(re-frame/subscribe [::subs/client])
        params @(re-frame/subscribe [::data-page/params ::page])
        ]
    [:div 
     [:h1.title "External Ledger"]
     [status/status-notification {:statuses [[::status/single ::delete-selected]]}]
     [:div.is-pulled-right
      ]
     [table/table {:id :ledger
                   :data-page ::page
                   :action-buttons [action-buttons]}]]))


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

