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

require 'contrast/agent/protect/rule/cmd_injection'
require 'contrast/agent/protect/rule/deserialization'
require 'contrast/agent/protect/rule/no_sqli'
require 'contrast/agent/reporting/attack_result/user_input'
require 'contrast/agent/reporting/attack_result/response_type'
require 'contrast/components/logger'

module Contrast
  module Agent
    module Reporting
      # This is the new ApplicationDefendAttackSample class which includes a samples of an attack for the given rule of
      # the given result observed in the activity period.
      class ApplicationDefendAttackSample
        include Contrast::Agent::Reporting::InputType

        # @return [Contrast::Agent::Reporting::UserInput]
        attr_accessor :user_input
        # @return [Array<Contrast::Agent::Reporting::ApplicationDefendAttackSampleStack>]
        attr_reader :stack
        # Details are per rule specific and should be set when the sample is build
        #
        # @return [Contrast::Agent::Reporting::Details::ProtectRuleDetails, {}]
        attr_accessor :details
        # @return [Integer] time in ms
        attr_accessor :time_stamp

        class << self
          # @param attack_result [Contrast::Agent::Reporting::AttackResult]
          # @param attack_sample [Contrast::Agent::Reporting::ApplicationDefendAttackSample]
          def convert attack_result, attack_sample
            activity = new
            activity.attach_data(attack_result, attack_sample)
            activity
          end
        end

        def initialize
          @time_stamp = Contrast::Agent::REQUEST_TRACKER.current&.timer&.start_ms || 0 # in ms
          @blocked = false
          @event_type = :application_defend_attack_sample
          @user_input = Contrast::Agent::Reporting::UserInput.new
          @request = Contrast::Agent::REQUEST_TRACKER.current&.activity&.request
          @stack = Contrast::Utils::StackTraceUtils.build_protect_report_stack_array
          @details = {}
        end

        def to_controlled_hash
          {
              blocked: @blocked,
              input: build_input(@user_input),
              details: @details&.to_controlled_hash,
              request: @request&.to_controlled_hash,
              stack: @stack&.map(&:to_controlled_hash),
              timestamp: build_time_stamp
          }
        end

        # @param response_type [Contrast::Agent::Reporting::ResponseType]
        # @return [Boolean] check if response type is blocked
        def blocked? response_type
          @blocked = response_type == Contrast::Agent::Reporting::ResponseType::BLOCKED
        end

        # @param user_input [Contrast::Agent::Reporting::UserInput]
        def build_input user_input
          {
              documentPath: user_input.path,
              documentType: user_input.document_type.to_s,
              filters: user_input.matcher_ids,
              name: user_input.key,
              time: time_stamp,
              type: user_input.input_type.to_s,
              value: user_input.value
          }
        end

        # @param attack_result [Contrast::Agent::Reporting::AttackResult]
        # @param attack_sample [Contrast::Agent::Reporting::RaspRuleSample]
        def attach_data attack_result, attack_sample
          @blocked = attack_result.response == ::Contrast::Agent::Reporting::ResponseType::BLOCKED
          @user_input = attack_sample.user_input
          @details = attack_sample.details
          @time_stamp = attack_sample.time_stamp
          @request = FindingRequest.convert(Contrast::Agent::REQUEST_TRACKER.current&.request)
          @stack = Contrast::Utils::StackTraceUtils.build_protect_report_stack_array
        end

        # @return [Hash]
        def build_time_stamp
          {
              start: time_stamp,
              elapsed: Contrast::Utils::Timer.now_ms - time_stamp
          }
        end
      end
    end
  end
end