(ns auto-ap.views.pages.transactions
  (:require [auto-ap.effects.forward :as forward]
            [auto-ap.forms :as forms]
            [auto-ap.status :as status]
            [auto-ap.subs :as subs]
            [auto-ap.views.components.layouts
             :refer
             [appearing-side-bar side-bar-layout]]
            [auto-ap.views.components.modal :as modal]
            [auto-ap.views.pages.data-page :as data-page]
            [auto-ap.views.pages.transactions.bulk-updates :as bulk]
            [auto-ap.views.pages.transactions.common :refer [data-params->query-params
                                                             transaction-read]]
            [auto-ap.views.pages.transactions.form :as edit]
            [auto-ap.views.pages.transactions.manual :as manual]
            [auto-ap.views.pages.transactions.side-bar :as side-bar]
            [auto-ap.views.pages.transactions.table :as table]
            [auto-ap.views.utils :refer [date->str dispatch-event standard
                                         with-user]]
            [auto-ap.views.utils :as u]
            [cljs-time.core :as time]
            [clojure.string :as str]
            [re-frame.core :as re-frame]
            [reagent.core :as reagent]
            [vimsical.re-frame.fx.track :as track]))



(re-frame/reg-event-fx
 ::params-change
 [with-user]
 (fn [{:keys [user db]} [_ params]]
   (try 
     {:graphql {:token user
                :owns-state {:single [::data-page/page ::page]}
                :query-obj {:venia/queries [{:query/data  [:transaction_page
                                                           {:filters (data-params->query-params params)}
                                                           [[:data transaction-read]
                                                            :total
                                                            :start
                                                            :end]]
                                             :query/alias :result}]} 
                :on-success (fn [result]
                              [::data-page/received ::page (:result result)])}
      :db (-> db
              (forms/stop-form ::edit/form))}
     (catch js/Error e
       ;; this catches an error where you choose a parameter, change to invoices page, then change to voided invoices
       (println "Error!" e)))))

(re-frame/reg-event-fx
 ::unset-selected
 (fn [cofx [_ params suppress]]
   (let [checked @(re-frame/subscribe [::data-page/checked ::page])
         checked-params (get checked "header")
         specific-transactions (map :id (vals (dissoc checked "header")))]
     {:db (-> (:db cofx)
              (assoc-in [:status :loading] true))
      :graphql {:token (-> cofx :db :user)
                :owns-state {:single ::delete-selected}
                :query-obj
                {:venia/operation {:operation/type :mutation
                                   :operation/name "DeleteTransactions"}
                 :venia/queries [{:query/data
                                  [:delete-transactions
                                   {:filters (some-> checked-params data-params->query-params)
                                    :ids specific-transactions
                                    :suppress suppress}
                                   [:message]]}]}
                :on-success (fn [_]
                              [::params-change params])}
      :dispatch-n [[::data-page/reset-checked ::page]
                   [::modal/modal-closed]]})))
(re-frame/reg-event-fx
 ::delete-selected
 (fn [cofx [_ params suppress]]
   (let [checked @(re-frame/subscribe [::data-page/checked ::page])
         checked-params (get checked "header")
         specific-transactions (map :id (vals (dissoc checked "header")))]
     {:db (-> (:db cofx)
              (assoc-in [:status :loading] true))
      :graphql {:token (-> cofx :db :user)
                :owns-state {:single ::delete-selected}
                :query-obj
                {:venia/operation {:operation/type :mutation
                                   :operation/name "DeleteTransactions"}
                 :venia/queries [{:query/data
                                  [:delete-transactions
                                   {:filters (some-> checked-params data-params->query-params)
                                    :ids specific-transactions
                                    :suppress suppress}
                                   [:message]]}]}
                :on-success (fn [_]
                              [::params-change params])}
      :dispatch-n [[::data-page/reset-checked ::page]
                   [::modal/modal-closed]]})))

(re-frame/reg-event-fx
  ::delete-selected-requested
  (fn [_ [_ params suppress]]
    (let [checked @(re-frame/subscribe [::data-page/checked ::page])
          to-delete (if (get checked "header")
                      "all visible transactions"
                      (str (count checked) " transactions"))]
      {:dispatch [::modal/modal-requested {:title       "Confirmation"
                                           :body        [:div (str "Are you sure you want to delete " to-delete "?")]
                                           :cancel?     true
                                           :confirm     {:value       "Delete"
                                                         :class       "is-danger"
                                                         :status-from [::status/single ::delete-selected]
                                                         :on-click    (dispatch-event [::delete-selected params suppress] )}
                                           :close-event [::status/completed ::delete-selected]}]})))



