(ns auto-ap.views.components.expense-accounts-dialog
  (:require
   [auto-ap.forms :as forms]
   [auto-ap.status :as status]
   [auto-ap.utils :refer [by]]
   [auto-ap.views.components.modal :as modal]
   [auto-ap.views.components.typeahead.vendor :refer [search-backed-typeahead]]
   [auto-ap.views.pages.invoices.common :refer [invoice-read]]
   [auto-ap.views.utils :refer [dispatch-event with-user]]
   [clojure.string :as str]
   [goog.string :as gstring]
   [re-frame.core :as re-frame]
   [auto-ap.forms.builder :as form-builder]
   [auto-ap.views.components :as com]))

(re-frame/reg-event-fx
 ::try-save
 [(forms/in-form ::form)]
 (fn [{:keys [db]} _]
   (let [{{:keys [ total]} :invoice
          :keys [expense-accounts]} (:data db)
         expense-accounts (vals expense-accounts)
         expense-accounts-total (->> expense-accounts
                                     (map :new-amount)
                                     (map js/parseFloat)
                                     (map #(or % 0.0))
                                     (map #(if (js/Number.isNaN %)
                                             0.0
                                             %))
                                     (reduce + 0))
         does-add-up? (< (Math/abs (- expense-accounts-total (js/parseFloat total))) 0.001)]

     (if (and does-add-up?
              (every? :new-amount expense-accounts))
       
       {:dispatch [::save]}
       {:dispatch [::status/error ::form [{:message "Expense accounts do not add up."}]]}))))



(re-frame/reg-event-fx
 ::save
 [with-user (forms/in-form ::form)]
 (fn [{:keys [db user] } _]
   (let [{{:keys [id]} :invoice
          :keys [expense-accounts]} (:data db)
         expense-accounts (vals expense-accounts)]
     {:graphql
      {:token user
       :owns-state {:single ::form}
       :query-obj {:venia/operation {:operation/type :mutation
                                     :operation/name "EditExpenseAccounts"}
                   
                   :venia/queries [{:query/data [:edit-expense-accounts
                                                 {:invoice-id  id
                                                  :expense-accounts (map (fn [ea] {:id (if (clojure.string/includes? (str (:id ea)) "new-")
                                                                                         nil
                                                                                         (:id ea))
                                                                                   :amount (:new-amount ea)
                                                                                   :location (:location ea)
                                                                                   :account-id (:id (:account ea))})
                                                                         expense-accounts)}
                                                 invoice-read]}]}  
       :on-success (fn [result]
                     [::updated (:edit-expense-accounts result)])}})))

(re-frame/reg-event-fx
 ::updated
 (fn [_ _]
   {:dispatch [::modal/modal-closed]}))

(re-frame/reg-event-db
 ::add-split
 [(forms/in-form ::form)]
 (fn [db _]
   (update-in db [:data :expense-accounts]
              assoc (str "new-" (random-uuid)) {:amount "0.0"   :account nil :location (-> db :data :invoice :client :locations first) })))

(re-frame/reg-event-db
 ::remove-expense-account-split
 [(forms/in-form ::form)]
 (fn [db [_ x]]
   (update-in db [:data :expense-accounts] dissoc x)))

