(ns auto-ap.events
  (:require [re-frame.core :as re-frame]
            [auto-ap.db :as db]
            [auto-ap.subs :as subs]
            [auto-ap.routes :as routes]
            [auto-ap.effects :as effects]
            [auto-ap.utils :refer [by]]
            [venia.core :as v]
            [bidi.bidi :as bidi]
            [cemerick.url :refer [url]]
            [goog.crypt.base64 :as b64]
            [clojure.string :as str]))

(defn jwt->data [token]
  (js->clj (.parse js/JSON (b64/decodeString (second (str/split token #"\." ))))))

(re-frame/reg-event-fx
 ::initialize-db
 (fn  [{:keys [db]} [_ token]]
   (let [handler (:handler (bidi/match-route routes/routes (.. js/window -location -pathname)))]
     (prn (and token (get (jwt->data token) "user/role")))
     (cond
       (and (not= :login handler) (not token))
       {:redirect "/login"
        :db (assoc db/default-db
                   :active-page :login
                   :user token)}

       (and token (= "none" (or (get (jwt->data token) "role") (get (jwt->data token) "user/role")) ))
       {:redirect "/needs-activation"
        :db (assoc db/default-db
                   :active-page :needs-activation
                   :user token)}

       :else
       {:db (assoc db/default-db
                   :active-page handler
                   :query-params (->> (:query (url (.-location js/window)))
                                       (map (fn [[k v]] [(keyword k) v]))
                                       (into {}))
                   :user token)
        :graphql {:token token
                  :query-obj {:venia/queries [[:client

                                               [:id :name :code :email :locations [:bank-accounts [:id :code :number :bank-name :bank-code :check-number :name :routing :type] ]
                                                [:address [:street1 :street2 :city :state :zip]]]]
                                              [:vendor
                                               [:id :name :default-expense-account [:primary-contact [:name :phone :email :id]] [:secondary-contact [:id :name :phone :email]] :print-as :invoice-reminder-schedule :code]]]}
                  
                  :on-success [::received-initial]}}))))
(def vendor-query
  [:id :name :default-expense-account
   [:primary-contact [:name :phone :email :id]]
   [:secondary-contact [:id :name :phone :email]]
   :print-as :invoice-reminder-schedule :code
   [:address [:street1 :street2 :city :state :zip]]])

(re-frame/reg-event-db
 ::toggle-menu
 (fn  [db [_ which]]
   (update-in db [:menu which :active?] #(not %))))

(re-frame/reg-event-fx
 ::logged-in
 (fn  [{:keys [db]} [_ token user]]
   {:graphql {:token token
              :query-obj {:venia/queries [[:client
                                           [:id :name :code [:address [:street1 :street2 :city :state :zip]] [:bank-accounts [:id :code :number :bank-name :bank-code :check-number :name :routing :type] ]]]
                                          [:vendor
                                           [:id :name :default-expense-account [:primary-contact [:name :phone :email :id]] [:secondary-contact [:id :name :phone :email]] :print-as :invoice-reminder-schedule :code]]]}
              
              :on-success [::received-initial]}
    :db (assoc db :user (assoc user :token token))}))

(re-frame/reg-event-db
 ::received-initial
 (fn  [db [_ {clients :client vendors :vendor :as x}]]
   (-> db 
       (assoc :clients (by :id clients) )
       (assoc :vendors (by :id vendors) )
       (assoc :client (when (= 1 (count clients)) (->> clients first :id ))))))

(re-frame/reg-event-db
 ::swap-client
 (fn  [db [_ client]]
   (assoc db :client (:id client))))

(re-frame/reg-event-db
 ::change-form
 (fn  [db [_ location field value]]
   (if value
     (assoc-in db (into location field) value)
     (update-in db (into location (butlast field)) dissoc (last field)))))

(re-frame/reg-event-db
 ::modal-status
 (fn  [db [_ id  state]]
   (println "changing modal status" id "to")
   (update-in db [:modal-state id] #(merge % state))))

(re-frame/reg-event-db
 ::modal-failed
 (fn  [db [_ id  message]]
   (-> db
       (assoc-in [:modal-state id :saving?] false)
       (assoc-in [:modal-state id :error-message] message))))

(re-frame/reg-event-db
 ::modal-completed
 (fn  [db [_ id  state]]
   (update-in db [:modal-state] #(dissoc % id))))

(re-frame/reg-event-fx
 ::set-active-page
 (fn  [{:keys [db]} [_ handler params]]
   (println "PARAMS" params)
   (if (and (not= :login handler) (not (:user db)))
     {:redirect "/login"
      :db (assoc db :active-page :login)}
     {:db (assoc db :active-page handler
                 :query-params params)})))

(re-frame/reg-event-db
 ::imported-invoices
 (fn  [db [_ new-invoices]]
   (assoc-in db [:invoices :pending] new-invoices)))

(re-frame/reg-event-fx
 ::view-pending-invoices
 (fn [cofx []]
   {:db (assoc-in (:db cofx) [:status :loading] true)
    :graphql {:token (-> cofx :db :user)
              :query-obj {:venia/queries [[:invoice
                                           {:imported false :client_id (:id @(re-frame/subscribe [::subs/client]))}
                                           [:id :total :invoice-number :date [:vendor [:name :id]] [:client [:name :id]]]]]}
              
              :on-success [::received-invoices :pending]}}))

(re-frame/reg-event-fx
 ::view-unpaid-invoices
 (fn [cofx []]
   {:db (assoc-in (:db cofx) [:status :loading] true)
    :graphql {:token (-> cofx :db :user)
              :query-obj {:venia/queries [[:invoice
                                           {:imported true :client_id (:id @(re-frame/subscribe [::subs/client]))}
                                           [:id :total :invoice-number :date [:vendor [:name :id]] [:client [:name :id]]]]]} 
              :on-success [::received-invoices :unpaid]}}))

(re-frame/reg-event-db
 ::submitted-new-invoice
 (fn  [db [_ invoice]]
   (assoc db :new-invoice {})))

(re-frame/reg-event-fx
 ::logout
 (fn  [{:keys [db]} [_]]
   {:db (assoc db :user nil :menu {:client {:active? false}
                                   :account {:active? false}})
    :redirect (bidi/path-for routes/routes :login)
    :set-local-storage ["jwt" nil]}))

(re-frame/reg-event-fx
 ::submit-new-invoice
 (fn  [{:keys [db]} [_ invoice]]
   {:http {:method :post
           :token (-> db :user)
           :uri "/api/invoices"
           :body (pr-str {:rows [(assoc invoice :imported true)]})
           :headers {"Content-Type" "application/edn"}
           :on-success [::submitted-new-invoice]}
    :db (assoc-in db [:new-invoice :loading?] true)}))

(re-frame/reg-event-db
 ::received-invoices
 (fn  [db [_ type result]]
   (let [new-invoices (if (:invoice result)
                        (:invoice result)
                        result)]
     (-> db
         (assoc-in [:invoices type]  new-invoices)
         (assoc-in [:status :loading] false)))))

(re-frame/reg-event-db
 ::change-form-state
 (fn  [db [_ target value]]
   (assoc-in db target value)))

(re-frame/reg-event-db
 ::change-nested-form-state
 (fn  [db [_ form more value]]
   (update-in db form
              (fn [x]
                (assoc-in x more value)))))

(re-frame/reg-event-fx
 ::save-vendor
 (fn  [{:keys [db]} _]
   (let [edited-vendor (get-in db [:user-editing-vendor])]
     (assoc {} :graphql
            {:token (-> db :user)
             :query-obj {:venia/operation {:operation/type :mutation
                                           :operation/name "UpsertVendor"}
                         
                         :venia/queries [{:query/data [:upsert-vendor
                                                       {:vendor edited-vendor}
                                                       vendor-query]}]}  
             :on-success [::save-complete]
             :on-error [::save-error]}))))
(re-frame/reg-event-fx
 ::save-complete
 (fn  [{:keys [db]} [_ vendor]]
   {:dispatch [::modal-completed :auto-ap.views.main/user-editing-vendor ]
    :db (-> db
            (dissoc :user-editing-vendor)
            (assoc-in [:vendors (:id vendor)] (:upsert-vendor vendor)))}))
