module DataTests
  module AccountingRun
    class CloudmatchValidation
      attr_reader :lost_to_rounding, :skipped

      # Acceptance testing for iTunes CloudMatch ETL changes to be completed on 9/11/2015.
      # Use this as a reference for any possible future changes to the accounting run process.
      def self.run
        lost_to_rounding = 0
        all_temp_statements.each do |temp_statement|
          statement = new(temp_statement)
          if statement.skipped
            next
          end
          lost_to_rounding += statement.lost_to_rounding
        end
        puts "gross lost to rounding: #{lost_to_rounding}"
      end

      private

      def self.all_temp_statements
        query_string = "SELECT * FROM TEMP_dig_sales_statements_test"
        query = DbQuery.new(query_string)
        query.expect_results
        query.results
      end

      def initialize(temp_statement)
        statement_detail_id = temp_statement["statement_detail_id"]
        puts "running test for statement_detail_id #{statement_detail_id}"
        #check_if_processed(statement_detail_id)
        unless temp_statement["trans_type"] == "CL"
          puts "  skipping #{statement_detail_id}: transaction type is not CL"
          @skipped = true
          return
        end

        vendor_contract = VendorContract.new(temp_statement["vendor_id"])
        calculator = CloudmatchCalculator.new(temp_statement, vendor_contract)
        expected_statement = calculator.calculate

        processed_statement = DbQuery.get_single_row("processed_dig_sales", statement_detail_id: statement_detail_id)
        compare_statements(expected_statement, processed_statement)
        @lost_to_rounding = calculator.unrounded_gross - processed_statement["gross"]
      end

      def check_if_processed(id)
        result = DbQuery.get_single_row("TEMP_dig_sales_processed_test", statement_detail_id: id)
        fail "#{id} not processed" unless result["processed"] == 'Y'
      end

      def compare_statements(expected_statement, actual_statement)
        expected_statement.each_pair do |key, expected_value|
          actual_value = actual_statement[key].to_f
          puts "  comparing for #{key}: expected #{expected_value}, actual #{actual_value}"
          error = (expected_value - actual_value)/actual_value
          fail "#{key} discrepency of #{error}" if error > error_tolerance
        end
      end

      def error_tolerance
        10**-6
      end
    end
  end
end
