(ns auto-ap.ssr.ledger.common 
  (:require
   [auto-ap.client-routes :as client-routes]
   [auto-ap.datomic
             :refer [add-sorter-fields apply-pagination apply-sort-4 conn
                     merge-query observable-query pull-many]]
   [auto-ap.datomic.accounts :as d-accounts]
   [auto-ap.graphql.utils :refer [extract-client-ids]]
   [auto-ap.permissions :refer [can?]]
   [auto-ap.routes.invoice :as invoice-route]
   [auto-ap.routes.ledger :as route]
   [auto-ap.ssr-routes :as ssr-routes]
   [auto-ap.ssr.components :as com]
   [auto-ap.ssr.components.link-dropdown :refer [link-dropdown]]
   [auto-ap.ssr.grid-page-helper :as helper]
   [auto-ap.ssr.hx :as hx]
   [auto-ap.ssr.pos.common :refer [date-range-field*]]
   [auto-ap.ssr.svg :as svg]
   [auto-ap.ssr.utils
             :refer [clj-date-schema entity-id html-response ref->enum-schema
                     strip]]
   [auto-ap.time :as atime]
   [auto-ap.utils :refer [dollars-0?]]
   [bidi.bidi :as bidi]
   [clj-time.coerce :as coerce]
   [clojure.string :as str]
   [datomic.api :as dc]
   [hiccup.util :as hu]
   [iol-ion.query :refer [dollars=]]
   [malli.core :as mc]))

(defn exact-match-id* [request]
  (if (nat-int? (:exact-match-id (:query-params request)))
    [:div {:x-data (hx/json {:exact_match (:exact-match-id (:query-params request))}) :id "exact-match-id-tag"}
     (com/hidden {:name "exact-match-id"
                  "x-model" "exact_match"})
     (com/pill {:color :primary}
               [:span.inline-flex.space-x-2.items-center
                [:div "exact match"]
                [:div.w-3.h-3
                 (com/link {"@click" "exact_match=null; $nextTick(() => $dispatch('change'))"}
                           svg/x)]])]
    [:div {:id "exact-match-id-tag"}]))

(defn bank-account-filter* [request]
  [:div {:hx-trigger "clientSelected from:body"
         :hx-get (bidi.bidi/path-for ssr-routes/only-routes ::route/bank-account-filter)
         :hx-target "this"
         :hx-swap "outerHTML"}
   (when (:client request)
     (let [bank-account-belongs-to-client? (get (set (map :db/id (:client/bank-accounts (:client request))))
                                                (:db/id (:bank-account (:query-params request))))]
       (com/field {:label "Bank Account"}
                  (com/radio-card {:size    :small
                                   :name    "bank-account"
                                   :value (or (when bank-account-belongs-to-client?
                                                (:db/id (:bank-account (:query-params request))))
                                              "")
                                   :options
                                   (into [{:value ""
                                           :content "All"}]
                                         (for [ba (:client/bank-accounts (:client request))]
                                           {:value   (:db/id ba)
                                            :content (:bank-account/name ba)}))}))))])

(defn bank-account-filter [request]
  (html-response (bank-account-filter* request)))

