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

require 'contrast/components/base'
require 'contrast/components/config'
require 'contrast/components/settings'

module Contrast
  module Components
    module Assess
      # A wrapper build around the Common Agent Configuration project to allow
      # for access of the values contained in its
      # parent_configuration_spec.yaml.
      # Specifically, this allows for querying the state of the Assess product.
      class Interface
        include Contrast::Components::ComponentBase

        def enabled?
          # config overrides if forcibly set
          return false if forcibly_disabled?
          return true  if forcibly_enabled?

          ::Contrast::SETTINGS.assess_state.enabled == true
        end

        def tainted_columns
          ::Contrast::SETTINGS.tainted_columns
        end

        def forcibly_disabled?
          @_forcibly_disabled = false?(::Contrast::CONFIG.root.assess.enable) if @_forcibly_disabled.nil?
          @_forcibly_disabled
        end

        def rule_disabled? name
          disabled_rules.include?(name)
        end

        # The value of the stacktrace should be treated as an ENUM. We upcase it for
        # faster comparisons when we use it. Anything not one of the known values of
        # 'NONE',  'SOME', or 'ALL' is treated as 'ALL'
        #
        # @return [Symbol] the normalized value of ::Contrast::CONFIG.root.assess.stacktraces
        def capture_stacktrace_value
          @_capture_stacktrace_value ||= case ::Contrast::CONFIG.root.assess.stacktraces.upcase
                                         when 'NONE'
                                           :NONE
                                         when 'SOME'
                                           :SOME
                                         else
                                           :ALL
                                         end
        end

        # Consider capture_stacktrace_value along with the node type
        # to dertmine whether stacktraces should be captured.
        #
        # capture_stacktrace_value -> (:ALL, :NONE, :SOME)
        # node types (SourceNode, PolicyNode, TriggerNode, PropagationNode)
        #
        # @param policy_node [Contrast::Agent::Assess::Policy::PolicyNode] The node in question.
        # @return [Boolean] to capture or not to capture, that is the question.
        def capture_stacktrace? policy_node
          return true if capture_stacktrace_value == :ALL
          return false if capture_stacktrace_value == :NONE

          # Below here capture_stacktrace_value must be :SOME.
          return true if policy_node.cs__is_a?(Contrast::Agent::Assess::Policy::SourceNode)
          return true if policy_node.cs__is_a?(Contrast::Agent::Assess::Policy::TriggerNode)

          false
        end

        def scan_response?
          @_scan_response = !false?(::Contrast::CONFIG.root.assess.enable_scan_response) if @_scan_response.nil?
          @_scan_response
        end

        def require_scan?
          @_require_scan = !false?(::Contrast::CONFIG.root.agent.ruby.require_scan) if @_require_scan.nil?
          @_require_scan
        end

        def require_dynamic_sources?
          return @_require_dynamic_sources unless @_require_dynamic_sources.nil?

          @_require_dynamic_sources = !false?(::Contrast::CONFIG.root.assess.enable_dynamic_sources)
        end

        def non_request_tracking?
          @_non_request_tracking = true?(::Contrast::CONFIG.root.agent.ruby.non_request_tracking) if
            @_non_request_tracking.nil?
          @_non_request_tracking
        end

        def tags
          ::Contrast::CONFIG.root.assess&.tags
        end

        def disabled_rules
          # TODO: RUBY-903
          ::Contrast::CONFIG.root.assess&.rules&.disabled_rules ||
              ::Contrast::SETTINGS.assess_state.disabled_assess_rules ||
              []
        end

        def track_original_object?
          if @_track_original_object.nil?
            @_track_original_object = !false?(::Contrast::CONFIG.root.assess.enable_original_object)
          end

          @_track_original_object
        end

        # The id for this process, based on the session metadata or id provided by the user, as indicated in
        # application startup.
        def session_id
          ::Contrast::SETTINGS.assess_state.session_id
        end

        def max_source_events
          ::Contrast::CONFIG.root.assess.max_context_source_events
        end

        def max_propagation_events
          ::Contrast::CONFIG.root.assess.max_propagation_events
        end

        def time_limit_threshold
          ::Contrast::CONFIG.root.assess.time_limit_threshold
        end

        def max_rule_reported
          ::Contrast::CONFIG.root.assess.max_rule_reported
        end

        private

        def forcibly_enabled?
          @_forcibly_enabled = true?(::Contrast::CONFIG.root.assess.enable) if @_forcibly_enabled.nil?
          @_forcibly_enabled
        end
      end
    end
  end
end