(ns auto-ap.views.components.vendor-dialog
  (:require
   [auto-ap.forms :as forms]
   [auto-ap.forms.builder :as form-builder]
   [auto-ap.schema :as schema]
   [auto-ap.status :as status]
   [auto-ap.subs :as subs]
   [auto-ap.views.components :as com]
   [auto-ap.views.components.address :refer [address2-field]]
   [auto-ap.views.components.level :refer [left-stack]]
   [auto-ap.views.components.modal :as modal]
   [auto-ap.views.components.multi :refer [multi-field-v2]]
   [auto-ap.views.components.number :refer [number-input]]
   [auto-ap.views.components.typeahead :refer [typeahead-v3]]
   [auto-ap.views.components.typeahead.vendor
    :refer [search-backed-typeahead]]
   [auto-ap.views.utils
    :refer [dispatch-event str->int with-is-admin? with-user]]
   [malli.core :as m]
   [re-frame.core :as re-frame]))

;; Remaining cleanup todos:
;; test minification

(def default-read [:id :name :hidden :terms [:default-account [:name :id :location]]
                   [:account-overrides [[:client [:id :name]] :id [:account [:id :numeric-code :name]]]]
                   [:automatically-paid-when-due [:id :name]]
                   [:terms-overrides [[:client [:id :name]] :id :terms]]
                   [:schedule-payment-dom [[:client [:id :name]] :id :dom]]
                   [:usage [:client-id :count]]
                   [:primary-contact [:name :phone :email :id]]
                   [:plaid-merchant [:name :id]]
                   [:secondary-contact [:id :name :phone :email]]
                   :print-as :invoice-reminder-schedule :code
                   :legal-entity-name
                   :legal-entity-first-name :legal-entity-middle-name :legal-entity-last-name
                   :legal-entity-tin :legal-entity-tin-type
                   :legal-entity-1099-type
                   [:address [:id :street1 :street2 :city :state :zip]]])

(def terms-override-schema (m/schema [:map
                                      [:client schema/reference]
                                      [:terms :int]]))

(def automatically-paid-schema (m/schema [:map
                                          [:client schema/reference]]))

(def schedule-payment-dom-schema (m/schema [:map
                                            [:client schema/reference]
                                            [:dom [:int {:max 30}]]]))

(def account-override-schema (m/schema [:map
                                        [:client schema/reference]
                                        [:account schema/reference]]))

(def schema (m/schema [:map [:name schema/not-empty-string]
                       [:print-as {:optional true}
                        [:maybe :string]]
                       [:hidden {:optional true}
                        [:maybe :boolean]]
                       [:terms {:optional true}
                        [:maybe :int]]
                       [:terms-overrides {:optional true}
                        [:maybe [:sequential terms-override-schema]]]
                       [:schedule-payment-dom {:optional true}
                        [:maybe [:sequential schedule-payment-dom-schema]]]
                       [:default-account schema/reference]
                       [:account-overrides {:optional true}
                        [:sequential account-override-schema]]
                       [:legal-entity-name {:optional true}
                        [:maybe :string]]
                       [:legal-entity-first-name {:optional true}
                        [:maybe :string]]
                       [:legal-entity-middle-name {:optional true}
                        [:maybe :string]]
                       [:legal-entity-last-name {:optional true}
                        [:maybe :string]]
                       [:legal-entity-tin {:optional true}
                        [:maybe :string]]
                       [:legal-entity-tin-type {:optional true}
                        [:or [:maybe :string]
                         [:maybe keyword?]]]
                       [:legal-entity-1099-type {:optional true}
                        [:or [:maybe :string]
                         [:maybe keyword?]]]]))

(re-frame/reg-event-fx
 ::save-complete
 [(forms/triggers-stop ::vendor-form)]
 (fn  [_ [_ _]]
   {:dispatch [::modal/modal-closed]}))

