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

require 'contrast/components/logger'
require 'contrast/utils/object_share'
require 'contrast/agent/reporting/reporting_events/application_defend_attack_activity'

module Contrast
  module Agent
    module Reporting
      # This is the new AttackerActivity class which will includes the attacker information discovered during this
      # activity period.
      class ApplicationDefendAttackerActivity
        include Contrast::Components::Logger::InstanceMethods
        # @return [Hash<String,Contrast::Agent::Reporting::ApplicationDefendAttackActivity>] map of rule-id to violated
        #   samples for that rule
        attr_accessor :protection_rules
        # @return [String, nil] the IP address of the request from which the attack originated; used to identify unique
        #   attackers
        attr_reader :source_ip
        # @return [String, nil] the X-Forwarded-For Header of the request from which the attack originated; used to
        #   identify unique attackers
        attr_reader :source_forwarded_for

        def initialize
          @protection_rules = {}
          req = Contrast::Agent::REQUEST_TRACKER.current&.request
          if req
            @source_ip = req.ip || Contrast::Utils::ObjectShare::EMPTY_STRING
            @source_forwarded_for = req.headers['X-Forwarded-For']
          end
          @event_type = :application_defend_attacker_activity
        end

        def to_controlled_hash
          processed_rules = process_protection_rules
          validate(processed_rules)

          {
              protectionRules: processed_rules,
              source: {
                  ip: source_ip,
                  xForwardedFor: source_forwarded_for
              }
          }
        end

        def validate processed_rules
          raise(ArgumentError, 'Protection Rules are not presented') if processed_rules.empty?
          raise(ArgumentError, 'Source is not presented') unless source_ip
        end

        # @param attack_result [Contrast::Agent::Reporting::AttackResult]
        def attach_data attack_result
          @protection_rules[attack_result.rule_id] = Contrast::Agent::Reporting::ApplicationDefendAttackActivity.new.
              tap do |activity|
            activity.attach_data(attack_result)
          end
        end

        def process_protection_rules
          hsh = {}
          @protection_rules.each_pair do |rule_id, attack_activity|
            hsh[rule_id] = attack_activity.to_controlled_hash
          end
          hsh
        end
      end
    end
  end
end