require 'rails_helper'

RSpec.describe Users::RulesOfUseController do
  let(:rules_of_use_updated_at) { 1.day.ago }
  let(:accepted_terms_at) { nil }
  let(:user) { create(:user, :fully_registered, accepted_terms_at: accepted_terms_at) }
  before do
    allow(IdentityConfig.store).to receive(:rules_of_use_updated_at)
      .and_return(rules_of_use_updated_at)
  end
  describe 'before_actions' do
    it 'includes appropriate before_actions' do
      expect(subject).to have_actions(
        :before,
        :confirm_signed_in,
        :confirm_need_to_accept_rules_of_use,
      )
    end
  end

  describe '#new' do
    subject(:action) { get :new }

    context 'with a user that has not accepted the rules of use' do
      before do
        sign_in_before_2fa(user)
      end

      it 'renders' do
        action
        expect(response).to render_template(:new)
      end

      it 'logs an analytics event for visiting' do
        stub_analytics

        action

        expect(@analytics).to have_logged_event('Rules of Use Visited')
      end
    end

    context 'with a user that has accepted the rules of use' do
      before do
        sign_in_before_2fa
      end

      it 'redirects to mfa' do
        action

        expect(response).to redirect_to user_two_factor_authentication_url
      end
    end

    context 'with a user who is not up to date with rules of use ' do
      let(:accepted_terms_at) { 2.days.ago }
      before do
        sign_in_before_2fa(user)
      end

      it 'renders' do
        action
        expect(response).to render_template(:new)
      end

      it 'logs an analytics event for visiting' do
        stub_analytics

        action

        expect(@analytics).to have_logged_event('Rules of Use Visited')
      end
    end

    context 'with a user who is up to date with rules of use' do
      let(:accepted_terms_at) { 12.hours.ago }
      before do
        sign_in_before_2fa(user)
      end

      it 'redirects to mfa' do
        action

        expect(response).to redirect_to user_two_factor_authentication_url
      end
    end

    context 'with no user signed in' do
      it 'redirects to root' do
        action

        expect(response).to redirect_to root_url
      end
    end
  end

  describe '#create' do
    context 'when the user needs to accept the rules of use and does accept them' do
      subject(:action) do
        post :create, params: { rules_of_use_form: { terms_accepted: '1' } }
      end

      before do
        sign_in_before_2fa(user)
      end

      it 'updates the user accepted terms at timestamp' do
        action

        expect(controller.current_user.reload.accepted_terms_at).to be_present
      end

      it 'redirects to the two factor authentication page' do
        action

        expect(response).to redirect_to user_two_factor_authentication_url
      end

      it 'logs a successful analytics event' do
        stub_analytics

        action

        expect(@analytics).to have_logged_event(
          'Rules of Use Submitted',
          success: true,
        )
      end

      it 'includes service provider URIs in form-action CSP header when enabled' do
        allow(IdentityConfig.store).to(
          receive(:openid_connect_content_security_form_action_enabled).and_return(true),
        )
        sp = create(:service_provider, issuer: 'example-issuer', redirect_uris: ['https://example.com'])
        params = {
          client_id: sp.issuer,
          response_type: 'code',
          acr_values: Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF,
          scope: 'openid email',
          redirect_uri: sp.redirect_uris.first,
          state: '1234567890123456789012',
          nonce: '1234567890123456789012',
        }
        session[:sp] = {
          issuer: sp.issuer,
          request_url: "http://test.com?#{URI.encode_www_form(params)}",
        }
        action
        expect(response.request.content_security_policy.form_action)
          .to match_array(["'self'", 'https://example.com'])
      end

      it 'does not include service provider URIs in form-action CSP header when disabled' do
        allow(IdentityConfig.store).to(
          receive(:openid_connect_content_security_form_action_enabled).and_return(false),
        )
        sp = create(:service_provider, issuer: 'example-issuer', redirect_uris: ['https://example.com'])
        params = {
          client_id: sp.issuer,
          response_type: 'code',
          acr_values: Saml::Idp::Constants::IAL1_AUTHN_CONTEXT_CLASSREF,
          scope: 'openid email',
          redirect_uri: sp.redirect_uris.first,
          state: '1234567890123456789012',
          nonce: '1234567890123456789012',
        }
        session[:sp] = {
          issuer: sp.issuer,
          request_url: "http://test.com?#{URI.encode_www_form(params)}",
        }
        action
        expect(response.request.content_security_policy.form_action)
          .to match_array(["'self'"])
      end
    end

    context 'when the user needs to accept the rules of use and does not accept them' do
      subject(:action) do
        post :create, params: { rules_of_use_form: { terms_accepted: '0' } }
      end

      before do
        sign_in_before_2fa(user)
      end

      it 'does not updates the user accepted terms at timestamp' do
        action

        expect(controller.current_user.reload.accepted_terms_at).to be_nil
      end

      it 'redirects to the two factor authentication page' do
        action

        expect(response).to render_template(:new)
      end

      it 'logs a failure analytics event' do
        stub_analytics

        action

        expect(@analytics).to have_logged_event(
          'Rules of Use Submitted',
          hash_including(success: false),
        )
      end
    end
  end
end
