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

require 'contrast/agent/reporting/settings/assess_rule'
require 'contrast/agent/reporting/settings/protect_rule'

module Contrast
  module Agent
    module Reporting
      # This module will hold the methods for TS response conversion to settings objects.
      module ResponseExtractor
        private

        ##########################################
        #         Server Settings Parsing        #
        ##########################################

        # This method is universal and used for both ng endpoing 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 extract_assess_server_settings response_data, res
          assess = response_data[:assess]
          return unless assess

          res.server_features.assess.enabled = assess[:enable]
          res.server_features.assess.report_stacktraces = assess[:report_stacktraces]
          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 extract_protect_server_settings response_data, res
          protect = response_data[:protect]
          return unless protect

          res.server_features.protect.enabled = protect[:enable]
          res.server_features.protect.observability = protect[:observability]
          res.server_features.protect.log_enhancers = protect[:log_enhancers]
          update_protect_rules(protect, res)
        end

        # This method is used with ServerSettings as we expect to have data for
        # all the loggers - security_logger, logger, syslog.
        #
        # @param response_data [Hash]
        # @param res [Contrast::Agent::Reporting::Response]
        def extract_loggers response_data, res
          logger = response_data[:logger]
          security_logger = response_data[:security_logger]

          if logger
            res.server_features.log_level = logger[:level]
            res.server_features.log_file = logger[:path]
          end
          return unless security_logger

          log_level = security_logger[:level]
          log_file = security_logger[:path]
          res.server_features.security_logger.log_level = log_level
          res.server_features.security_logger.log_file = log_file
          res.server_features.security_logger.not_blank!
          res.server_features.security_logger.syslog.assign_array(response_data[:security_logger][:syslog], ng_: false)
        end

        # @param protect [Hash] response data
        # @param res [Contrast::Agent::Reporting::Response]
        def update_protect_rules protect, res
          return unless (rules = protect[:rules])

          res.server_features.protect.ip_allowlist = rules[:ip_allowlist]
          res.server_features.protect.ip_denylist = rules[:ip_denylist]
          res.server_features.protect.bot_blocker.enable = rules[:bot_blocker][:enable]
          res.server_features.protect.bot_blocker.bots = rules[:bot_blocker][:bots]
          res.server_features.protect.rules_to_definition_list(rules)
        end

        ##########################################
        #      Application Settings Parsing      #
        ##########################################

        # @param response_data [Hash]
        # @param res [Contrast::Agent::Reporting::Response]
        def extract_assess_application_settings response_data, res
          assess = response_data[:assess]
          return unless assess

          assess.each_pair do |rule_id, value|
            rule_setting =
              Contrast::Agent::Reporting::Settings::AssessRule.new.tap { |setting| setting.enable = value[:enable] }
            res.application_settings.assess.rule_settings[rule_id.to_s] = rule_setting
          end

          # This endpoint can never give us session_id, so we dont need to set it here
          # res.application_settings.assess.session_id
        end

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

          rules = protect[:rules]
          rules&.each_pair do |rule_id, value|
            rule_setting =
              Contrast::Agent::Reporting::Settings::ProtectRule.new.tap { |setting| setting.mode = value[:mode] }
            res.application_settings.protect.rule_settings[rule_id.to_s] = rule_setting
          end
          protect[:'virtual-patches']&.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 extract_exclusions response_data, res
          exclusions = response_data[:exclusions]
          return unless exclusions

          res.application_settings.exclusions.url_exclusions = exclusions[:url]
          res.application_settings.exclusions.input_exclusions = exclusions[:input]
        end

        # @param response_data [Hash]
        # @param res [Contrast::Agent::Reporting::Response]
        def extract_sensitive_data_policy response_data, res
          return unless (sensitive_data = response_data[: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

        # @param response_data [Hash]
        # @param res [Contrast::Agent::Reporting::Response]
        def extract_reactions response_data, res
          res.reactions = response_data[:reactions]
        end
      end
    end
  end
end