(re-frame/reg-event-fx
 ::save
 [with-user with-is-admin? (forms/triggers-loading ::vendor-form) (forms/in-form ::vendor-form)]
 (fn  [{:keys [user is-admin?] {{:keys [name hidden print-as terms invoice-reminder-schedule plaid-merchant primary-contact automatically-paid-when-due schedule-payment-dom secondary-contact address default-account terms-overrides account-overrides id legal-entity-name legal-entity-tin legal-entity-tin-type legal-entity-first-name legal-entity-last-name legal-entity-middle-name legal-entity-1099-type] :as data} :data} :db} _]
   (if (m/validate schema data)
     (let [query [:upsert-vendor
                  {:vendor (cond-> {:id id
                                    :name name
                                    :print-as print-as
                                    :terms (or terms
                                               nil)
                                    :default-account-id (:id default-account)
                                    :address address
                                    :primary-contact primary-contact
                                    :secondary-contact secondary-contact
                                    :invoice-reminder-schedule invoice-reminder-schedule}
                             is-admin? (assoc :hidden hidden
                                              :terms-overrides (mapv
                                                                (fn [{:keys [client terms id]}]
                                                                  {:id        id
                                                                   :client-id (:id client)
                                                                   :terms     (or (str->int terms) 0)})
                                                                terms-overrides)
                                              :account-overrides (mapv
                                                                  (fn [{:keys [client account id]}]
                                                                    {:id         id
                                                                     :client-id  (:id client)
                                                                     :account-id (:id account)})
                                                                  account-overrides)
                                              :schedule-payment-dom (mapv
                                                                     (fn [{:keys [client dom id]}]
                                                                       {:id        id
                                                                        :client-id (:id client)
                                                                        :dom       (or (str->int dom)
                                                                                       0)})
                                                                     schedule-payment-dom)
                                              :automatically-paid-when-due (mapv
                                                                            (comp :id :client)
                                                                            automatically-paid-when-due)
                                              :plaid-merchant (:id plaid-merchant)
                                              :legal-entity-name legal-entity-name
                                              :legal-entity-first-name legal-entity-first-name
                                              :legal-entity-middle-name legal-entity-middle-name
                                              :legal-entity-last-name legal-entity-last-name
                                              :legal-entity-tin legal-entity-tin
                                              :legal-entity-tin-type (some-> legal-entity-tin-type clojure.core/name not-empty keyword)
                                              :legal-entity-1099-type (some-> legal-entity-1099-type  clojure.core/name not-empty keyword)))}
                  default-read]]
       {:graphql
        {:token      user
         :owns-state {:single ::vendor-form}
         :query-obj  {:venia/operation
                      {:operation/type :mutation
                       :operation/name "UpsertVendor"} :venia/queries [{:query/data query}]}
         :on-success [::save-complete]}})

     {:dispatch-n [[::forms/attempted-submit ::vendor-form]
                   [::status/error ::vendor-form [{:message "Please fix the errors and try again."}]]]})))

(defn contact-field [{:keys [name field]}]
  [form-builder/with-scope {:scope field}
   [form-builder/vertical-control
    name
    [left-stack
     [form-builder/vertical-control {:is-small? true}
      "Name"
      [:div.control.has-icons-left
       [form-builder/raw-field-v2 {:field :name}
        [:input.input.is-expanded {:type  "text"}]]
       [:span.icon.is-small.is-left
        [:i.fa.fa-user]]]]
     [form-builder/vertical-control  {:is-small? true}
      "Email"

      [:div.control.has-icons-left
       [:span.icon.is-small.is-left
        [:i.fa.fa-envelope]]
       [form-builder/raw-field-v2 {:field :email}
        [:input.input {:type  "email"}]]]]
     [form-builder/vertical-control {:is-small? true}
      "Phone"
      [:div.control.has-icons-left
       [form-builder/raw-field-v2 {:field :phone}
        [:input.input {:type  "phone"}]]
       [:span.icon.is-small.is-left
        [:i.fa.fa-phone]]]]]]])



