require 'rails_helper'

RSpec.describe TwoFactorAuthentication::WebauthnUpdateForm do
  let(:user) { create(:user) }
  let(:original_name) { 'original-name' }
  let(:configuration) { create(:webauthn_configuration, user:, name: original_name) }
  let(:configuration_id) { configuration&.id }
  let(:form) { described_class.new(user:, configuration_id:) }

  describe '#submit' do
    let(:name) { 'new-namae' }
    let(:result) { form.submit(name:) }

    it 'returns a successful result' do
      expect(result.success?).to eq(true)
      expect(result.to_h).to eq(
        success: true,
        configuration_id:,
        platform_authenticator: false,
      )
    end

    context 'with platform authenticator' do
      let(:configuration) do
        create(:webauthn_configuration, :platform_authenticator, user:, name: original_name)

        it 'includes platform authenticator detail in result' do
          expect(result.to_h[:platform_authenticator]).to eq(true)
        end
      end
    end

    it 'saves the new name' do
      result

      expect(configuration.reload.name).to eq(name)
    end

    context 'with blank configuration' do
      let(:configuration) { nil }

      it 'returns an unsuccessful result' do
        expect(result.success?).to eq(false)
        expect(result.to_h).to eq(
          success: false,
          error_details: {
            configuration_id: { configuration_not_found: true },
          },
          configuration_id:,
          platform_authenticator: nil,
        )
      end
    end

    context 'with configuration that does not exist' do
      let(:configuration_id) { 'does-not-exist' }

      it 'returns an unsuccessful result' do
        expect(result.success?).to eq(false)
        expect(result.to_h).to eq(
          success: false,
          error_details: {
            configuration_id: { configuration_not_found: true },
          },
          configuration_id:,
          platform_authenticator: nil,
        )
      end
    end

    context 'with configuration not belonging to the user' do
      let(:configuration) { create(:webauthn_configuration, name: original_name) }

      it 'returns an unsuccessful result' do
        expect(result.success?).to eq(false)
        expect(result.to_h).to eq(
          success: false,
          error_details: {
            configuration_id: { configuration_not_found: true },
          },
          configuration_id:,
          platform_authenticator: nil,
        )
      end

      it 'does not save the new name' do
        expect(configuration).not_to receive(:save)

        result

        expect(configuration.reload.name).to eq(original_name)
      end
    end

    context 'with blank name' do
      let(:name) { '' }

      it 'returns an unsuccessful result' do
        expect(result.success?).to eq(false)
        expect(result.to_h).to eq(
          success: false,
          error_details: {
            name: { blank: true },
          },
          configuration_id:,
          platform_authenticator: false,
        )
      end

      it 'does not save the new name' do
        expect(configuration).not_to receive(:save)

        result

        expect(configuration.reload.name).to eq(original_name)
      end

      context 'with platform authenticator' do
        let(:configuration) do
          create(:webauthn_configuration, :platform_authenticator, user:, name: original_name)

          it 'includes platform authenticator detail in result' do
            expect(result.to_h[:platform_authenticator]).to eq(true)
          end
        end
      end
    end

    context 'with duplicate name' do
      before do
        create(:webauthn_configuration, user:, name:)
      end

      it 'returns an unsuccessful result' do
        expect(result.success?).to eq(false)
        expect(result.to_h).to eq(
          success: false,
          error_details: {
            name: { duplicate: true },
          },
          configuration_id:,
          platform_authenticator: false,
        )
      end

      it 'does not save the new name' do
        expect(configuration).not_to receive(:save)

        result

        expect(configuration.reload.name).to eq(original_name)
      end

      context 'with platform authenticator' do
        let(:configuration) do
          create(:webauthn_configuration, :platform_authenticator, user:, name: original_name)

          it 'includes platform authenticator detail in result' do
            expect(result.to_h[:platform_authenticator]).to eq(true)
          end
        end
      end
    end
  end

  describe '#name' do
    subject(:name) { form.name }

    it 'returns configuration name' do
      expect(name).to eq(configuration.name)
    end
  end

  describe '#configuration' do
    subject(:form_configuration) { form.configuration }

    it 'returns configuration' do
      expect(form_configuration).to eq(configuration)
    end
  end
end
