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

require 'rubygems/version'
require 'contrast/agent/rule_set'

module Contrast
  module Components
    module Agent
      # 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 Agent.
      class Interface
        include Contrast::Components::ComponentBase

        def enabled?
          @_enabled = !false?(::Contrast::CONFIG.root.enable) if @_enabled.nil?
          @_enabled
        end

        def disabled?
          !enabled?
        end

        def enable!
          @_enabled = true
        end

        def disable!
          @_enabled = false
          Contrast::Agent::TracePointHook.disable
          Contrast::Agent.thread_watcher&.shutdown!
        end

        def ruleset
          @_ruleset ||= Contrast::Agent::RuleSet.new(retrieve_protect_ruleset.values)
        end

        def reset_ruleset
          @_ruleset = nil
        end

        def patch_yield?
          @_patch_yield = !false?(::Contrast::CONFIG.root.agent.ruby.propagate_yield) if @_patch_yield.nil?
          @_patch_yield
        end

        def interpolation_enabled?
          return @_interpolation_enabled unless @_interpolation_enabled.nil?

          @_interpolation_enabled = !false?(::Contrast::CONFIG.root.agent.ruby.interpolate)
        end

        def omit_body?
          @_omit_body = true?(::Contrast::CONFIG.root.agent.omit_body) if @_omit_body.nil?
          @_omit_body
        end

        def exception_control
          @_exception_control ||= {
              enable: true?(::Contrast::CONFIG.root.agent.ruby.exceptions.capture),
              status:
                ::Contrast::CONFIG.root.agent.ruby.exceptions.override_status || 403,
              message:
                ::Contrast::CONFIG.root.agent.ruby.exceptions.override_message ||
                    Contrast::Utils::ObjectShare::OVERRIDE_MESSAGE
          }
        end

        def skip_instrumentation? loaded_module_name
          return true unless loaded_module_name

          loaded_module_name.start_with?(*::Contrast::CONFIG.root.agent.ruby.uninstrument_namespace)
        end

        # Insert ourselves into the application, keeping our middleware at the outermost layer of the onion
        def insert_middleware app
          app.middleware.insert_before(0, Contrast::Agent::Middleware)
        end

        def enable_tracepoint
          Contrast::Agent::TracePointHook.enable!
        end

        protected

        def retrieve_protect_ruleset
          return {} unless enabled? && ::Contrast::PROTECT.enabled?

          ::Contrast::PROTECT.rules
        end
      end
    end
  end
end