(defn form-content []
  (let [is-admin? @(re-frame/subscribe [::subs/is-admin?])
        clients   @(re-frame/subscribe [::subs/client-refs])
        {vendor :data} @(re-frame/subscribe [::forms/form ::vendor-form])]
    [form-builder/builder {:submit-event [::save]
                           :id           ::vendor-form
                           :schema schema}
     [form-builder/field-v2 {:field :name
                             :required true}
      "Name"
      [:input.input {:auto-focus true}]]

     [form-builder/field-v2 {:field :print-as}
      "Print Checks As"
      [:input.input]]
     (when is-admin?
       [:<>
        [form-builder/raw-field-v2 {:field :hidden}
         [com/checkbox {:label "Hidden"}]]

        [form-builder/field-v2 {:field     :plaid-merchant
                                :required? false}
         "Plaid merchant"
         [search-backed-typeahead {:search-query (fn [i]
                                                   [:search_plaid_merchants
                                                    {:query     i}
                                                    [:name :id]])
                                   :style        {:width "19em"}}]]])

     [form-builder/section {:title "Terms"}
      [form-builder/field-v2 {:field :terms}
       "Terms"
       [number-input]]
      (when is-admin?
        [form-builder/field-v2 {:field [:terms-overrides]}
         "Overrides"
         [multi-field-v2 {:template [[form-builder/raw-field-v2 {:field [:client]}
                                      [typeahead-v3 {:entities     clients
                                                     :entity->text :name
                                                     :style        {:width "13em"}
                                                     :type         "typeahead-v3"}]]
                                     [form-builder/raw-field-v2 {:field :terms}
                                      [number-input]]]
                          :schema   [:sequential terms-override-schema]
                          :key-fn   :id
                          :next-key (random-uuid)
                          :new-text "New Terms Override"}]])]

     (when is-admin?
       [form-builder/section {:title "Schedule payment when due"}
        [form-builder/field-v2 {:field [:automatically-paid-when-due]}
         "Client"
         [multi-field-v2 {:template [[form-builder/raw-field-v2 {:field :client}
                                      [typeahead-v3 {:entities     clients
                                                     :entity->text :name
                                                     :style        {:width "13em"}}]]]
                          :schema [:sequential automatically-paid-schema]
                          :key-fn :id
                          :next-key (random-uuid)
                          :new-text "Schedule another client"}]]])

     (when is-admin?
       [form-builder/section {:title "Schedule payment on day of month"}
        [form-builder/field-v2 {:field [:schedule-payment-dom]}
         "Overrides"
         [multi-field-v2 {:template [[form-builder/raw-field-v2 {:field :client}
                                      [typeahead-v3 {:entities     clients
                                                     :entity->text :name
                                                     :style        {:width "13em"}}]]
                                     [form-builder/raw-field-v2  {:field :dom}
                                      [number-input]]]
                          :schema [:sequential schedule-payment-dom-schema]
                          :key-fn :id
                          :next-key (random-uuid)
                          :new-text "Schedule another client"}]]])
     [form-builder/section {:title "Expense Accounts"}
      [form-builder/field-v2 {:field :default-account
                              :required? true}
       "Default"
       [search-backed-typeahead {:search-query (fn [i]
                                                 [:search_account
                                                  {:query i
                                                   :allowance :vendor}
                                                  [:name :id :warning]])
                                 :style        {:width "19em"}}]]
      (when (:warning (:default-account vendor))
        [:div.notification.is-warning.is-light
         (:warning (:default-account vendor))])
      (when is-admin?
        [form-builder/field-v2 {:field [:account-overrides]}
         "Overrides"
         [multi-field-v2 {:template (fn [entity]
                                      [[form-builder/raw-field-v2 {:field :client}
                                        [typeahead-v3 {:entities     clients
                                                       :entity->text :name
                                                       :style        {:width "19em"}}]]
                                       [form-builder/raw-field-v2 {:field :account}
                                        [search-backed-typeahead {:search-query (fn [i]
                                                                                  [:search_account
                                                                                   {:query     i
                                                                                    :client_id (:id (:client entity))
                                                                                    :allowance :vendor}
                                                                                   [:name :id :warning]])
                                                                  :style        {:width "15em"}}]]])
                          :schema [:sequential account-override-schema]
                          :key-fn :id
                          :next-key (random-uuid)
                          :new-text "Add override"}]])]

     [form-builder/section {:title "Address"}
      [:div {:style {:width "30em"}}
       [form-builder/raw-field-v2 {:field :address}
        [address2-field]]]]

     [form-builder/section {:title "Contact"}
      [contact-field {:name "Primary"
                      :field [:primary-contact]}]
      [contact-field {:name  "Secondary"
                      :field [:secondary-contact]}]]

     (when is-admin?
       [form-builder/section {:title "Legal Entity"}
        [form-builder/field-v2 {:field :legal-entity-name}
         "Legal Entity Name"
         [:input.input {:type        "text"
                        :placeholder "Good Vendor LLC"}]]
        [:div
         "- OR -"]

        [form-builder/vertical-control
         "Name"
         [left-stack
          [:div.control
           [form-builder/raw-field-v2 {:field :legal-entity-first-name}
            [:input.input {:type        "text"
                           :placeholder "First Name"}]]]

          [:div.control
           [form-builder/raw-field-v2 {:field :legal-entity-middle-name}
            [:input.input {:type        "text"
                           :placeholder "Middle Name"}]]]

          [:div.control
           [form-builder/raw-field-v2 {:field :legal-entity-last-name}
            [:input.input {:type        "text"
                           :placeholder "Last Name"}]]]]]
        [form-builder/vertical-control
         "TIN"
         [left-stack
          [form-builder/raw-field-v2 {:field :legal-entity-tin}
           [:input.input {:type        "text"
                          :placeholder "SSN or EIN"
                          :size        "12"}]]

          [:div.control
           [form-builder/raw-field-v2 {:field :legal-entity-tin-type}
            [com/select-field {:options    [["ein" "EIN"]
                                            ["ssn" "SSN"]]
                               :allow-nil? true}]]]]]

        [form-builder/field-v2 {:field :legal-entity-1099-type}
         "1099 Type"
         [com/select-field {:options [["none" "Don't 1099"]
                                      ["misc" "Misc"]
                                      ["landlord" "Landlord"]]
                            :allow-nil? true}]]])
     [form-builder/hidden-submit-button]]))

