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

require 'contrast/agent/reporting/settings/sensitive_data_masking_rule'

module Contrast
  module Agent
    module Reporting
      # This module will hold all the settings from the TS responce
      module Settings
        # Protect level settings for the sensitive_data_masking_policy.
        # Configuration of the masking parameters will be delivered dynamically from TeamServer
        # during an ApplicationSettings response from requests to TS endpoints that return that
        # structure.
        # https://contrast.atlassian.net/wiki/spaces/~699189087/pages/807960614/Sensitive+Data+Masking+Design
        class SensitiveDataMasking
          # Policy flag to enable the use of masking on request body
          # Here is set to defaults to true.
          #
          # @return true | false
          def mask_http_body?
            @_mask_http_body
          end

          # Set the flag for request body masking
          #
          # @param bool [Boolean]
          # @return true | false
          def mask_http_body= bool
            @_mask_http_body = bool.nil? ? true : !!bool
          end

          # Policy flag to enable the use of masking on attack vector.
          # Here is set to defaults to false.
          #
          # @return true | false
          def mask_attack_vector?
            @_mask_attack_vector
          end

          # Set the flag for using masking on attack vector
          #
          # @param bool [Boolean]
          # @return true | false
          def mask_attack_vector= bool
            @_mask_attack_vector = !!bool
          end

          # Rules to follow when using the masking
          #
          # @return rules [Array<Contrast::Agent::Reporting::Settings::SensitiveDataMaskingRule>, []]
          def rules
            @_rules ||= Contrast::Agent::Reporting::Settings::RulesArray.new
          end

          # Assign rules array
          #
          # @param rules [Array<Contrast::Agent::Reporting::Settings::SensitiveDataMaskingRule>]
          # @return rules [Array<Contrast::Agent::Reporting::Settings::SensitiveDataMaskingRule>, []]
          def rules= rules
            @_rules = rules if rules_array?(rules)
          end

          # Build rules from hash
          #
          # @param settings_rules [Hash] Response settings under Settings/sensitive_data_masking_policy/rules
          # @return rules [Array<Contrast::Agent::Reporting::Settings::SensitiveDataMaskingRule>, nil
          def build_rules_form_settings settings_rules
            return if settings_rules.nil? || settings_rules.empty?

            settings_rules.each do |rule|
              instance = Contrast::Agent::Reporting::Settings::SensitiveDataMaskingRule.new
              instance.rule_id = rule[:id]
              instance.keywords = rule[:keywords]
              rules << instance
            end
            rules
          end

          def to_controlled_hash
            {
                rules: rules.map(&:to_controlled_hash),
                mask_attack_vector: mask_attack_vector?,
                mask_http_body: mask_http_body?
            }
          end

          private

          # Determine if parameter is array of Rules.
          #
          # @param array [Array<Contrast::Agent::Reporting::Settings::SensitiveDataMaskingRule>] Array of keywords.
          # @return true | false
          def rules_array? array
            return false unless array.is_a?(Array)

            array.all?(Contrast::Agent::Reporting::Settings::SensitiveDataMaskingRule)
          end
        end

        # Simple validation class for Rules Array.
        class RulesArray < Array
          # Do not push anything except Rules instances.
          # :<< method is called on object directly so this
          # will make sure the data pushed is as expected.
          #
          # @param item [Contrast::Agent::Reporting::Settings::SensitiveDataMaskingRule]
          # @return itself [Array<Contrast::Agent::Reporting::Settings::SensitiveDataMaskingRule>]
          def << item
            return itself unless item.instance_of?(Contrast::Agent::Reporting::Settings::SensitiveDataMaskingRule)

            super
          end
        end
      end
    end
  end
end