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

module Contrast
  module Agent
    module Reporting
      # This module will hold the methods for TS response conversion to settings objects. It is used for those
      # endpoints which have NG in their prefix.
      module NgResponseExtractor
        private

        # @param response_data [Hash]
        # @param res [Contrast::Agent::Reporting::Response]
        def ng_extract_assess response_data, res
          assessments = response_data[:settings][:assessment]
          return unless assessments

          res.application_settings.assess.session_id = assessments[:session_id]
          disabled = assessments[:disabledRules]
          return unless disabled

          disabled.each do |rule_id|
            rule_setting = Contrast::Agent::Reporting::Settings::AssessRule.new.tap { |setting| setting.enable = false }
            res.application_settings.assess.rule_settings[rule_id] = rule_setting
          end
        end

        # @param response_data [Hash]
        # @param res [Contrast::Agent::Reporting::Response]
        def ng_extract_protect response_data, res
          protect = response_data[:settings][:defend]
          return unless protect

          res.application_settings.protect.protection_rules = protect[:protectionRules]
          protect[:virtualPatches]&.each do |patch_json|
            res.application_settings.protect.virtual_patches <<
                Contrast::Agent::Reporting::Settings::VirtualPatch.new(patch_json)
          end
        end

        # @param response_data [Hash]
        # @param res [Contrast::Agent::Reporting::Response]
        def ng_extract_exclusions response_data, res
          exclusions = response_data[:settings][:exceptions]
          return unless exclusions

          # Pass true if the endpoint is ng.
          res.application_settings.exclusions.input_exclusions = [exclusions[:inputExceptions], true]
          res.application_settings.exclusions.url_exclusions = [exclusions[:urlExceptions], true]
        end

        # The responses we receive for feature and settings from TS have different
        # place to store these reactions: body.reactions vs body.settings.reactions.
        #
        # @param response_data [Hash]
        # @param res [Contrast::Agent::Reporting::Response]
        def ng_extract_reactions response_data, res
          res.reactions = response_data[:settings][:reactions] if response_data[:settings]
          res.reactions = response_data[:reactions] if response_data[:features]
        end

        # This method is universal and used for both ng endpoint of feature settings and the new
        # Server settings endpoint. Used in both build_feature_settings and build_server_settings.
        # Passing the ng_ flag determines the use of the endpoint and response used because some of
        # the response fields are with different names or do not exist: [enabled vs enable]
        #
        # @param response_data [Hash]
        # @param res [Contrast::Agent::Reporting::Response]
        def ng_extract_assess_features response_data, res
          assess = response_data[:features][:assessment]
          return unless assess

          res.server_features.assess.enabled = assess[:enabled]
          res.server_features.assess.sampling = assess[:sampling]
          res.server_features.assess.sanitizers = assess[:sanitizers]
          res.server_features.assess.validators = assess[:validators]
        end

        # @param response_data [Hash]
        # @param res [Contrast::Agent::Reporting::Response]
        def ng_extract_protect_features response_data, res
          protect = response_data[:features][:defend]
          return unless protect

          res.server_features.protect.enabled = protect[:enabled]
          res.server_features.protect.bot_blocker.enable = protect[:'bot-blocker']
          res.server_features.protect.bot_blocker.bots = protect[:botBlockers]
          ng_extract_syslog(response_data, res)
        end

        # @param response_data [Hash]
        # @param res [Contrast::Agent::Reporting::Response]
        def ng_extract_syslog response_data, res
          return unless (syslog = response_data[:features][:defend][:syslog])

          res.server_features.protect.syslog.assign_array(syslog, ng_: true)
        end

        # @param response_data [Hash]
        # @param res [Contrast::Agent::Reporting::Response]
        def ng_extract_protect_lists response_data, res
          protect = response_data[:features][:defend]
          return unless protect

          res.server_features.protect.ip_allowlist = protect[:ipAllowlist]
          res.server_features.protect.ip_denylist = protect[:ipDenylist]
          res.server_features.protect.log_enhancers = protect[:logEnhancers]
          res.server_features.protect.ng_rule_definition_list(protect[:ruleDefinitionList])
        end

        # Here we extract the rules and state for the sensitive data masking policy
        # received from TS.
        #
        # @param response_data [Hash]
        # @param res [Contrast::Agent::Reporting::Response]
        def ng_extract_sensitive_data_policy response_data, res
          return unless (sensitive_data = response_data[:settings][:sensitive_data_masking_policy])

          res.application_settings.sensitive_data_masking.mask_http_body = sensitive_data[:mask_http_body]
          res.application_settings.sensitive_data_masking.mask_attack_vector = sensitive_data[:mask_attack_vector]
          res.application_settings.sensitive_data_masking.build_rules_form_settings(sensitive_data[:rules])
        end

        # Here we extract the log settings received from TS.
        #
        # @param response_data [Hash]
        # @param res [Contrast::Agent::Reporting::Response]
        def ng_extract_log_settings response_data, res
          # agent_startup event defines the log level under features.
          log_level = if response_data[:features]
                        response_data[:features][:logLevel]
                      else
                        response_data[:logLevel]
                      end
          return unless log_level

          res.server_features.log_level = log_level
          log_file = if response_data[:features]
                       response_data[:features][:logFile]
                     else
                       response_data[:logFile]
                     end
          return unless log_file

          res.server_features.log_file = log_file
        end
      end
    end
  end
end