(re-frame/reg-event-fx
 ::unmounted
 (fn [{:keys []} _]
   {:dispatch-n [[::data-page/dispose ::page]
                 [::status/dispose-single ::manual-import]]
    ::track/dispose {:id ::params}
    ::forward/dispose [{:id ::updated}
                       {:id ::manual-import}]}))

(re-frame/reg-event-fx
 ::mounted
 (fn [{:keys [db]} _]
   (let [db (if (:date-range (u/query-params))
              db
             (assoc-in db [::data-page/settled-filters ::page :date-range] {:start (date->str (time/plus (time/now) (time/months -1))
                                                                                                 standard)}))]
     {:db db
      ::track/register {:id ::params
                        :subscription [::data-page/params ::page]
                        :event-fn (fn [params]
                                    [::params-change params])}
      ::forward/register [{:id ::updated
                           :events #{::edit/edited}
                           :event-fn (fn [[_ edited-transaction]]
                                       [::data-page/updated-entity ::page edited-transaction])}
                          {:id ::manual-import
                           :events #{::manual/import-completed}
                           :event-fn (fn [[_ result]]
                                       [::status/info ::manual-import
                                        (str "Successfully "
                                             (str/join ", "
                                                       [(when-let [imported (:import-batch/imported result)]
                                                          (str "imported " imported))
                                                        (when-let [extant (:import-batch/extant result)]
                                                          (str "extant " extant))
                                                        (when-let [suppressed (:import-batch/suppressed result)]
                                                          (str "suppressed " suppressed))
                                                        (when-let [not-ready (:import-batch/not-ready result)]
                                                          (str "too early " not-ready))
                                                        (when-let [error (:validation-error result)]
                                                          (str "errored " error))])
                                             " transactions."
                                             (when (:sample-error result)
                                               (str " Sample error: " (:info (:sample-error result)))))])}]})))

(defn action-buttons []
  (let [is-admin? @(re-frame/subscribe [::subs/is-admin?])
        params    @(re-frame/subscribe [::data-page/params ::page])
        checked   @(re-frame/subscribe [::data-page/checked ::page])
        {:keys [total]} @(re-frame/subscribe [::data-page/data ::page])
        client @(re-frame/subscribe [::subs/client])]
    (when is-admin?
      [:<>
       [:div.level-item
        [:div.tags
         (map (fn [[z {:keys [id]}]]
                (if (= "header" z)
                  ^{:key "header"}
                  [:span.tag.is-medium {:on-click
                                        (dispatch-event [::data-page/remove-check ::page "header"])}
                   "All visible transactions"]

                  ^{:key id}
                  [:span.tag.is-medium id
                   [:button.delete.is-small {:on-click
                                             (dispatch-event [::data-page/remove-check ::page id])}]]))
              checked)]]
       [:div.level-item
        [:div.buttons 
         [:button.button.is-outlined.is-primary {:on-click (dispatch-event [::manual/opening])}
          "Manual Yodlee Import"]
         [:button.button.is-warning {:on-click (dispatch-event [::bulk/code-requested checked params total])
                                     :disabled (not (seq checked))}
          "Code"]
         [:button.button.is-danger {:on-click (dispatch-event [::delete-selected-requested params false])
                                    :disabled (not (seq checked))}
          "Delete"]
         [:button.button.is-danger {:on-click (dispatch-event [::delete-selected-requested params true])
                                    :disabled (not (seq checked))}
          "Suppress"]]]])))


(defn content []
  (let [is-admin? @(re-frame/subscribe [::subs/is-admin?])
        _ @(re-frame/subscribe [::data-page/params ::page])]
    [:div 
     [:h1.title "Transactions"]
     [status/status-notification {:statuses [[::status/single ::delete-selected]
                                             [::status/single ::manual-import]]}]
     
     [table/table {:id :transactions
                   :check-boxes? is-admin?
                   :data-page ::page
                   :action-buttons [action-buttons]}]]))


(defn transactions-page [{:keys [approval-status]}]
  (reagent/create-class
   {:display-name "transaction-page"
    :component-will-unmount #(re-frame/dispatch [::unmounted])
    :component-did-mount #(re-frame/dispatch [::mounted])
    :reagent-render
    (fn []
      (let [{transaction-bar-active? :active?} @(re-frame/subscribe [::forms/form ::edit/form])]
        [side-bar-layout
         {:side-bar [side-bar/side-bar {:data-page ::page}]
          :main [:div ^{:key approval-status}
                 [content]]
          :right-side-bar [appearing-side-bar
                           {:visible? transaction-bar-active?}
                           [edit/form]]}]))}))

