# frozen_string_literal: true

# omniauth loves spending lots cycles in its magic middleware stack
# this middleware bypasses omniauth middleware and only hits it when needed
class Middleware::OmniauthBypassMiddleware
  module OmniAuthStrategyCompatPatch
    def callback_url
      result = super
      if script_name.present? && result.include?("#{script_name}#{script_name}")
        result = result.gsub("#{script_name}#{script_name}", script_name)
        Discourse.deprecate <<~MESSAGE
          OmniAuth strategy '#{name}' included duplicate script_name in callback url. It's likely the callback_url method is concatenating `script_name` with `callback_path`.
          OmniAuth v2 includes the `script_name` in the `callback_path` automatically, so the manual `script_name` call can be removed.
          This issue has been automatically corrected, but the strategy should be updated to ensure subfolder compatibility with future versions of Discourse.
        MESSAGE
      end
      result
    end
  end

  class PatchedOmniAuthBuilder < OmniAuth::Builder
    def use(strategy, *args, **kwargs, &block)
      if !strategy.ancestors.include?(OmniAuthStrategyCompatPatch)
        strategy.prepend(OmniAuthStrategyCompatPatch)
      end
      super(strategy, *args, **kwargs, &block)
    end
  end

  def initialize(app, options = {})
    @app = app
  end

  def call(env)
    return @app.call(env) unless env["PATH_INFO"].start_with?("/auth")

    # When only one provider is enabled, assume it can be completely trusted, and allow GET requests
    only_one_provider = !SiteSetting.enable_local_logins && Discourse.enabled_authenticators.one?

    allow_get = only_one_provider || !SiteSetting.auth_require_interaction

    OmniAuth.config.allowed_request_methods = allow_get ? %i[get post] : [:post]

    omniauth =
      PatchedOmniAuthBuilder.new(@app) do
        Discourse.enabled_authenticators.each do |authenticator|
          authenticator.register_middleware(self)
        end
      end

    omniauth.call(env)
  end
end
