require 'rails_helper'

RSpec.feature 'IAL1 Single Sign On' do
  include SamlAuthHelper

  context 'First time registration', email: true do
    it 'takes user to agency handoff page when sign up flow complete' do
      email = 'test@test.com'
      request_url = saml_authn_request_url

      perform_in_browser(:one) do
        visit request_url
        sign_up_user_from_sp_without_confirming_email(email)
      end

      perform_in_browser(:two) do
        confirm_email_in_a_different_browser(email)
        expect(page).to have_current_path sign_up_completed_path
        expect(page).to have_content t('help_text.requested_attributes.email')
        expect(page).to have_content email
        expect(page).to_not have_content t('help_text.requested_attributes.address')
        expect(page).to_not have_content t('help_text.requested_attributes.birthdate')
        expect(page).to_not have_content t('help_text.requested_attributes.phone')
        expect(page).to_not have_content t('help_text.requested_attributes.social_security_number')

        click_agree_and_continue

        expect(page).to have_current_path complete_saml_path
        expect(page.get_rack_session.keys).to include('sp')
      end
    end

    it 'takes user to the service provider, allows user to visit IDP' do
      user = create(:user, :fully_registered)
      request_url = saml_authn_request_url

      visit request_url
      fill_in_credentials_and_submit(user.email, user.password)
      fill_in_code_with_last_phone_otp
      click_submit_default_twice
      click_agree_and_continue

      expect(page).to have_current_path complete_saml_path

      visit root_path
      expect(page).to have_current_path account_path
    end

    it 'shows user the start page without accordion' do
      sp_content = [
        'Your friendly Government Agency',
        t('headings.create_account_with_sp.sp_text', app_name: APP_NAME),
      ].join(' ')

      visit saml_authn_request_url

      expect(page).to have_current_path new_user_session_path
      expect(page).to have_content(sp_content)
      expect(page).to_not have_css('.usa-accordion__heading')
    end

    it 'shows user the start page with a link back to the SP' do
      visit saml_authn_request_url
      expect(page).to have_link(
        t(
          'links.back_to_sp',
          sp: 'Your friendly Government Agency',
        ), href: return_to_sp_cancel_path(step: :authentication)
      )
    end

    it 'after session timeout, signing in takes user back to SP', :js, allow_browser_log: true do
      user = create(:user, :fully_registered)
      request_url = saml_authn_request_url

      visit request_url
      sp_request_id = ServiceProviderRequestProxy.last.uuid
      allow(IdentityConfig.store).to receive(:session_check_delay).and_return(0)
      allow(IdentityConfig.store).to receive(:session_check_frequency).and_return(1)
      fill_in_credentials_and_submit(user.email, user.password)

      Warden.on_next_request do |proxy|
        session = proxy.env['rack.session']
        session['warden.user.user.session']['last_request_at'] = 30.minutes.ago.to_i
      end

      expect(page).to have_current_path(new_user_session_path(request_id: sp_request_id))
      allow(IdentityConfig.store).to receive(:session_check_delay).and_call_original
      allow(IdentityConfig.store).to receive(:session_check_frequency).and_call_original

      fill_in_credentials_and_submit(user.email, user.password)
      fill_in_code_with_last_phone_otp
      click_submit_default

      # SAML does internal redirect using JavaScript prior to showing consent screen
      expect(page).to have_current_path(sign_up_completed_path)
      click_agree_and_continue

      expect(page).to have_current_path(test_saml_decode_assertion_path)
    end
  end

  context 'fully signed up user authenticates new sp' do
    let(:user) { create(:user, :fully_registered) }
    let(:saml_authn_request) { saml_authn_request_url }

    before do
      sign_in_user(user)
      fill_in_code_with_last_phone_otp
      click_submit_default
      visit saml_authn_request
    end

    it 'redirects user to verify attributes page' do
      sp = ServiceProvider.find_by(issuer: 'http://localhost:3000')
      expect(page).to have_current_path(sign_up_completed_path)
      expect(page).to have_content(
        t(
          'titles.sign_up.completion_first_sign_in',
          sp: sp.friendly_name,
        ),
      )
    end

    it 'returns to sp after clicking continue' do
      click_agree_and_continue
      expect(page).to have_current_path complete_saml_path
    end

    it 'it confirms the user wants to continue to the SP after signing in again' do
      click_agree_and_continue

      set_new_browser_session

      sign_in_user(user)
      fill_in_code_with_last_phone_otp
      click_submit_default

      visit saml_authn_request

      expect(page).to have_current_path(user_authorization_confirmation_path)
      continue_as(user.email)

      expect(page).to have_current_path complete_saml_path
    end
  end

  context 'fully signed up user is signed in with email and password only' do
    it 'prompts to enter OTP' do
      user = create(:user, :fully_registered)
      sign_in_user(user)

      visit saml_authn_request_url

      expect(page).to have_current_path login_two_factor_path(otp_delivery_preference: 'sms')
    end
  end

  context 'user that has not yet set up 2FA is signed in with email and password only' do
    it 'prompts to set up 2FA' do
      sign_in_user

      visit saml_authn_request_url

      expect(page).to have_current_path authentication_methods_setup_path
    end
  end

  context 'visiting IdP via SP, then using the language selector' do
    it 'displays the branded page' do
      visit saml_authn_request_url

      within(first('.language-picker', visible: false)) do
        find_link(t('i18n.locale.es'), visible: false).click
      end

      expect(page).to have_current_path(root_path(locale: :es, trailing_slash: true))
      expect_branded_experience
    end
  end

  context 'visiting IdP via SP, then going back to SP and visiting IdP again' do
    it 'displays the branded page' do
      request_url = saml_authn_request_url
      visit request_url

      expect(page).to have_current_path(root_path)
      expect_branded_experience

      visit request_url

      expect(page).to have_current_path(root_path)
      expect_branded_experience
    end
  end

  context 'canceling sign in after email and password' do
    it 'returns to the branded landing page' do
      user = create(:user, :fully_registered)

      visit saml_authn_request_url
      fill_in_credentials_and_submit(user.email, user.password)
      sp_request_id = ServiceProviderRequestProxy.last.uuid
      sp = ServiceProvider.find_by(issuer: 'http://localhost:3000')
      click_link t('links.cancel')

      expect(page).to have_current_path(new_user_session_path(request_id: sp_request_id))
      expect(page).to have_content t('links.back_to_sp', sp: sp.friendly_name)
    end
  end

  context 'requesting verified_at for an IAL1 account' do
    it 'shows verified_at as a requested attribute, even if blank' do
      user = create(:user, :fully_registered)
      saml_authn_request = saml_authn_request_url(
        overrides: {
          issuer: sp1_issuer,
          authn_context: [
            Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF,
            "#{Saml::Idp::Constants::REQUESTED_ATTRIBUTES_CLASSREF}email,verified_at",
          ],
        },
      )

      visit saml_authn_request
      fill_in_credentials_and_submit(user.email, user.password)
      fill_in_code_with_last_phone_otp
      click_submit_default

      expect(page).to have_current_path complete_saml_path
      click_submit_default
      click_agree_and_continue
      click_submit_default

      xmldoc = SamlResponseDoc.new('feature', 'response_assertion')

      expect(xmldoc.attribute_node_for('verified_at')).to be_present
      expect(xmldoc.attribute_value_for('verified_at')).to be_blank
    end
  end

  context 'requesting locale' do
    it 'includes locale in the response' do
      user = create(:user, :fully_registered)
      saml_authn_request = saml_authn_request_url(
        overrides: {
          issuer: sp1_issuer,
          authn_context: [
            Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF,
            "#{Saml::Idp::Constants::REQUESTED_ATTRIBUTES_CLASSREF}email,locale",
          ],
        },
      )

      visit saml_authn_request
      visit root_url(locale: 'es')
      fill_in_credentials_and_submit(user.email, user.password)
      fill_in_code_with_last_phone_otp
      click_submit_default

      expect(page).to have_current_path complete_saml_path(locale: 'es')
      click_submit_default
      click_agree_and_continue
      click_submit_default

      xmldoc = SamlResponseDoc.new('feature', 'response_assertion')

      expect(xmldoc.attribute_node_for('locale')).to be_present
      expect(xmldoc.attribute_value_for('locale')).to eq('es')
    end
  end
end