(defn form []
  (let [{:keys [data]} @(re-frame/subscribe [::forms/form ::form])
        expense-accounts (:expense-accounts data)
        {:keys [total] :or {total 0} {:keys [locations] :as client} :client} (:invoice data)
        multi-location? (> (count locations) 1)
        expense-accounts-total (->> expense-accounts
                                    vals
                                    (map :new-amount)
                                    (map js/parseFloat)
                                    (map #(or % 0.0))
                                    (map #(if (js/Number.isNaN %)
                                            0.0
                                            %))
                                    (reduce + 0))]
    [:div
     [:div
      [:a.button.is-outlined {:on-click (dispatch-event [::add-split])} "Add split"]]
     [form-builder/builder {:submit-event [::try-save]
                            :id           ::form}
      [:table.table
       [:thead
        [:tr
         [:th {:style {:width "500px"}} "Expense Account"]
         (when multi-location?
           [:th {:style {:width "200px"}} "Location"])
         [:th {:style {:width "200px"}} "Original Amount"]
         [:th {:style {:width "300px"}} "Amount"]
         [:th {:style {:width "5em"}}]]]
       [:tbody
        (doall (for [[id a] expense-accounts]
                 ^{:key id}
                 [:tr {:class (when (:warning (:account a))
                                "has-background-warning-light")}
                  [:td.expandable [:div.control
                                   [form-builder/raw-field-v2 {:field [:expense-accounts id :account]}
                                    [search-backed-typeahead {:search-query (fn [i]
                                                                              [:search_account
                                                                               {:query     i
                                                                                :client-id (:id client)
                                                                                :vendor-id (:id (:vendor (:invoice data)))
                                                                                :allowance :invoice}
                                                                               [:name :id :location :warning]])
                                                              :class "is-warn"}]]]]

                  (when multi-location?
                    [:td
                     (if-let [forced-location (get-in expense-accounts [id :account :location])]
                       [:div.select
                        [:select {:disabled "disabled" :value forced-location} [:option {:value forced-location} forced-location]]]
                       [:div.select

                        [form-builder/raw-field-v2 {:field [:expense-accounts id :location]}
                         [com/select-field {:options (map (fn [l] [l l])
                                                         locations)
                                           :allow-nil? true}]]])])
                  
                  [:td
                   (str "$" (get-in expense-accounts [id :amount]))]
                  [:td
                   [:div.control
                    [:div.field.has-addons.is-extended
                     [:p.control [:a.button.is-static "$"]]
                     [:p.control
                      [form-builder/raw-field-v2 {:field [:expense-accounts id :new-amount-temp]}
                       [:input.input {:type        "number"
                                      :style       {:text-align "right"}
                                      :on-blur     (dispatch-event [::forms/change ::form [:expense-accounts id :new-amount] (get-in expense-accounts [id :new-amount-temp])])
                                      :on-key-down (fn [e ]
                                                     (if (= 13 (.-keyCode e))
                                                       (do 
                                                         (re-frame/dispatch [::forms/change ::form [:expense-accounts id :new-amount] (get-in expense-accounts [id :new-amount-temp])])
                                                         true)
                                                       false))
                                      :max         (:total data)
                                      :step        "0.01"}]]]]]]
                  [:td [:a.button {:on-click (dispatch-event [::remove-expense-account-split id])} [:i.fa.fa-times]]]]))
        [:tr
         [:td.no-border { :col-span (if multi-location? "3" "2") :style { :text-align "right"} } "Invoice total: "]
         [:td.no-border { :style { :text-align "right"} } (str (gstring/format "$%.2f" total ) )]]
        [:tr
         [:td { :col-span (if multi-location? "3" "2") :style { :text-align "right"} } "Account total: "]
         [:td { :style { :text-align "right"} } (str (gstring/format "$%.2f" expense-accounts-total ) )]]
        [:tr
         [:td.no-border { :col-span (if multi-location? "3" "2") :style { :text-align "right"} } "Difference: "]
         [:td.no-border { :style { :text-align "right"} } (str (gstring/format "$%.2f" (- total expense-accounts-total) ) )]]]]
      [form-builder/hidden-submit-button]]]))

(re-frame/reg-event-fx
 ::show
 (fn [{:keys [db]} [_ i]]
   {:dispatch [::modal/modal-requested {:title   "Change expense accounts"
                                        :body    [form]
                                        :confirm {:value       "Save"
                                                  :status-from [::status/single ::form]
                                                  :class       "is-primary"
                                                  :on-click    (dispatch-event [::try-save])
                                                  :close-event [::status/completed ::form]}}]
    :db       (-> db
                  (forms/start-form ::form

                                    {:expense-accounts (by :id
                                                           (:expense-accounts i))
                                     :invoice          i}))}))
