class Balance::ForwardCalculator
  attr_reader :account

  def initialize(account)
    @account = account
  end

  def calculate
    Rails.logger.tagged("Balance::ForwardCalculator") do
      calculate_balances
    end
  end

  private
    def calculate_balances
      current_cash_balance = 0
      next_cash_balance = nil

      @balances = []

      account.start_date.upto(Date.current).each do |date|
        entries = sync_cache.get_entries(date)
        holdings = sync_cache.get_holdings(date)
        holdings_value = holdings.sum(&:amount)
        valuation = sync_cache.get_valuation(date)

        next_cash_balance = if valuation
          valuation.amount - holdings_value
        else
          calculate_next_balance(current_cash_balance, entries, direction: :forward)
        end

        @balances << build_balance(date, next_cash_balance, holdings_value)

        current_cash_balance = next_cash_balance
      end

      @balances
    end

    def sync_cache
      @sync_cache ||= Balance::SyncCache.new(account)
    end

    def build_balance(date, cash_balance, holdings_value)
      Balance.new(
        account_id: account.id,
        date: date,
        balance: holdings_value + cash_balance,
        cash_balance: cash_balance,
        currency: account.currency
      )
    end

    def calculate_next_balance(prior_balance, transactions, direction: :forward)
      flows = transactions.sum(&:amount)
      negated = direction == :forward ? account.asset? : account.liability?
      flows *= -1 if negated
      prior_balance + flows
    end
end
