# frozen_string_literal: true

if GlobalSetting.skip_redis?
  MessageBus.configure(backend: :memory)
  return
end

MessageBus.site_id_lookup do |env = nil|
  if env
    setup_message_bus_env(env)
    env["__mb"][:site_id]
  else
    RailsMultisite::ConnectionManagement.current_db
  end
end

def setup_message_bus_env(env)
  return if env["__mb"]

  if (queue_time = env[Middleware::ProcessingRequest::REQUEST_QUEUE_SECONDS_ENV_KEY]) &&
       Discourse.redis.get("docker_manager:upgrade:server_restarting").blank?
    if queue_time > GlobalSetting.reject_message_bus_queue_seconds.to_f
      raise RateLimiter::LimitExceeded, 30 + (rand * 120).to_i
    end
  end

  host = RailsMultisite::ConnectionManagement.host(env)
  RailsMultisite::ConnectionManagement.with_hostname(host, raise_on_missing: false) do
    cors_origin = Discourse.base_url_no_prefix

    if GlobalSetting.enable_cors && SiteSetting.cors_origins.present?
      allowed_origins = SiteSetting.cors_origins_map
      cors_origin = env["HTTP_ORIGIN"] if allowed_origins.include?(env["HTTP_ORIGIN"])
    end

    extra_headers = {
      "Access-Control-Allow-Origin" => cors_origin,
      "Access-Control-Allow-Methods" => "GET, POST",
      "Access-Control-Allow-Headers" =>
        "X-SILENCE-LOGGER, X-Shared-Session-Key, Dont-Chunk, Discourse-Present, Discourse-Deferred-Track-View",
      "Access-Control-Max-Age" => "7200",
    }

    user = nil
    begin
      user = CurrentUser.lookup_from_env(env)
    rescue Discourse::InvalidAccess => e
      # this is bad we need to remove the cookie
      if e.opts[:delete_cookie].present?
        extra_headers["Set-Cookie"] = "_t=del; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"
      end
    rescue => e
      Discourse.warn_exception(e, message: "Unexpected error in Message Bus", env: env)
    end

    user_id = user&.id

    raise Discourse::InvalidAccess if !user_id && SiteSetting.login_required

    is_admin = user&.admin || false

    logged_in_pseudogroups =
      if SiteSetting.granular_anonymous_and_logged_in_groups_permissions
        [Group::AUTO_GROUPS[:logged_in_users]]
      else
        [Group::AUTO_GROUPS[:logged_in_users], Group::AUTO_GROUPS[:everyone]]
      end

    group_ids =
      if is_admin
        # Special rule, admin is allowed access to all groups
        Group.pluck(:id) + logged_in_pseudogroups
      elsif user
        user.belonging_to_group_ids + logged_in_pseudogroups
      else
        [Group::AUTO_GROUPS[:anonymous_users]]
      end

    extra_headers["Discourse-Logged-Out"] = "1" if env[Auth::DefaultCurrentUserProvider::BAD_TOKEN]

    if Rails.env.development?
      # Adding no-transform prevents the expressjs ember-cli proxy buffering/compressing the response
      extra_headers["Cache-Control"] = "no-transform, must-revalidate, private, max-age=0"
    end

    hash = {
      extra_headers: extra_headers,
      user_id: user_id,
      group_ids: group_ids,
      is_admin: is_admin,
      site_id: RailsMultisite::ConnectionManagement.current_db,
    }
    env["__mb"] = hash
  end

  nil
end

MessageBus.extra_response_headers_lookup do |env|
  setup_message_bus_env(env)
  headers = env["__mb"][:extra_headers]
  if view_tracking_data = env["discourse.view_tracking_data"]
    headers["X-Discourse-TrackView"] = "1" if view_tracking_data[:track_view]
    headers["X-Discourse-BrowserPageView"] = "1" if view_tracking_data[:browser_page_view]
  end
  headers
end

MessageBus.user_id_lookup do |env|
  setup_message_bus_env(env)
  env["__mb"][:user_id]
end

MessageBus.group_ids_lookup do |env|
  setup_message_bus_env(env)
  env["__mb"][:group_ids]
end

MessageBus.is_admin_lookup do |env|
  setup_message_bus_env(env)
  env["__mb"][:is_admin]
end

MessageBus.on_middleware_error do |env, e|
  if Discourse::InvalidAccess === e
    [403, {}, ["Invalid Access"]]
  elsif RateLimiter::LimitExceeded === e
    [429, { "Retry-After" => e.available_in.to_s }, [e.description]]
  end
end

MessageBus.on_connect do |site_id|
  RailsMultisite::ConnectionManagement.establish_connection(db: site_id)
end

MessageBus.on_disconnect do |site_id|
  ActiveRecord::Base.connection_handler.clear_active_connections!
end

if Rails.env.test?
  MessageBus.configure(backend: :memory)
else
  MessageBus.redis_config = GlobalSetting.message_bus_redis_config
end

MessageBus.backend_instance.max_backlog_size = GlobalSetting.message_bus_max_backlog_size
MessageBus.backend_instance.clear_every = GlobalSetting.message_bus_clear_every
MessageBus.long_polling_enabled =
  GlobalSetting.enable_long_polling.nil? ? true : GlobalSetting.enable_long_polling
MessageBus.long_polling_interval = GlobalSetting.long_polling_interval || 25_000

if Rails.env.test? || $0 =~ /rake$/
  # disable keepalive in testing
  MessageBus.keepalive_interval = -1
end
