# frozen_string_literal: true

require 'rails_helper'

RSpec.describe Users::SessionsController, type: :controller do
  describe 'POST #create' do
    before do
      @request.env['devise.mapping'] = Devise.mappings[:user]
    end

    let(:user) { create :user }
    let(:password) { 'asdf1243' }
    let(:params) do
      { user: {
        email: user.email,
        password: password
      } }
    end

    let(:action) do
      post :create, params: params
    end

    context 'when have invalid email or password' do
      let(:password) { '123' }

      it 'returns error message' do
        action

        expect(flash[:alert]).to eq('Invalid Email or password.')
      end

      it 'does not set current user' do
        expect { action }.not_to(change { subject.current_user })
      end
    end

    context 'when have valid email and password' do
      context 'when user has 2FA disabled' do
        it 'returns successfully log in' do
          action

          expect(flash[:notice]).to eq('Logged in successfully.')
        end

        it 'sets current user' do
          expect { action }.to(change { subject.current_user }.from(nil).to(User))
        end
      end

      context 'when user has 2FA enabled' do
        it 'redirects to 2fa code form, sets the session and does not sign in the user' do
          user.two_factor_auth_enabled = true
          user.save!
          expect(action).to redirect_to(users_two_factor_auth_path)
          expect(action.request.session[:otp_user_id]).to eq user.id
          expect { action }.not_to(change { subject.current_user })
        end
      end
    end
  end

  describe 'POST #authenticate_with_two_factor' do
    before do
      @request.env['devise.mapping'] = Devise.mappings[:user]
    end

    let(:user) { create :user }
    let(:params) { { otp: '123123' } }
    let(:otp_user_id) { user.id }
    let(:action) do
      post :authenticate_with_two_factor, params: params, session: { otp_user_id: otp_user_id }
    end

    context 'when have valid otp' do
      it 'sets current user' do
        allow_any_instance_of(User).to receive(:valid_otp?).and_return(true)

        expect { action }.to(change { subject.current_user }.from(nil).to(User))
      end
    end

    context 'when have invalid valid otp' do
      it 'returns error message' do
        allow_any_instance_of(User).to receive(:valid_otp?).and_return(nil)
        action

        expect(flash[:alert]).to eq(I18n.t('devise.sessions.2fa.error_message'))
      end

      it 'does not set current user' do
        allow_any_instance_of(User).to receive(:valid_otp?).and_return(nil)

        expect { action }.not_to(change { subject.current_user })
      end
    end

    context 'when user is not found' do
      let(:otp_user_id) { -1 }

      it 'returns error message' do
        action

        expect(flash[:alert]).to eq('Cannot find user!')
      end
    end
  end
end
