# Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
# frozen_string_literal: true

require 'contrast/utils/timer'
require 'contrast/agent/reporting/reporting_events/application_defend_attack_sample'
require 'contrast/agent/reporting/reporting_events/reportable_hash'

module Contrast
  module Agent
    module Reporting
      # This is the new AttackerSampleActivity class which will include Sample of the given attacks in the activity
      # period.
      class ApplicationDefendAttackSampleActivity < Contrast::Agent::Reporting::ReportableHash
        # @return [Array<Contrast::Agent::Reporting::ApplicationDefendAttackSample>]
        attr_reader :samples
        # @return [Hash<Integer,Integer>] map of time from start in seconds to number of attacks in that second
        attr_reader :time_map

        def initialize
          @samples = []
          @start_time = Contrast::Agent::REQUEST_TRACKER.current&.timer&.start_ms || 0 # in ms
          @event_type = :application_defend_attack_sample_activity
          @time_map = Hash.new { |h, k| h[k] = 0 }
          super()
        end

        def to_controlled_hash
          validate
          {
              attackTimeMap: time_map,
              samples: samples.map(&:to_controlled_hash),
              startTime: @start_time, # Start time in ms.
              total: 1 # there will only ever be 1 attack sample, until batching is done
          }
        end

        def validate
          raise(ArgumentError, 'Start Time is not presented') unless @start_time
        end

        # @param attack_result [Contrast::Agent::Reporting::AttackResult]
        def attach_data attack_result
          attack_result.samples.each do |attack_sample|
            base_time = Contrast::Agent::REQUEST_TRACKER.current&.timer&.start_ms || 0
            sample_time = attack_sample.time_stamp.to_i
            samples << Contrast::Agent::Reporting::ApplicationDefendAttackSample.convert(attack_result, attack_sample)
            @start_time = if sample_time.zero?
                            @start_time
                          else
                            sample_time
                          end
            attack_second = (@start_time - base_time) / 1000 # in seconds
            time_map[attack_second] += 1
          end
        end

        # This method will merge time_maps of attack samples with same
        # type.
        #
        # @param map [Hash<Integer,Integer>] TimeMap to append to previously_violated rule
        # samples.
        # @return time_map [Hash<Integer,Integer>] merged time map with updated occurrences.
        def merge_time_maps map
          # If the second is the same (key) if we just merge there won't be a new entry,
          # so just increase the attack count.
          map.each_key do |key|
            @time_map[key] = @time_map.fetch(key, 0) + map[key]
          end
          @time_map
        end
      end
    end
  end
end