(ns auto-ap.integration.graphql.ledger.running-balance
  (:require
   [auto-ap.datomic :refer [conn pull-attr]]
   [auto-ap.ledger :as sut]
   [iol-ion.tx.upsert-ledger :refer [upsert-ledger]]
   [auto-ap.integration.util :refer [wrap-setup]]
   [clojure.test :as t :refer [deftest is testing use-fixtures]]
   [datomic.api :as d]))

(use-fixtures :each wrap-setup)

(deftest running-balance
  (let [{:strs [test-account-1
                test-account-2
                test-client
                journal-entry-1
                journal-entry-2
                journal-entry-3

                line-1-1
                line-1-2
                line-2-1
                line-2-2
                line-3-1
                line-3-2]} (:tempids @(d/transact conn [{:db/id        "test-account-1"
                                                        :account/type :account-type/asset}
                                                       {:db/id        "test-account-2"
                                                        :account/type :account-type/equity}
                                                       {:db/id       "test-client"
                                                        :client/code "TEST"}
                                                        [:upsert-ledger {:db/id                     "journal-entry-1"
                                                                         :journal-entry/external-id "1"
                                                                         :journal-entry/date        #inst "2022-01-01"
                                                                         :journal-entry/client      "test-client"
                                                                         :journal-entry/line-items  [{:db/id                       "line-1-1"
                                                                                                      :journal-entry-line/account  "test-account-1"
                                                                                                      :journal-entry-line/location "A"
                                                                                                      :journal-entry-line/debit    10.0}
                                                                                                     {:db/id                       "line-1-2"
                                                                                                      :journal-entry-line/account  "test-account-2"
                                                                                                      :journal-entry-line/location "A"
                                                                                                      :journal-entry-line/credit   10.0}]}]
                                                        [:upsert-ledger {:db/id                     "journal-entry-2"
                                                                         :journal-entry/date        #inst "2022-01-02"
                                                                         :journal-entry/external-id "2"
                                                                         :journal-entry/client      "test-client"
                                                                         :journal-entry/line-items  [{:db/id                       "line-2-1"
                                                                                                      :journal-entry-line/account  "test-account-1"
                                                                                                      :journal-entry-line/location "A"
                                                                                                      :journal-entry-line/debit    50.0}
                                                                                                     {:db/id                       "line-2-2"
                                                                                                      :journal-entry-line/account  "test-account-2"
                                                                                                      :journal-entry-line/location "A"
                                                                                                      :journal-entry-line/credit   50.0}]}]
                                                        [:upsert-ledger {:db/id                     "journal-entry-3"
                                                                         :journal-entry/date        #inst "2022-01-03"
                                                                         :journal-entry/external-id "3"
                                                                         :journal-entry/client      "test-client"
                                                                         :journal-entry/line-items  [{:db/id                       "line-3-1"
                                                                                                      :journal-entry-line/account  "test-account-1"
                                                                                                      :journal-entry-line/location "A"
                                                                                                      :journal-entry-line/debit    150.0}
                                                                                                     {:db/id                       "line-3-2"
                                                                                                      :journal-entry-line/account  "test-account-2"
                                                                                                      :journal-entry-line/location "A"
                                                                                                      :journal-entry-line/credit   150.0}]}]]))]

    (testing "should set running-balance on ledger entries missing them"
      
      (sut/refresh-running-balance-cache)
      (println (d/pull (d/db conn) '[*] line-1-1))

      (is (= [-10.0 -60.0 -210.0]
             (map #(pull-attr (d/db conn) :journal-entry-line/running-balance %) [line-1-1 line-2-1 line-3-1
                                                                                  ])))
      (is (= [10.0 60.0 210.0]
             (map #(pull-attr (d/db conn) :journal-entry-line/running-balance %) [line-1-2 line-2-2 line-3-2]))))

    (testing "should recompute if the data is out of date"

      (d/transact conn 
                  [{:db/id                              line-1-1
                    :journal-entry-line/dirty           true
                    :journal-entry-line/running-balance 123810.23}])
      (sut/refresh-running-balance-cache)

      (is (= [-10.0 -60.0 -210.0]
             (map #(pull-attr (d/db conn) :journal-entry-line/running-balance %) [line-1-1 line-2-1 line-3-1]))))

    (testing "should recompute every entry after the out of date one"

      (d/transact conn 
                  [{:db/id                    line-1-1
                    :journal-entry-line/dirty true
                    :journal-entry-line/debit 70.0}])
      (sut/refresh-running-balance-cache)
      (is (= [-70.0 -120.0 -270.0]
             (map #(pull-attr (d/db conn) :journal-entry-line/running-balance %) [line-1-1 line-2-1 line-3-1]))))
    (testing "should not recompute entries that aren't dirty"

      (d/transact conn 
                  [{:db/id                    line-1-1
                    :journal-entry-line/dirty false
                    :journal-entry-line/debit 90.0}])
      (sut/refresh-running-balance-cache)
      (is (= [-70.0 -120.0 -270.0]
             (map #(pull-attr (d/db conn) :journal-entry-line/running-balance %) [line-1-1 line-2-1 line-3-1])))

      )
    (testing "changing a ledger entry should mark the line items as dirty"
      (println "AFTER HERE")
        @(d/transact conn 
                     [[:upsert-ledger {:db/id                     journal-entry-2
                                       :journal-entry/date        #inst "2022-01-02"
                                       :journal-entry/client      test-client
                                       :journal-entry/external-id "2"
                                       :journal-entry/line-items  [{:db/id                       "line-2-1"
                                                                    :journal-entry-line/account  test-account-1
                                                                    :journal-entry-line/location "A"
                                                                    :journal-entry-line/debit    50.0}
                                                                   {:db/id                       "line-2-2"
                                                                    :journal-entry-line/account  test-account-2
                                                                    :journal-entry-line/location "A"
                                                                    :journal-entry-line/credit   50.0}]}]])
        (is (= [true true]
               (->> (d/pull (d/db conn) '[{:journal-entry/line-items [:journal-entry-line/dirty]}]  journal-entry-2)
                    (:journal-entry/line-items)
                    (map :journal-entry-line/dirty))))
        (testing "should also mark the next entry as dirty, so that if a ledger entry is changed, the old accounts get updated"
          (is (= [false false]
                 (->> (d/pull (d/db conn) '[{:journal-entry/line-items [:journal-entry-line/dirty]}]  journal-entry-1)
                      (:journal-entry/line-items)
                      (map :journal-entry-line/dirty))))
          (is (= [true true]
                 (->> (d/pull (d/db conn) '[{:journal-entry/line-items [:journal-entry-line/dirty]}]  journal-entry-2)
                      (:journal-entry/line-items)
                      (map :journal-entry-line/dirty))))))))
