# frozen_string_literal: true

RSpec.describe Users::AssociateAccountsController do
  fab!(:user)
  fab!(:user2) { Fabricate(:user) }

  before { OmniAuth.config.test_mode = true }

  after do
    Rails.application.env_config["omniauth.auth"] = OmniAuth.config.mock_auth[:google_oauth2] = nil
    OmniAuth.config.test_mode = false
  end

  context "when attempting reconnect" do
    before do
      SiteSetting.enable_google_oauth2_logins = true
      OmniAuth.config.mock_auth[:google_oauth2] = OmniAuth::AuthHash.new(
        provider: "google_oauth2",
        uid: "12345",
        info: {
          email: "someemail@test.com",
        },
        extra: {
          raw_info: {
            email_verified: true,
          },
        },
      )

      Rails.application.env_config["omniauth.auth"] = OmniAuth.config.mock_auth[:google_oauth2]
    end

    it "should work correctly" do
      sign_in(user)

      # Reconnect flow:
      post "/auth/google_oauth2?reconnect=true"
      expect(response.status).to eq(302)
      expect(session[:auth_reconnect]).to eq(true)

      OmniAuth.config.mock_auth[:google_oauth2].uid = "123456"
      get "/auth/google_oauth2/callback.json"
      expect(response.status).to eq(302)

      expect(session[:current_user_id]).to eq(user.id) # Still logged in
      expect(UserAssociatedAccount.count).to eq(0) # Reconnect has not yet happened

      # Request associate info
      uri = URI.parse(response.redirect_url)
      get "#{uri.path}.json"
      data = response.parsed_body
      expect(data["provider_name"]).to eq("google_oauth2")
      expect(data["account_description"]).to eq("someemail@test.com")

      # Make the connection
      events = DiscourseEvent.track_events { post "#{uri.path}.json" }
      expect(events.any? { |e| e[:event_name] == :before_auth }).to eq(true)
      expect(
        events.any? do |e|
          e[:event_name] === :after_auth && Auth::GoogleOAuth2Authenticator === e[:params][0] &&
            !e[:params][1].failed?
        end,
      ).to eq(true)

      expect(response.status).to eq(200)
      expect(UserAssociatedAccount.count).to eq(1)

      # Token cannot be reused
      get "#{uri.path}.json"
      expect(response.status).to eq(404)
    end

    it "should only work within the current session" do
      sign_in(user)

      post "/auth/google_oauth2?reconnect=true"
      expect(response.status).to eq(302)
      expect(session[:auth_reconnect]).to eq(true)

      OmniAuth.config.mock_auth[:google_oauth2].uid = "123456"
      get "/auth/google_oauth2/callback.json"
      expect(response.status).to eq(302)

      expect(session[:current_user_id]).to eq(user.id) # Still logged in
      expect(UserAssociatedAccount.count).to eq(0) # Reconnect has not yet happened

      uri = URI.parse(response.redirect_url)
      get "#{uri.path}.json"
      data = response.parsed_body
      expect(data["provider_name"]).to eq("google_oauth2")
      expect(data["account_description"]).to eq("someemail@test.com")

      cookies.delete "_forum_session"

      get "#{uri.path}.json"
      expect(response.status).to eq(404)
    end

    it "returns the correct response for non-existent tokens" do
      sign_in(user)

      get "/associate/12345678901234567890123456789012.json"
      expect(response.status).to eq(404)

      get "/associate/shorttoken.json"
      expect(response.status).to eq(404)
    end

    it "requires login" do
      # XHR should 403
      get "/associate/#{SecureRandom.hex}.json"
      expect(response.status).to eq(403)
    end
  end
end