# frozen_string_literal: true

# If Mini Profiler is included via gem
if Rails.configuration.respond_to?(:load_mini_profiler) && Rails.configuration.load_mini_profiler &&
     RUBY_ENGINE == "ruby"
  require "rack-mini-profiler"
  require "stackprof"

  begin
    require "memory_profiler"
  rescue => e
    STDERR.put "#{e} failed to require mini profiler"
  end

  # initialization is skipped so trigger it
  Rack::MiniProfilerRails.initialize!(Rails.application)
end

if defined?(Rack::MiniProfiler) && defined?(Rack::MiniProfiler::Config)
  # note, we may want to add some extra security here that disables mini profiler in a multi hosted env unless user global admin
  #   raw_connection means results are not namespaced
  #
  # namespacing gets complex, cause mini profiler is in the rack chain way before multisite
  Rack::MiniProfiler.config.storage_instance =
    Rack::MiniProfiler::RedisStore.new(connection: DiscourseRedis.new(nil, namespace: false))

  Rack::MiniProfiler.config.snapshot_every_n_requests = GlobalSetting.mini_profiler_snapshots_period
  Rack::MiniProfiler.config.snapshots_transport_destination_url =
    GlobalSetting.mini_profiler_snapshots_transport_url
  Rack::MiniProfiler.config.snapshots_transport_auth_key =
    GlobalSetting.mini_profiler_snapshots_transport_auth_key
  Rack::MiniProfiler.config.skip_paths =
    %w[
      /assets/
      /cdn_asset/
      /extra-locales/
      /favicon/proxied
      /highlight-js/
      /images/
      /javascripts/
      /letter_avatar_proxy/
      /letter_avatar/
      /logs
      /manifest.webmanifest
      /message-bus/
      /opensearch.xml
      /presence/
      /secure-media-uploads/
      /secure-uploads/
      /srv/status
      /stylesheets/
      /svg-sprite/
      /theme-javascripts
      /topics/timings
      /uploads/
      /user_avatar/
      /theme-qunit/
    ].map { |path| "#{Discourse.base_path}#{path}" }.concat([%r{/(\d+/)?(theme-qunit|tests)}])

  # we DO NOT WANT mini-profiler loading on anything but real desktops and laptops
  # so let's rule out all handheld, tablet, and mobile devices
  Rack::MiniProfiler.config.pre_authorize_cb =
    lambda { |env| env["HTTP_USER_AGENT"] !~ /iPad|iPhone|Android/ }

  # without a user provider our results will use the ip address for namespacing
  #  with a load balancer in front this becomes really bad as some results can
  #  be stored associated with ip1 as the user and retrieved using ip2 causing 404s
  Rack::MiniProfiler.config.user_provider =
    lambda do |env|
      request = Rack::Request.new(env)
      id = request.cookies["_t"] || request.ip || "unknown"
      id = id.to_s
      # some security, lets not have these tokens floating about
      Digest::MD5.hexdigest(id)
    end

  # Cookie path should be set to the base path so Discourse's session cookie path
  #  does not get clobbered.
  Rack::MiniProfiler.config.cookie_path = Discourse.base_path.presence || "/"

  Rack::MiniProfiler.config.position = "right"

  Rack::MiniProfiler.config.backtrace_ignores ||= []
  Rack::MiniProfiler.config.backtrace_ignores << %r{lib/rack/message_bus.rb}
  Rack::MiniProfiler.config.backtrace_ignores << %r{config/initializers/silence_logger}
  Rack::MiniProfiler.config.backtrace_ignores << %r{config/initializers/quiet_logger}

  Rack::MiniProfiler.config.backtrace_includes = [%r{^/?(app|config|lib|test|plugins)}]

  Rack::MiniProfiler.config.max_traces_to_show = 100 if Rails.env.development?

  Rack::MiniProfiler.config.content_security_policy_nonce =
    Proc.new do |env, headers|
      if csp = headers["Content-Security-Policy"] || headers["Content-Security-Policy-Report-Only"]
        csp[/script-src[^;]+'nonce-([^']+)'/, 1]
      end
    end

  Rack::MiniProfiler.counter_method(Redis::Client, :call_v) { "redis" }
end

if ENV["PRINT_EXCEPTIONS"]
  trace =
    TracePoint.new(:raise) do |tp|
      puts tp.raised_exception
      puts tp.raised_exception.backtrace.join("\n")
      puts
    end
  trace.enable
end