(defn filters [request]
  [:form#ledger-filters {"hx-trigger"   "change delay:500ms, keyup changed from:.hot-filter delay:1000ms"
                          "hx-get"       (bidi/path-for ssr-routes/only-routes
                                                        ::route/table)
                          "hx-target"    "#entity-table"
                          "hx-indicator" "#entity-table"}

   (com/hidden {:name "status"
                :value (some-> (:status (:query-params request)) name)})
   [:fieldset.space-y-6
    (com/field {:label "Vendor"}
               (com/typeahead {:name        "vendor"
                               :id          "vendor"
                               :url (bidi/path-for ssr-routes/only-routes :vendor-search)
                               :value       (:vendor (:query-params request))
                               :value-fn :db/id
                               :content-fn :vendor/name}))
    (com/field {:label "Account"}
               (com/typeahead {:name        "account"
                               :id          "account"
                               :url (bidi/path-for ssr-routes/only-routes :account-search)
                               :value       (:account (:query-params request))
                               :value-fn :db/id
                               :content-fn #(:account/name (d-accounts/clientize (dc/pull (dc/db conn) d-accounts/default-read (:db/id %))
                                                                                 (:db/id (:client request))))}))

    (bank-account-filter* request)

    (date-range-field* request)
    (com/field {:label "Invoice #"}
               (com/text-input {:name        "invoice-number"
                                :id          "invoice-number"
                                :class       "hot-filter"
                                :value       (:invoice-number (:query-params request))
                                :placeholder "e.g., ABC-456"
                                :size        :small}))
    
    (com/field {:label "Account Code"}
               [:div.flex.space-x-4.items-baseline
                (com/int-input {:name        "numeric-code-gte"
                                :id          "numeric-code-gte"
                                :hx-preserve "true"
                                :class       "hot-filter  w-20"
                                :value       (:numeric-code-gte (:query-params request))
                                :placeholder "40000"
                                :size        :small})
                [:div.align-baseline
                 "to"]
                (com/int-input {:name        "numeric-code-lte"
                                :hx-preserve "true"
                                :id          "numeric-code-lte"
                                :class       "hot-filter w-20"
                                :value       (:numeric-code-lte (:query-params request))
                                :placeholder "50000"
                                :size        :small})])

    (com/field {:label "Amount"}
               [:div.flex.space-x-4.items-baseline
                (com/money-input {:name        "amount-gte"
                                  :id          "amount-gte"
                                  :hx-preserve "true"
                                  :class       "hot-filter  w-20"
                                  :value       (:amount-gte (:query-params request))
                                  :placeholder "0.01"
                                  :size        :small})
                [:div.align-baseline
                 "to"]
                (com/money-input {:name        "amount-lte"
                                  :hx-preserve "true"
                                  :id          "amount-lte"
                                  :class       "hot-filter w-20"
                                  :value       (:amount-lte (:query-params request))
                                  :placeholder "9999.34"
                                  :size        :small})])
    [:div.mt-4  {:x-data (hx/json { :onlyUnbalanced (:only-unbalanced (:query-params request))})}
     (com/hidden {:name "only-unbalanced"
                  ":value" "onlyUnbalanced ? 'on' : ''"})
     (com/checkbox {:value (:only-unbalanced (:query-params request)) 
                    :x-model "onlyUnbalanced"}
                   "Show unbalanced")]
    (exact-match-id* request)]])

