(ns auto-ap.integration.graphql.clients
  (:require
   [auto-ap.time-reader]
   [auto-ap.datomic :refer [conn pull-attr]]
   [auto-ap.graphql.clients :as sut]
   [auto-ap.integration.util :refer [wrap-setup user-token admin-token]]
   [datomic.client.api :as dc]
   [clojure.test :as t :refer [deftest is testing use-fixtures]]))

(use-fixtures :each wrap-setup)

(deftest current-balance
  (testing "it should start with a balance of 0"
    (dc/transact conn
                 {:tx-data 
                  [{:client/code          "TEST"
                    :client/bank-accounts [{:bank-account/code "TEST-1"}]}]})
    (sut/refresh-current-balance)
    (is (= 0.00
           (pull-attr (dc/db conn) :bank-account/current-balance  [:bank-account/code "TEST-1"] ))))

  (testing "it should consider a single transaction"
    (dc/transact conn
                 {:tx-data 
                  [{:client/code          "TEST"
                    :db/id                "TEST"
                    :client/bank-accounts [{:bank-account/code "TEST-1"
                                            :db/id             "TEST-1"}]}
                   {:journal-entry-line/account "TEST-1"
                    :journal-entry-line/debit   13.50}

                   {:journal-entry-line/account "TEST-1"
                    :journal-entry-line/debit   19.50}]})
    (sut/refresh-current-balance)
    (is (= -33.0
           (pull-attr (dc/db conn) :bank-account/current-balance [:bank-account/code "TEST-1"]))))

  (testing "bank accounts should start in a needing refresh state"
    (let [bank-account-id (-> (dc/transact conn
                                           {:tx-data 
                                            [{:client/code          "TEST"
                                              :db/id                "TEST"
                                              :client/bank-accounts [{:bank-account/code "TEST-2" :db/id "TEST-2"}]}
                                             ]})
                              :tempids
                              (get "TEST-2"))]
      
      (is ((sut/bank-accounts-needing-refresh) bank-account-id ))))

  (testing "bank accounts should not need a refresh if balance is up-to-date"
    (let [bank-account-id (-> (dc/transact conn
                                           {:tx-data 
                                            [{:client/code          "TEST"
                                              :db/id                "TEST"
                                              :client/bank-accounts [{:bank-account/code "TEST-3" :db/id "TEST-3"}]}
                                             ]})
                              :tempids
                              (get "TEST-3"))]
      (sut/refresh-bank-account-current-balance bank-account-id)
      (is (not ((sut/bank-accounts-needing-refresh) bank-account-id )))
      (dc/transact conn
                   {:tx-data 
                    [{:journal-entry-line/account [:bank-account/code "TEST-3"]
                      :journal-entry-line/debit   -10.50}
                     ]})
      (is ((sut/bank-accounts-needing-refresh) bank-account-id ))
      (sut/refresh-bank-account-current-balance bank-account-id)
      (is (not ((sut/bank-accounts-needing-refresh) bank-account-id ))))))

(deftest upsert-client
  (testing "Should create a new client"
    (let [create-client-request {:code              "TEST"
                               :name              "Test Co"
                               :matches           ["Test Company"]
                               :email             "hello@hi.com"
                               :locked_until      #clj-time/date-time "2022-01-01"
                               :locations         ["DT"]
                               :week_a_debits     1000.0
                               :week_a_credits    2000.0
                               :week_b_debits     3000.0
                               :week_b_credits    9000.0
                               :location_matches  [{:location "DT"
                                                    :match    "DOWNTOWN"}]
                               :address           {:street1 "hi street"
                                                   :street2 "downtown"
                                                   :city    "seattle"
                                                   :state   "wa"
                                                   :zip     "1238"}
                               :feature_flags     ["new-square"]
                               :bank_accounts     [{:code               "TEST-1"
                                                    :bank_name          "Bank of America"
                                                    :bank_code          "BANKCODE"
                                                    :start_date         #clj-time/date-time "2022-01-01"
                                                    :routing            "1235"
                                                    :include_in_reports true

                                                    :name                           "Bank of Am Check"
                                                    :visible                        true
                                                    :number                         "1000"
                                                    :check_number                   1001
                                                    :numeric_code                   12001
                                                    :sort_order                     1
                                                    :locations                      ["DT"]
                                                    :use_date_instead_of_post_date? false
                                                    :type                           :cash}]

                               }
          create-result (sut/edit-client {:id (admin-token)} {:edit_client create-client-request} nil)]
      (is (some? (-> create-result :id)))
      (is (some? (-> create-result :bank_accounts first :id)))
      (is (= (set (keys create-client-request)) (disj (set (keys create-result))
                                                      :square_integration_status :yodlee_provider_accounts :plaid_items :id)))

      (testing "Should be able to retrieve created client"
        (let [[created-client] (sut/get-client {:id (admin-token)} nil nil)]
          (is (some? (-> created-client :id)))
          (is (some? (-> created-client :bank_accounts first :id)))
          (is (= (set (keys create-client-request)) (disj (set (keys created-client))
                                                          :square_integration_status :yodlee_provider_accounts :plaid_items :id)))))

      (testing "Should edit an existing client"
        (let [edit-result (sut/edit-client {:id (admin-token)} {:edit_client {:id   (:id create-result)
                                                                              :name "New Company Name"
                                                                              :code "TEST"}} nil)]
          (is (some? (:id edit-result)))
          (is (= "New Company Name" (:name edit-result)))))

      (testing "Should support removing collections"
        (let [edit-result (sut/edit-client {:id (admin-token)} {:edit_client {:id   (:id create-result)
                                                                              :matches []
                                                                              :location_matches []
                                                                              :feature_flags []}}
                                           nil)]
          (is (some? (:id edit-result)))
          (is (seq (:location_matches create-result)))
          (is (not (seq (:location_matches edit-result))))

          (is (seq (:matches create-result)))
          (is (not (seq (:matches edit-result))))

          (is (seq (:feature_flags create-result)))
          (is (not (seq (:feature_flags edit-result))))
          ))
      ))

  (testing "Only admins can create clients"
    (is (thrown? Exception (sut/edit-client {:id (user-token)} {:edit_client {:code "INVALID"}} nil)))))