(defn vendor-dialog []
  (let [{:keys [data]} @(re-frame/subscribe [::forms/form ::vendor-form])]
    [:div
     [form-content {:data data}]]))

(re-frame/reg-event-fx
 ::vendor-selected
 [with-user (forms/in-form ::select-vendor-form)]
 (fn [{{:keys [data]} :db :keys [user]} _]
   (if (:vendor data)
     {:graphql {:token      user
                :query-obj  {:venia/queries [[:vendor-by-id
                                              {:id (:id (:vendor data))}
                                              default-read]]}
                :owns-state {:single ::select-vendor-form}
                :on-success (fn [r]
                              [::started (:vendor-by-id r)])}}
     {:dispatch-n [[::forms/attempted-submit ::select-vendor-form]
                   [::status/error ::select-vendor-form [{:message "Please select a vendor."}]]]})))

(defn select-vendor-form-content []
  [form-builder/builder {:submit-event [::vendor-selected]
                         :id           ::select-vendor-form
                         :validation-error-string "Please select a vendor."
                         :schema [:map
                                  [:vendor schema/reference]]}
   [form-builder/field-v2 {:field :vendor
                           :required? true}
    "Vendor to edit"
    [search-backed-typeahead {:search-query (fn [i]
                                              [:search_vendor
                                               {:query i}
                                               [:name :id]])
                              :style {:width "20em"}
                              :auto-focus   true}]]
   [form-builder/hidden-submit-button]])



(re-frame/reg-event-fx
 ::started
 (fn  [{:keys [db]} [_ vendor]]
   {:db (-> db (forms/start-form ::vendor-form (-> vendor
                                                   (update :automatically-paid-when-due #(mapv (fn [apwd]
                                                                                                 apwd
                                                                                                 {:id (:id apwd)
                                                                                                  :client apwd})
                                                                                               %))
                                                   (update :hidden #(if (nil? %)
                                                                      false
                                                                      %)))))
    :dispatch [::modal/modal-requested
               {:title "Vendor"
                :body [vendor-dialog]
                :class "semi-wide"
                :status-from [::status/single ::vendor-form]
                :confirm {:value "Save Vendor"
                          :status-from [::status/single ::vendor-form]
                          :class "is-primary"
                          :on-click (dispatch-event [::save])
                          :close-event [::status/completed ::vendor-form]}}]}))

(re-frame/reg-event-fx
 ::edit
 (fn  [{:keys [db]} [_]]
   {:db (-> db (forms/start-form ::select-vendor-form {}))
    :dispatch [::modal/modal-requested
               {:title "Select Vendor"
                :body [select-vendor-form-content]
                :confirm {:value "Choose a vendor"
                          :status-from [::status/single ::select-vendor-form]
                          :class "is-primary"
                          :on-click (dispatch-event [::vendor-selected])
                          :close-event [::status/completed ::select-vendor-form]}}]}))
