(ns auto-ap.views.pages.payments
  (:require
   [auto-ap.effects.forward :as forward]
   [auto-ap.status :as status]
   [auto-ap.subs :as subs]
   [auto-ap.views.components.layouts :refer [side-bar-layout]]
   [auto-ap.views.components.modal :as modal]
   [auto-ap.views.pages.data-page :as data-page]
   [auto-ap.views.pages.payments.side-bar :as side-bar]
   [auto-ap.views.pages.payments.table :as table]
   [auto-ap.views.utils :refer [dispatch-event nf with-user date->str standard]]
   [cljs-time.core :as time]
   [clojure.set :as set]
   [goog.string :as gstring]
   [re-frame.core :as re-frame]
   [reagent.core :as reagent]
   [vimsical.re-frame.fx.track :as track]))

(defn data-params->query-params [params]
  (if (:exact-match-id params) 
    {:client-id         (:id @(re-frame/subscribe [::subs/client]))
     :exact-match-id    (some-> (:exact-match-id params) str)}
    {:start             (:start params 0)
     :per-page          (:per-page params)
     :sort              (:sort params)
     :client-id         (:id @(re-frame/subscribe [::subs/client]))
     :vendor-id         (:id (:vendor params))
     :payment-type      (:payment-type params)
     :status            (:status params)
     
     :date-range        (:date-range params)
     :amount-gte        (:amount-gte (:amount-range params))
     :amount-lte        (:amount-lte (:amount-range params))
     :check-number-like (str (:check-number-like params))
     :invoice-number    (:invoice-number params)}))

(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 [[:payment_page
                                            {:filters (data-params->query-params params)}
                                            [[:payments [:id :status :amount :type :check_number :s3_url
                                                         [:bank-account [:name]]
                                                         :date [:vendor [:name :id]] [:client [:name :id]]
                                                         [:invoices [:invoice-id [:invoice [:invoice-number :id]]
                                                                     :amount]]
                                                         [:transaction [:id :date]]]]
                                             :total
                                             :start
                                             :end]]]} 
              :on-success (fn [result]
                            (let [result (set/rename-keys (first (:payment-page result))
                                                          {:payments :data})]
                              [::data-page/received ::page result]))}}))


(re-frame/reg-event-fx
 ::unmounted
 (fn [{:keys [db]} _]
   {:dispatch [::data-page/dispose ::page]
    :db (-> db (status/reset-multi ::table/void))
    ::track/dispose {:id ::params}
    ::forward/dispose {:id ::page}}))

(re-frame/reg-event-fx
 ::mounted
 (fn [{:keys [db]} _]
   {:db (assoc-in db [::data-page/settled-filters ::page :date-range] {:start (date->str (time/plus (time/now) (time/months -1))
                                                                                         standard)})
    ::track/register {:id ::params
                      :subscription [::data-page/params ::page]
                      :event-fn (fn [params]
                                  [::params-change params])}
    ::forward/register {:id ::page
                        :events #{::table/payment-voided}
                        :event-fn (fn [[_ {:keys [void-payment]}]]
                                    [::data-page/updated-entity ::page (assoc void-payment :class "live-removed")])}}))

(re-frame/reg-event-fx
  ::voided-selected
  (fn [_ _]
    {:dispatch-n [[::modal/modal-closed]
                  [::params-change @(re-frame/subscribe [::data-page/params ::page])]
                  [::data-page/reset-checked ::page]]}))

(re-frame/reg-event-fx
  ::void-selected
  (fn [cofx [_ which]]
    (let [checked-params    (get which "header")
          specific-invoices (map :id (vals (dissoc which "header")))]
      {:graphql  {:token      (-> cofx :db :user)
                  :owns-state {:single ::void-selected}
                  :query-obj
                  {:venia/operation {:operation/type :mutation
                                     :operation/name "VoidPayments"}
                   :venia/queries   [{:query/data
                                      [:void-payments
                                       {:filters (some-> checked-params data-params->query-params)
                                        :ids     specific-invoices}
                                       [:message]]}]}
                  :on-success (fn [_]
                                [::voided-selected])}})))


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

(defn void-selected-button []
  (let [status           @(re-frame/subscribe [::status/single ::void-selected])
        checked-payments @(re-frame/subscribe [::data-page/checked ::page])
        is-admin?        @(re-frame/subscribe [::subs/is-admin?])]
    (when is-admin? 
      [:button.button.is-danger {:on-click (dispatch-event [::void-selected-requested checked-payments])
                                 :class    (status/class-for status)
                                 :disabled (or (status/disabled-for status)
                                               (not (seq checked-payments)))}
       " Void"])))

(defn action-buttons []
  (let [checked-payments @(re-frame/subscribe [::data-page/checked ::page])]
    [:<>
     [:div.level-item
      (into [:div.tags ] (map (fn [[z {:keys [id check-number type amount]}]]
                                (if (= z "header")
                                  [:span.tag.is-medium "All visible payments"
                                   [:button.delete.is-small {:on-click
                                                             (dispatch-event [::data-page/remove-check ::page z])}]]
                                  [:span.tag.is-medium (cond
                                                         (= :cash type)  (gstring/format "Cash (%s)" (nf amount ))
                                                         (= :debit type) (gstring/format "Debit (%s)" (nf amount ))
                                                         :else           (gstring/format "Check #%d (%s)" check-number (nf amount )))
                                   [:button.delete.is-small {:on-click
                                                             (dispatch-event [::data-page/remove-check ::page id])}]]))
                              checked-payments))]
     [:div.level-item 
      [:div.buttons
       [void-selected-button]]]]))

(defn content []
  [:div
   [:h1.title "Payments"]
   [status/status-notification {:statuses [[::status/last-multi ::table/void]]}]
   [table/table {:id :payments
                 :data-page ::page
                 :action-buttons [action-buttons]}]])

(defn payments-page []
  (reagent/create-class
   {:display-name "payments-page"
    :component-will-unmount #(re-frame/dispatch-sync [::unmounted])
    :component-did-mount #(re-frame/dispatch [::mounted])
    :reagent-render
    (fn []
      [side-bar-layout {:side-bar [side-bar/side-bar {:data-page ::page}]
                        :main [content]}])}))