(defn- apply-only-unbalanced [query-params results]
  (if (:only-unbalanced query-params)
    (let [unbalanced-ids (->>
                          (dc/q '[:find (sum ?debit) (sum ?credit) ?je
                                  :in $ [?je ...]
                                  :with ?li
                                  :where
                                  [?je :journal-entry/line-items ?li]
                                  [(get-else $ ?li :journal-entry-line/credit 0.0) ?credit]
                                  [(get-else $ ?li :journal-entry-line/debit 0.0) ?debit]]
                                (dc/db conn)
                                (map last results))
                          (filter (fn [[debits credits]]
                                    (not (dollars= debits credits))))
                          (map last)
                          (into #{})) ]
      (for [ result results 
            :when (get unbalanced-ids (last result))]
        result))
    results))

;; TODO
;; 1. Sorting in investigate dialog
;; 2. actual date range filtering in investigate dialog
;; 3. CSVs
;; 4. better date range / advanced mode for dialog

(defn fetch-ids [db {:keys [query-params route-params] :as request}]
  (let [valid-clients (extract-client-ids (:clients request)
                                          (:client-id request)
                                          (:client-id query-params)
                                          (when (:client-code request)
                                            [:client/code (:client-code request)]))
        args query-params
        query
        (if (:exact-match-id args)
          {:query {:find  '[?e]
                   :in    '[$ ?e [?c ...]]
                   :where '[[?e :journal-entry/client ?c]]}
           :args  [db
                   (:exact-match-id args)
                   valid-clients]}
          (cond-> {:query {:find []
                           :in ['$ '[?clients ?start ?end]]
                           :where '[[(iol-ion.query/scan-ledger $ ?clients ?start ?end) [[?e _ ?sort-default] ...]]]}
                   :args [db
                          [valid-clients
                           (some-> (:start-date query-params) coerce/to-date)
                           (some-> (:end-date query-params) coerce/to-date)]]}

            (:only-external args)
            (merge-query {:query {:where ['(not [?e :journal-entry/original-entity])]}})

            (seq (:external-id-like args))
            (merge-query {:query {:in    ['?external-id-like]
                                  :where ['[?e :journal-entry/external-id ?external-id]
                                          '[(.contains ^String ?external-id ?external-id-like)]]}
                          :args  [(:external-id-like args)]})

            (seq (:source args))
            (merge-query {:query {:in    ['?source]
                                  :where ['[?e :journal-entry/source ?source]]}
                          :args  [(:source args)]})
            (:external? route-params)
            (merge-query {:query {:where ['[?e :journal-entry/external-id]]}})

            (:vendor args)
            (merge-query {:query {:in    ['?vendor-id]
                                  :where ['[?e :journal-entry/vendor ?vendor-id]]}
                          :args  [(:db/id (:vendor args))]})

            (:invoice-number args)
            (merge-query {:query {:in    ['?invoice-number]
                                  :where ['[?e :journal-entry/original-entity ?oe]
                                          '[?oe :invoice/invoice-number ?invoice-number]]}
                          :args  [(:invoice-number args)]})

            (or (:numeric-code-lte args)
                (:numeric-code-gte args)
                (seq (:numeric-code args))
                (:account args)
                (:db/id (:bank-account args))
                (not-empty (:location args)))
            (merge-query {:query {:where ['[?e :journal-entry/line-items ?li]]}})

            (or (:numeric-code-gte args)
                (:numeric-code-lte args))
            (merge-query {:query {:in    '[?from-numeric-code ?to-numeric-code]
                                  :where ['[?li :journal-entry-line/account ?a]
                                          '(or-join [?a ?c]
                                                    [?a :account/numeric-code ?c]
                                                    [?a :bank-account/numeric-code ?c])
                                          '[(>= ?c ?from-numeric-code)]
                                          '[(<= ?c ?to-numeric-code)]]}
                          :args  [(or (:numeric-code-gte args) 0) (or (:numeric-code-lte args) 99999)]})

            (seq (:numeric-code args))
            (merge-query {:query {:in    '[ [ [?from-numeric-code ?to-numeric-code] ...]]
                                  :where ['[?li :journal-entry-line/account ?a]
                                          '(or-join [?a ?c]
                                                    [?a :account/numeric-code ?c]
                                                    [?a :bank-account/numeric-code ?c])
                                          '[(>= ?c ?from-numeric-code)]
                                          '[(<= ?c ?to-numeric-code)]]}
                          :args  [ (map (juxt :from :to ) (:numeric-code args))]})
            (seq (:account args))
            (merge-query {:query {:in    ['?a3]
                                  :where ['[?li :journal-entry-line/account ?a3]]}
                          :args  [(:db/id (:account args))]})


            (:amount-gte args)
            (merge-query {:query {:in    ['?amount-gte]
                                  :where ['[?e :journal-entry/amount ?a]
                                          '[(>= ?a ?amount-gte)]]}
                          :args  [(:amount-gte args)]})

            (:amount-lte args)
            (merge-query {:query {:in    ['?amount-lte]
                                  :where ['[?e :journal-entry/amount ?a]
                                          '[(<= ?a ?amount-lte)]]}
                          :args  [(:amount-lte args)]})

            (:db/id (:bank-account args))
            (merge-query {:query {:in    ['?a]
                                  :where ['[?li :journal-entry-line/account ?a]]}
                          :args  [(:db/id (:bank-account args))]})

            (:account-id args)
            (merge-query {:query {:in    ['?a2]
                                  :where ['[?e :journal-entry/line-items ?li2]
                                          '[?li2 :journal-entry-line/account ?a2]]}
                          :args  [(:account-id args)]})

            (not-empty (:location args))
            (merge-query {:query {:in    ['?location]
                                  :where ['[?li :journal-entry-line/location ?location]]}
                          :args  [(:location args)]})

            (not-empty (:locations args))
            (merge-query {:query {:in    ['[?location ...]]
                                  :where ['[?li :journal-entry-line/location ?location]]}
                          :args  [(:locations args)]})

            (:sort args) (add-sorter-fields {"client"      ['[?e :journal-entry/client ?c]
                                                            '[?c :client/name ?sort-client]]
                                             "date"        ['[?e :journal-entry/date ?sort-date]]
                                             "vendor"      '[(or-join  [?e ?sort-vendor]
                                                                       (and
                                                                        [?e :journal-entry/vendor ?v]
                                                                        [?v :vendor/name ?sort-vendor])
                                                                       (and [(missing?  $ ?e :journal-entry/vendor)]
                                                                            [(ground "") ?sort-vendor]))]
                                             "amount"      ['[?e :journal-entry/amount ?sort-amount]]
                                             "external-id" ['[?e :journal-entry/external-id ?sort-external-id]]
                                             "source"      '[(or-join [?e ?sort-source]
                                                                      [?e :journal-entry/source ?sort-source]
                                                                      (and [(missing?  $ ?e :journal-entry/source)]
                                                                           [(ground "") ?sort-source]))]}
                                            args)

            true
            (merge-query {:query {:find ['?sort-default '?e]}})))]

    (->> (observable-query query)
         (apply-sort-4 (assoc query-params :default-asc? true))
         (apply-only-unbalanced query-params)
         (apply-pagination query-params))))


#_(dc/q '{:find [ ?sort-vendor (count ?e)], 
:in [$ [?clients ?start ?end]], 
:where [[(iol-ion.query/scan-ledger $ ?clients ?start ?end)
         [[?e _ ?sort-default] ...]]
        #_(not [?e :journal-entry/vendor])
        [(missing? $ ?e :journal-entry/vendor)]
        [(ground "ih") ?sort-vendor]]}
(dc/db conn)
args
)

(def default-read
  '[:journal-entry/amount
    :journal-entry/alternate-description
    :journal-entry/memo
    :journal-entry/source
    :journal-entry/external-id
    :db/id
    [:journal-entry/date :xform clj-time.coerce/from-date]
    {:journal-entry/vendor  [:vendor/name :db/id]
     :journal-entry/original-entity [:invoice/invoice-number 
                                     :invoice/source-url
                                     :transaction/description-original :db/id]
     :journal-entry/client     [:client/name :client/code :db/id]
     :journal-entry/line-items [:journal-entry-line/debit
                                :journal-entry-line/location
                                :journal-entry-line/running-balance
                                :journal-entry-line/credit
                                {:journal-entry-line/account [:account/name :db/id :account/numeric-code
                                                              :bank-account/name :bank-account/numeric-code
                                                              {[:account/type :xform iol-ion.query/ident] [:db/ident :db/id]}
                                                              {:account/client-overrides [:account-client-override/name
                                                                                          {:account-client-override/client [:db/id]}]}
                                                              {[:bank-account/type :xform iol-ion.query/ident]
                                                               [:db/ident :db/id]}]}]}])

(defn hydrate-results [ids db _]
  (let [results (->> (pull-many db default-read ids)
                     (group-by :db/id))
        refunds (->> ids
                     (map results)
                     (map first))]
    refunds))

(defn sum-outstanding [ids]
  
  (->> 
    (dc/q {:find  ['?id '?o]
           :in    ['$ '[?id ...]]
           :where ['[?id :invoice/outstanding-balance ?o]]}
          (dc/db conn)
          ids)
   (map last)
   (reduce
    +
    0.0)))

(defn sum-total-amount [ids]
  
  (->> 
    (dc/q {:find  ['?id '?o]
           :in    ['$ '[?id ...]]
           :where ['[?id :invoice/total ?o]]
           }
          (dc/db conn)
          ids)
    (map last)
    (reduce
      +
      0.0)))


(defn fetch-page [request]
  (let [db                                           (dc/db conn)
        {ids-to-retrieve :ids matching-count :count
         all-ids :all-ids} (fetch-ids db request)]

    [(->> (hydrate-results ids-to-retrieve db request))
     matching-count
     (sum-outstanding all-ids)
     (sum-total-amount all-ids)]))
(defn render-lines [key {:journal-entry/keys [line-items client]}]
  (let [lines (for [jel line-items
                    :when (and (key jel)
                               (not (dollars-0? (key jel))))]
                jel)]
    [:div.grid.grid-cols-2.gap-1.auto-cols-min.grid-flow-row.shrink

     (for [jel lines
           :let [account (d-accounts/clientize (:journal-entry-line/account jel) (:db/id client))
                 account-name (or (:account/name account)
                                  (:bank-account/name (:journal-entry-line/account jel)))]]
       (list

        (if account-name
          [:div { :x-tooltip (hx/json (str "Running Balance: " (some->> (:journal-entry-line/running-balance jel)
                                                                        (format "$%,.2f"))))}
           [:div.text-left.underline.cursor-pointer  {:x-ref "source"}
            (:journal-entry-line/location jel) ": "
            (or (:account/numeric-code account) (:bank-account/numeric-code account))
            " - " account-name] ]
          [:div.text-left (com/pill {:color :yellow} "Unassigned")])
        [:div.text-right.text-underline  (format "$%,.2f" (key jel))]))

     (when-not (= 1 (count lines))
       [:div.col-span-2 (com/pill {:color :primary} "Total: " (->> lines
                                                                   (map #(or (key %) 0.0))
                                                                   (reduce + 0.0)
                                                                   (format "$%,.2f")))])]))

(def query-schema (mc/schema
                   [:maybe [:map {:date-range [:date-range :start-date :end-date]}
                            [:sort {:optional true} [:maybe [:any]]]
                            [:per-page {:optional true :default 25} [:maybe :int]]
                            [:start {:optional true :default 0} [:maybe :int]]
                            [:amount-gte {:optional true} [:maybe :double]]
                            [:amount-lte {:optional true} [:maybe :double]]
                            [:client-id {:optional true} [:maybe entity-id]]
                            [:only-unbalanced {:optional true }
                             [:maybe [:boolean {:decode/string {:enter #(cond (= % "on") true
                                                                          (= % "") false
                                                                          :else
                                                                            
                                                                            (boolean %))}
                                                :encode/string {:enter #(if % "on" "")}}]]]
                            [:numeric-code {:optional true :decode/string clojure.edn/read-string}
                             [:maybe [:vector [:map [:from nat-int?]
                                               [:to nat-int?]]]]]
                            [:numeric-code-gte {:optional true} [:maybe nat-int?]]
                            [:numeric-code-lte {:optional true} [:maybe nat-int?]]
                            [:vendor {:optional true :default nil} [:maybe  [:entity-map {:pull [:db/id :vendor/name]}]]]
                            [:bank-account {:optional true :default nil} [:maybe  [:entity-map {:pull [:db/id :bank-account/name]}]]]
                            [:account {:optional true :default nil} [:maybe  [:entity-map {:pull [:db/id :account/name]}]]]
                            [:check-number {:optional true} [:maybe [:string {:decode/string strip}]]]
                            [:invoice-number {:optional true} [:maybe [:string {:decode/string strip}]]]
                            [:status {:optional true} [:maybe (ref->enum-schema "invoice-status")]]
                            [:exact-match-id {:optional true} [:maybe entity-id]]
                            [:all-selected {:optional true :default nil} [:maybe :boolean]]
                            [:selected {:optional true :default nil} [:maybe [:vector {:coerce? true}
                                                                              entity-id]]]
                            [:start-date {:optional true}
                             [:maybe clj-date-schema]]
                            [:end-date {:optional true}
                             [:maybe clj-date-schema]]]]))

(def grid-page
  (helper/build {:id                 "entity-table"
                 :nav                com/main-aside-nav
                 :check-boxes? true
                 :check-box-warning? (fn [e]
                                       (some? (:invoice/scheduled-payment e)))
                 :page-specific-nav  filters
                 :fetch-page         fetch-page
                 :oob-render
                 (fn [request]
                   [(assoc-in (date-range-field* request) [1 :hx-swap-oob] true)
                    (assoc-in (exact-match-id* request)  [1 :hx-swap-oob] true)])
                 :query-schema query-schema
                 :action-buttons (fn [request]
                                   [(when-not (:external? (:route-params request)) (com/button {:color :primary
                                                                                                :hx-get (bidi/path-for ssr-routes/only-routes
                                                                                                                       ::route/new)}
                                                                                               "Add journal entry"))])
                 :row-buttons (fn [request entity]
                                [(when (and (= :invoice-status/unpaid (:invoice/status entity))
                                            (can? (:identity request) {:subject :invoice :activity :delete}))
                                   (com/icon-button {:hx-delete (bidi/path-for ssr-routes/only-routes
                                                                               ::route/delete
                                                                               :db/id (:db/id entity))
                                                     :hx-confirm "Are you sure you want to void this invoice?"}
                                                    svg/trash))
                                 (when (and (can? (:identity request) {:subject :invoice :activity :edit})
                                            (#{:invoice-status/unpaid  :invoice-status/paid} (:invoice/status entity)))
                                   (com/icon-button {:hx-put (bidi/path-for ssr-routes/only-routes
                                                                            ::route/edit-wizard
                                                                            :db/id (:db/id entity))}
                                                    svg/pencil))
                                 (when (and (can? (:identity request) {:subject :invoice :activity :edit})
                                            (#{:invoice-status/voided} (:invoice/status entity)))
                                   (com/icon-button {:hx-put (bidi/path-for ssr-routes/only-routes
                                                                            ::route/unvoid
                                                                            :db/id (:db/id entity))}
                                                    svg/undo))])

                 :breadcrumbs        [[:a {:href (bidi/path-for ssr-routes/only-routes ::route/page)}
                                       "Ledger"]]
                 :title       (fn [r]
                                (str
                                 (some-> r :route-params :status name str/capitalize (str " "))
                                 "Register"))
                 :entity-name "register"
                 :route       ::route/table
                 :csv-route ::route/csv
                 :break-table (fn [request entity]
                                (cond
                                  (= (-> request :query-params :sort first :name) "Vendor")
                                  (or (-> entity :journal-entry/vendor :vendor/name)
                                      "No vendor")

                                  (= (-> request :query-params :sort first :name) "Source")
                                  (or (-> entity :journal-entry/source)
                                      "No external source")

                                  :else nil))
                 :page->csv-entities (fn [[journal-entries]]
                                       (for [je journal-entries
                                             jel (:journal-entry/line-items je)]
                                         (merge jel je)))
                 :headers     [{:key      "id"
                  :name     "Id"
                  :render-csv :db/id
                  :render-for #{:csv}}
                 {:key      "client"
                  :name     "Client"
                  :sort-key "client"
                  :hide?    (fn [args]
                              (and (= (count (:clients args)) 1)
                                   (= 1 (count (:client/locations (:client args))))))
                  :render   (fn [x] [:div.flex.items-center.gap-2 (-> x :journal-entry/client :client/name)])
                  :render-csv (fn [x] (-> x :journal-entry/client :client/name))}

                 {:key      "vendor"
                  :name     "Vendor"
                  :sort-key "vendor"
                  :render   (fn [e] (or (-> e :journal-entry/vendor :vendor/name)
                                        [:span.italic.text-gray-400 (-> e :journal-entry/alternate-description)]))
                  :render-csv   (fn [e] (or (-> e :journal-entry/vendor :vendor/name)
                                            (-> e :journal-entry/alternate-description)))}
                 {:key      "source"
                  :name     "Source"
                  :sort-key "source"
                  :hide?    (fn [args]
                              (not (:external? (:route-params args))))
                  :render   :journal-entry/source
                  :render-csv :journal-entry/source}
                 {:key      "external-id"
                  :name     "External Id"
                  :sort-key "external-id"
                  :class "max-w-[12rem]"
                  :hide?    (fn [args]
                              (not (:external? (:route-params args))))
                  :render   (fn [x] [:p.truncate (:journal-entry/external-id x)])
                  :render-csv :journal-entry/external-id}
                 {:key           "date"
                  :sort-key "date"
                  :name          "Date"
                  :show-starting "lg"
                  :render        (fn [{:journal-entry/keys [date]}]
                                   (some-> date (atime/unparse-local atime/normal-date)))}
                 {:key           "amount"
                  :sort-key "amount"
                  :name          "Amount"
                  :show-starting "lg"
                  :render        (fn [{:journal-entry/keys [amount]}]
                                   (some->> amount
                                            (format "$%,.2f")))}
                 {:key           "account"
                  :name          "Account"
                  :sort-key "account"
                  :class "text-right"
                  :render-csv #(or (-> % :journal-entry-line/account :account/name)
                                   (-> % :journal-entry-line/account :bank-account/name))
                  :render-for #{:csv}}
                 {:key           "debit"
                  :name          "Debit"
                  :class "text-right"
                  :render        (partial render-lines :journal-entry-line/debit)
                  :render-csv :journal-entry-line/debit}



                 {:key           "credit"
                  :name          "Credit"
                  :class "text-right"
                  :render        (partial render-lines :journal-entry-line/credit)
                  :render-csv :journal-entry-line/credit}

                 {:key           "links"
                  :name          "Links"
                  :show-starting "lg"
                  :class "w-8"
                  :render        (fn [i]
                                   (link-dropdown
                                    (cond-> []
                                      (-> i :journal-entry/original-entity :invoice/invoice-number)
                                      (conj
                                       {:link (hu/url (bidi/path-for ssr-routes/only-routes
                                                                     ::invoice-route/all-page)
                                                      {:exact-match-id (:db/id (:journal-entry/original-entity i))})
                                        :color :primary
                                        :content (format "Invoice '%s'" (-> i :journal-entry/original-entity :invoice/invoice-number))})
                                      (-> i :journal-entry/original-entity :invoice/source-url)
                                      {:link  (-> i :journal-entry/original-entity :invoice/source-url)
                                       :color :secondary
                                       :content (str "File")}

                                      (-> i :journal-entry/original-entity :transaction/description-original)
                                      (conj
                                       {:link (hu/url (bidi/path-for client-routes/routes
                                                                     :transactions)
                                                      {:exact-match-id (:db/id (:journal-entry/original-entity i))})
                                        :color :primary
                                        :content (format "Transaction '%s'" (-> i :journal-entry/original-entity :transaction/description-original))})
                                      (-> i :journal-entry/memo)
                                      (conj {:color :secondary 
                                             :content (str "Memo: " (:journal-entry/memo i))}))))
                  :render-for #{:html}}]}))

(def row* (partial helper/row* grid-page))