module BackendClient
  class Provider
    module Transactions

      Transaction = Struct.new(:cinstance, :usage, :timestamp)

      def latest_transactions
        transactions = account.services.map do |s|
          response = get("/transactions/latest.xml", :service_id => s.backend_id)
          doc = Nokogiri::XML(response.body)

          doc.search('transactions transaction').map do |transaction_node|
            usage = transaction_node.search('value').inject({}) do |memo, value_node|
              memo[value_node['metric_id']] = value_node.content.to_i
              memo
            end

            {:application_id => transaction_node['application_id'],
             :usage          => usage,
             :timestamp      => transaction_node['timestamp']}
          end
        end.flatten

        process_transactions(transactions.sort{|a,b| a[:timestamp] <=> b[:timestamp]}.reverse)
      end

      private

      def process_transactions(transactions)
        application_ids = transactions.map { |transaction| transaction[:application_id] }
        cinstances      = preload_cinstances(application_ids)
        services        = preload_services(application_ids)
        metrics         = preload_metrics(services)

        transactions.map do |transaction|
          Transaction.new(cinstances[transaction[:application_id]],
                          process_usage(transaction[:usage], metrics),
                          parse_timestamp(transaction[:timestamp]))
        end
      end

      def preload_cinstances(application_ids)
        account.provided_cinstances.where(application_id: application_ids).index_by(&:application_id)
      end

      def preload_services(application_ids)
        account.services.joins(:application_plans => [:cinstances]).includes(:metrics).where(:cinstances => {:application_id => application_ids})
      end

      def preload_metrics(services)
        services.map(&:metrics).flatten.index_by(&:id)
      end

      def process_usage(usage, metrics)
        usage.map_keys do |metric_id|
          metrics[metric_id.to_i]
        end
      end

    end
  end
end
