(ns auto-ap.ssr.company.company-1099
  (:require
   [auto-ap.datomic :refer [conn remove-nils]]
   [auto-ap.graphql.utils :refer [can-see-client? is-admin?]]
   [auto-ap.shared-views.company.sidebar :refer [company-side-bar]]
   [auto-ap.ssr-routes :as ssr-routes]
   [auto-ap.ssr.ui :refer [base-page]]
   [auto-ap.ssr.utils :refer [html-response]]
   [bidi.bidi :as bidi]
   [clojure.string :as str]
   [datomic.client.api :as dc]
   [hiccup2.core :as hiccup]))

(defn cannot-overwrite? [vendor]
  (some? (or (:vendor/legal-entity-1099-type vendor)
             (:vendor/legal-entity-tin vendor)
             (:vendor/legal-entity-tin-type vendor))))

(defn get-1099-companies [user session]
  (let [clients (->> (dc/q '[:find ?c
                            :in $ ?user
                            :where [?c :client/code]
                            [(auto-ap.graphql.utils/can-see-client? ?user ?c)]]
                          (dc/db conn) user)
                     (map first)
                     set)
        results (cond
                  (and (some-> session :client :db/id)
                       (can-see-client? user
                                        (some-> session :client :db/id)))
                  (dc/q '[:find
                         (pull ?c [:client/code :db/id])
                         (pull ?v [:db/id
                                   :vendor/name
                                   {:vendor/legal-entity-1099-type [:db/ident]}
                                   {:vendor/legal-entity-tin-type [:db/ident]}
                                   {:vendor/address [:address/street1
                                                     :address/city
                                                     :address/state
                                                     :address/zip]}
                                   :vendor/legal-entity-tin
                                   :vendor/legal-entity-name
                                   :vendor/legal-entity-first-name
                                   :vendor/legal-entity-middle-name
                                   :vendor/legal-entity-last-name])
                         (sum ?a)
                         :with ?d 
                         :in $ ?c
                         :where
                         [?p :payment/client ?c]
                         [?p :payment/date ?d ]
                         [(>= ?d #inst "2022-01-01T08:00")]
                         [(< ?d #inst "2023-01-01T08:00")]
                         [?p :payment/type :payment-type/check]
                         
                         [?p :payment/amount ?a]
                         [?p :payment/vendor ?v]]
                       (dc/db conn)
                       (some-> session :client :db/id))

                  (is-admin? user)
                  (dc/q '[:find
                         (pull ?c [:client/code :db/id])
                         (pull ?v [:db/id
                                   :vendor/name
                                   {:vendor/legal-entity-1099-type [:db/ident]}
                                   {:vendor/legal-entity-tin-type [:db/ident]}
                                   {:vendor/address [:address/street1
                                                     :address/city
                                                     :address/state
                                                     :address/zip]}
                                   :vendor/legal-entity-tin
                                   :vendor/legal-entity-name
                                   :vendor/legal-entity-first-name
                                   :vendor/legal-entity-middle-name
                                   :vendor/legal-entity-last-name])
                         (sum ?a)
                         :with ?d 
                         :in $
                         :where
                         [?p :payment/date ?d ]
                         [(>= ?d #inst "2022-01-01T08:00")]
                         [(< ?d #inst "2023-01-01T08:00")]
                         [?p :payment/type :payment-type/check]
                         [?p :payment/client ?c]
                         [?p :payment/amount ?a]
                         [?p :payment/vendor ?v]]
                       (dc/db conn))

                  :else
                  (dc/q '[:find
                         (pull ?c [:client/code :db/id])
                         (pull ?v [:db/id
                                   :vendor/name
                                   {:vendor/legal-entity-1099-type [:db/ident]}
                                   {:vendor/legal-entity-tin-type [:db/ident]}
                                   {:vendor/address [:address/street1
                                                     :address/city
                                                     :address/state
                                                     :address/zip]}
                                   :vendor/legal-entity-tin
                                   :vendor/legal-entity-name
                                   :vendor/legal-entity-first-name
                                   :vendor/legal-entity-middle-name
                                   :vendor/legal-entity-last-name])
                         (sum ?a)
                         :with ?d 
                         :in $ [?c ...]
                         :where
                         [?p :payment/client ?c]
                         [?p :payment/date ?d ]
                         [(>= ?d #inst "2022-01-01T08:00")]
                         [(< ?d #inst "2023-01-01T08:00")]
                         [?p :payment/type :payment-type/check]
                         
                         [?p :payment/amount ?a]
                         [?p :payment/vendor ?v]]
                       (dc/db conn)
                       clients))]
    (->> results
         (filter (fn [[_ _ a]]
                   (>= (or a 0.0) 600.0)))
         (take 200)
         (sort-by (fn [[client _ amount]]
                    [(:client/code client ) amount])))))

(defn dialog [header content footer]
  [:div.modal.is-active
   [:div.modal-background {"_" (hiccup/raw "on click remove <#modal-holder div/>")}]
   [:div.modal-card
    [:div.modal-card-head
     header]
    [:div.modal-card-body
     content]
    [:div.modal-card-foot
     footer]]
   [:button.modal-close.is-large {"_" (hiccup/raw "on click remove <#modal-holder div/>")}]])

(defn table [{:keys [identity session]} & {:keys [flash-id]}]
  [:div#vendor-table {:hx-get     (bidi/path-for ssr-routes/only-routes
                                                 :company-1099-vendor-table
                                                 :request-method :get) 
                      :hx-trigger "clientSelected from:body"
                      "_" (hiccup/raw "on htmx:beforeRequest remove <table/> in me")
                      :hx-swap    "outerHTML swap:300ms"}
   [:table.table.grid.compact.is-fullwidth 
    [:thead
     [:tr
      [:th {:style {:width "5em"}}"Client"]
      [:th "Vendor Name"]
      [:th "Name"]
      [:th {:style {:width "9em"}} "1099 Type"]
      [:th {:style {:width "8em"}} "TIN"]
      [:th "Address"]
      [:th "Amount Paid"]
      [:th {:style {:width "10em"}}]
      ]]
    [:tbody
     (for [[client vendor amount] (get-1099-companies identity session)]
       [:tr (when (= flash-id
                     (:db/id vendor))
              {:class "live-added"})
        [:td (:client/code client)]
        [:td (:vendor/name vendor)]
        [:td (or (-> vendor :vendor/legal-entity-name not-empty)
                 (str (-> vendor :vendor/legal-entity-first-name) " "
                      (-> vendor :vendor/legal-entity-middle-name) " "
                      (-> vendor :vendor/legal-entity-last-name)))]
        [:td (some-> vendor :vendor/legal-entity-1099-type :db/ident name)] " "
        [:td
         (some-> vendor :vendor/legal-entity-tin-type :db/ident name) " "
         (-> vendor :vendor/legal-entity-tin)]
        [:td
         (-> vendor :vendor/address :address/street1) " "
         (-> vendor :vendor/address :address/street2) " "
         (-> vendor :vendor/address :address/city) " "
         (-> vendor :vendor/address :address/state) " "
         (-> vendor :vendor/address :address/zip)
         [:td "$" (Math/round amount)]
         [:td
          (if (cannot-overwrite? vendor)
            [:a {:href "mailto:ben@integreatconsult.com"} "Contact Integreat"]
            [:button.button  {:hx-get    (bidi/path-for ssr-routes/only-routes
                                                        :company-1099-vendor-dialog
                                                        :vendor-id (:db/id vendor))
                              :hx-target "#modal-holder"
                              :hx-swap   "innerHTML"}
             [:span.icon [:i.fa.fa-pencil ]]])]]])]]
   [:div.container.htmx-indicator 
    [:div.column.is-4.is-offset-4.has-text-centered
     [:div.loader.is-loading.is-active.big.is-centered]]]])

(defn form-data->map [form-data]
  (reduce-kv
    (fn [acc k v]
      (assoc-in acc (->> (str/split k #"_")
                         (mapv #(apply keyword (str/split % #"/"))))
                v))
    {}
    form-data))

(defn path->name [k]
  (cond (keyword? k)
    (str (namespace k) "/" (name k))

    (seq k)
    (str/join "_" (map path->name k))
    :else k))

(defn vendor-save [{:keys [form-params identity route-params] :as request}]
  (when-not (cannot-overwrite? (dc/pull (dc/db conn) '[*] (Long/parseLong (:vendor-id route-params))))
    @(dc/transact conn {:tx-data [(remove-nils
                                    (-> (form-data->map form-params)
                                        (assoc :db/id (Long/parseLong (:vendor-id route-params)))
                                        (update :vendor/legal-entity-1099-type #(some->> % (keyword "legal-entity-1099-type")))
                                        (update :vendor/legal-entity-tin-type #(some->> % (keyword "legal-entity-tin-type")))))]}))
  (html-response 
    (table request :flash-id (Long/parseLong (:vendor-id route-params)))))


(defn vendor-dialog [request]
  (let [vendor (dc/pull (dc/db conn) '[* {:vendor/legal-entity-1099-type [:db/ident]
                                        :vendor/legal-entity-tin-type [:db/ident]}] (Long/parseLong (:vendor-id (:params request))))] ;; TODO perms
    (html-response 
      [:form {:hx-post   (bidi/path-for ssr-routes/only-routes
                                      :company-1099-vendor-save
                                      :request-method :post
                                      :vendor-id (Long/parseLong (:vendor-id (:params request)))) 
              :hx-target "#vendor-table"
              :hx-swap   "outerHTML swap:0.2s"
              "_" (hiccup/raw "on htmx:afterRequest transition <#modal-holder .modal-background, #modal-holder .modal-card />'s opacity from 1.0 to 0 over 100ms then remove <#modal-holder */> ")}
       (dialog
         [:h4.is-4.title "Vendor 1099 Info"]
         [:div
          [:h3.is-3.title (:vendor/name vendor)]

          [:h4.is-4.title "Address"]
          [:hr]
          [:div.field
           [:p.help "Street1"]
           [:div.control
            [:input.input.is-expanded {:type        "text"
                                       :autofocus   true
                                       :name        (path->name [:vendor/address :address/street1])
                                       :placeholder "1700 Pennsylvania Ave"
                                       :value       (-> vendor :vendor/address :address/street1)}]]]
          [:div.field
           [:p.help "Street 2"]
           [:div.control
            [:input.input.is-expanded {:type        "text"
                                       :name        (path->name [:vendor/address :address/street2])
                                       :placeholder "SUite 400"
                                       :value       (-> vendor :vendor/address :address/street2)}]]]
          [:div.level 
           [:div.level-left 
            [:div.level-item
             [:div.field
              [:p.help "City"]
              [:div.control
               [:input.input.is-expanded {:type        "text"
                                          :placeholder "Cupertino"
                                          :name        (path->name [:vendor/address :address/city])
                                          :value       (-> vendor :vendor/address :address/city)}]]]]
            [:div.level-item
             [:div.field
              [:p.help "State"]
              [:div.control
               [:input.input.is-expanded {:type        "text"
                                          :style       {:width "3em"}
                                          :placeholder "CA"
                                          :name        (path->name [:vendor/address :address/state])
                                          :value       (-> vendor :vendor/address :address/state)}]]]]
            [:div.level-item
             [:div.field
              [:p.help "Zip"]
              [:div.control
               [:input.input.is-expanded {:type        "text"
                                          :placeholder "95014"
                                          :name        (path->name [:vendor/address :address/zip])
                                          :value       (-> vendor :vendor/address :address/zip)}]]]]]]
          [:h4.is-4.title "Legal Entity"]
          [:hr]
          [:div.field
           [:p.help "Legal Entity Name"]
           [:div.control
            [:input.input.is-expanded {:type        "text"
                                       :placeholder "Good Restaurant LLC"
                                       :name        (path->name [:vendor/legal-entity-name])
                                       :value       (-> vendor :vendor/legal-entity-name)}]]]
          "OR"
          [:div.level 
           [:div.level-left 
            [:div.level-item
             [:div.field
              [:p.help "First Name"]
              [:div.control
               [:input.input.is-expanded {:type        "text"
                                          :placeholder "Josh"
                                          :name        (path->name [:vendor/legal-entity-first-name])
                                          :value       (-> vendor :vendor/legal-entity-first-name)}]]]]
            [:div.level-item
             [:div.field
              [:p.help "Middle Name"]
              [:div.control
               [:input.input.is-expanded {:type        "text"
                                          :placeholder "Caleb"
                                          :name        (path->name [:vendor/legal-entity-middle-name])
                                          :value       (-> vendor :vendor/legal-entity-middle-name)}]]]]
            [:div.level-item
             [:div.field
              [:p.help "Last Name"]
              [:div.control
               [:input.input.is-expanded {:type        "text"
                                          :placeholder "Smith"
                                          :name        (path->name [:vendor/legal-entity-last-name])
                                          :value       (-> vendor :vendor/legal-entity-last-name)}]]]]]]

          [:div.level 
           [:div.level-left 
            [:div.level-item
             [:div.field
              [:p.help "TIN"]
              [:div.control
               [:input.input {:type        "text"
                              :name        (path->name [:vendor/legal-entity-tin])
                              :placeholder "SSN or EIN"
                              :size        "12"
                              :value       (-> vendor :vendor/legal-entity-tin)}]]]]
            [:div.level-item
             [:div.field
              [:p.help "TIN Type"]
              [:div.control
               [:div.select
                [:select {:name (path->name [:vendor/legal-entity-tin-type])}
                 [:option {:value ""} ""]
                 [:option {:value "ein" :selected (= (-> vendor :vendor/legal-entity-tin-type :db/ident) :legal-entity-tin-type/ein)} "EIN"]
                 [:option {:value "ssn" :selected (= (-> vendor :vendor/legal-entity-tin-type :db/ident) :legal-entity-tin-type/ssn)} "SSN"]]]]]]
            [:div.level-item
             [:div.field
              [:p.help "1099 Type"]
              [:div.control
               [:div.select
                [:select {:name (path->name [:vendor/legal-entity-1099-type])}
                 [:option {:value ""} ""]
                 [:option {:value "none" :selected (= (-> vendor :vendor/legal-entity-1099-type :db/ident) :legal-entity-1099-type/none)} "None"]
                 [:option {:value "misc" :selected (= (-> vendor :vendor/legal-entity-1099-type :db/ident) :legal-entity-1099-type/misc)} "Misc"]
                 [:option {:value "landlord" :selected (= (-> vendor :vendor/legal-entity-1099-type :db/ident) :legal-entity-1099-type/landlord)} "Landlord"]]]]]]]]]
         [:button.button.is-primary.htmx-indicator "Save"])])))

(defn vendor-table [request]
  (html-response (table request)))

(defn page [{:keys [identity matched-route] :as request}]
  (base-page
    request
    [:div 
     [:div#vendor-table {:hx-get     (bidi/path-for ssr-routes/only-routes
                                                    :company-1099-vendor-table
                                                    :request-method :get) 
                         :hx-trigger "load, clientSelected from:body"
                         :hx-swap    "outerHTML swap:400ms"}
      [:div.container.htmx-indicator 
       [:div.column.is-4.is-offset-4.has-text-centered
        [:div.loader.is-loading.is-active.big.is-centered]]]]]
    [:div
     (company-side-bar matched-route)]))

