require 'rails_helper'

RSpec.describe ZoomUser, type: :model do
  describe 'associations' do
    it { is_expected.to have_many(:zoom_meetings).dependent(:nullify) }
  end

  describe "enums" do
    it { is_expected.to define_enum_for(:tier).with_values([:basic, :pro]) }
  end

  describe 'callbacks' do
    let(:zoom_user) { build(:zoom_user) }

    context '#after_create' do
      it 'triggers create_api_user' do
        allow(zoom_user).to receive(:create_api_user)

        zoom_user.run_callbacks(:create)
        expect(zoom_user).to have_received(:create_api_user)
      end

      it 'assigns api_id' do
        allow_any_instance_of(ZoomGateway).to receive(:create_host).and_return("retrieved_api_id")

        zoom_user.save
        expect(zoom_user.api_id).to eq "retrieved_api_id"
      end

      it 'assigns current account number' do
        allow_any_instance_of(ZoomGateway).to receive(:create_host).and_return("retrieved_api_id")
        ENV['ZOOM_ACCOUNT_NUMBER'] = 'xxx-yyy-zzz'

        zoom_user.save
        expect(zoom_user.account_number).to eq 'xxx-yyy-zzz'
      end
    end

    context '#before_destroy' do
      pending 'aborts if there is api_id assigned'
    end
  end

  describe 'scopes' do
    context '.current_account' do
      before do
        create_list(:zoom_user, 10, :with_api_id, account_number: 'first-account-id')
        create_list(:zoom_user, 25, :with_api_id, account_number: 'second-account-id')
      end

      it 'only returns users from currently set account' do
        ENV['ZOOM_ACCOUNT_NUMBER'] = 'first-account-id'
        expect(ZoomUser.current_account.count).to eq 10
        expect(ZoomUser.current_account.pluck(:account_number).uniq.count).to eq 1
        expect(ZoomUser.current_account.pluck(:account_number).uniq.first).to eq 'first-account-id'
      end
    end

    context '.free' do
      let(:free_user) { create(:zoom_user, :with_api_id) }
      let(:busy_user) { create(:zoom_user, :with_api_id) }
      let(:second_busy_user) { create(:zoom_user, :with_api_id) }
      let!(:meeting_started) { create(:zoom_meeting, zoom_user: busy_user, status: :started) }
      let!(:meeting_created) { create(:zoom_meeting, zoom_user: second_busy_user, status: :created) }

      it 'returns only the users without started / created meetings' do
        users = ZoomUser.free

        expect(users).to include(free_user)
        expect(users).not_to include(busy_user)
        expect(users).not_to include(second_busy_user)
      end
    end
  end


  describe '.current_account?' do
    let(:zoom_user) { create(:zoom_user, :with_api_id, account_number: 'xxx-xxx-xxx') }

    it 'returns true if it belongs to currently set account' do
      ENV['ZOOM_ACCOUNT_NUMBER'] = 'xxx-xxx-xxx'
      expect(zoom_user.current_account?).to be_truthy
    end

    it 'returns false if it doesn\'t belong to currently set account' do
      ENV['ZOOM_ACCOUNT_NUMBER'] = 'yyy-yyy-yyy'
      expect(zoom_user.current_account?).to be_falsey
    end
  end


  context 'static methods' do
    describe '.generate_api_email' do
      it 'contains @' do
        expect(ZoomUser.generate_api_email).to include('@')
      end
    end

    describe '.for_new_meeting' do
      let(:a_basic) { create(:zoom_user, :with_api_id, account_number: 'aaa', tier: :basic) }
      let(:b_basic) { create(:zoom_user, :with_api_id, account_number: 'bbb', tier: :basic) }
      let(:a_pro) { create(:zoom_user, :with_api_id, account_number: 'aaa', tier: :pro) }
      let(:b_pro) { create(:zoom_user, :with_api_id, account_number: 'bbb', tier: :pro) }

      it 'picks free user of requested type from current account' do
        [a_basic, a_pro, b_basic, b_pro]

        stub_env_variables(ZOOM_USER_TYPE: 'basic', ZOOM_ACCOUNT_NUMBER: 'aaa')
        expect(ZoomUser.for_new_meeting).to eq(a_basic)

        stub_env_variables(ZOOM_USER_TYPE: 'pro', ZOOM_ACCOUNT_NUMBER: 'aaa')
        expect(ZoomUser.for_new_meeting).to eq(a_pro)

        stub_env_variables(ZOOM_USER_TYPE: 'basic', ZOOM_ACCOUNT_NUMBER: 'bbb')
        expect(ZoomUser.for_new_meeting).to eq(b_basic)

        stub_env_variables(ZOOM_USER_TYPE: 'pro', ZOOM_ACCOUNT_NUMBER: 'bbb')
        expect(ZoomUser.for_new_meeting).to eq(b_pro)
      end

      context 'no free user' do
        before do
          allow_any_instance_of(ZoomGateway).to receive(:create_host).and_return('host-id')
        end

        it 'creates new user if there is no requested user free available under account' do
          [a_basic, a_pro, b_basic]
          stub_env_variables(ZOOM_USER_TYPE: 'pro', ZOOM_ACCOUNT_NUMBER: 'bbb')

          expect_any_instance_of(ZoomGateway).to receive(:create_host)
          ZoomUser.for_new_meeting
        end

        it 'creates new user if requested user is busy' do
          [a_basic, a_pro, b_basic, b_pro]
          stub_env_variables(ZOOM_USER_TYPE: 'pro', ZOOM_ACCOUNT_NUMBER: 'aaa')
          create(:zoom_meeting, zoom_user: a_pro, status: :started)

          expect_any_instance_of(ZoomGateway).to receive(:create_host)
          ZoomUser.for_new_meeting
        end
      end
    end
  end
end
