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

# Used to prevent deprecation warnings from flooding stdout
ENV['PB_IGNORE_DEPRECATIONS'] = 'true'

require 'contrast/extension/object'

# ActiveRecord gives access to the `String#blank?` method, which we've started using. We need to make sure that method
# actually exists.
# From https://github.com/rails/rails/blob/main/activesupport/lib/active_support/core_ext/object/blank.rb
class String
  unless cs__respond_to?(:blank?)

    CS__BLANK_RE = /\A[[:space:]]*\z/.cs__freeze
    # A string is blank if it's empty or contains whitespaces only:
    #
    #   ''.blank?       # => true
    #   '   '.blank?    # => true
    #   "\t\n\r".blank? # => true
    #   ' blah '.blank? # => false
    #
    # Unicode whitespace is supported:
    #
    #   "\u00a0".blank? # => true
    #
    # @return [true, false]
    def blank?
      # The regexp that matches blank strings is expensive. For the case of empty
      # strings we can speed up this method (~3.5x) with an empty? call. The
      # penalty for the rest of strings is marginal.
      empty? ||
          begin
            CS__BLANK_RE.match?(self)
          rescue Encoding::CompatibilityError
            false
          end
    end
  end
end

if RUBY_VERSION >= '3.0.0' && RUBY_VERSION < '3.1.0'
  # This fixes Ruby 3.0 issues with Module#(some instance method) patching by preventing the prepending of
  # a JSON helper on protobuf load. String.instance_method(:+) is one of the most noticeable.
  # This is fixed in Ruby 3.1.0
  # TODO: RUBY-1132 Remove this once Ruby 3 support is dropped.
  # See bug here: https://bugs.ruby-lang.org/issues/17725
  class Class
    alias_method(:cs__orig_prepend, :prepend)
    def prepend other
      include(other)
    end
  end
end

require 'contrast/components/assess'
require 'contrast/components/config'
require 'contrast/components/logger'
require 'contrast/components/protect'
require 'contrast/components/sampling'
require 'contrast/components/scope'
require 'contrast/components/settings'
require 'contrast/utils/routes_sent'
require 'contrast/agent/telemetry/exception_hash'
require 'contrast/agent/telemetry/telemetry'
require 'contrast/agent/telemetry/exception/event'
require 'contrast/agent_lib/interface'
require 'contrast/agent/telemetry/cache_hash'
require 'contrast/agent/telemetry/base64_hash'

module Contrast # :nodoc:
  CONFIG = Contrast::Components::Config::Interface.new
  SCOPE = Contrast::Components::Scope::Interface.new
  APP_CONTEXT = CONFIG.application
  API = CONFIG.api
  SETTINGS = Contrast::Components::Settings::Interface.new
  ASSESS = CONFIG.assess
  PROTECT = CONFIG.protect
  INVENTORY = CONFIG.inventory
  AGENT = CONFIG.agent
  RUBY_INTERFACE = AGENT.ruby
  LOGGER = AGENT.logger
  AGENT_LIB = Contrast::AgentLib::Interface.new
end

module Contrast
  TELEMETRY_EXCEPTIONS = (if Contrast::Agent::Telemetry.exceptions_enabled?
                            Contrast::Agent::Telemetry::ExceptionHash.new
                          end)
  TELEMETRY_IA_CACHE = (Contrast::Agent::Telemetry::CacheHash.new if Contrast::Agent::Telemetry::Base.enabled?)
  TELEMETRY_BASE64_HASH = (Contrast::Agent::Telemetry::Base64Hash.new if Contrast::Agent::Telemetry::Base.enabled? &&
    Contrast::PROTECT.normalize_base64?)
  ROUTES_SENT = Contrast::Utils::RoutesSent.new
end

# This needs to be required very early, after component interfaces, and before instrumentation attempts
require 'contrast/funchook/funchook'
require 'contrast/agent/version'

# shared utils
require 'contrast/utils/timer'
require 'contrast/utils/assess/sampling_util'
require 'contrast/agent'

# Prepend fix for Ruby 3.0
# TODO: RUBY-99999 remove once obsolete.
if RUBY_VERSION >= '3.0.0' && RUBY_VERSION < '3.1.0'
  # Put prepend back as it was.
  Class.alias_method(:prepend, :cs__orig_prepend)
  Class.remove_method(:cs__orig_prepend)
end