require_relative './helpers'

describe BeefCake::AttachedPermission do
  include_context 'with example roles'

  describe('find') do
    before(:each) do
      expect(BeefCake::Role).to receive(:find)
        .with(role_id)
        .and_return(role)
    end

    it 'succeeds' do
      expect(
        described_class.find(
          role_id: role_id,
          attached_permission_id: role_perm_id
        )
      ).to eq(attached_permission)
    end
  end

  describe('delete') do
    let(:method) { -> { attached_permission.delete } }
    let(:twirp_method) { :remove_legacy_permission_from_role }
    let(:twirp_request) do
      Twitch::Fulton::Beefcake::RemoveLegacyPermissionFromRoleRequest.new(
        role_id: role_id,
        legacy_permission_id: perm_id
      )
    end
    let(:twirp_data) { Twitch::Fulton::Beefcake::RemoveLegacyPermissionFromRoleResponse.new }
    let(:expected) { true }

    it_behaves_like 'a twirp backed service'
  end

  describe('update_scope') do
    let(:new_scope_as_strings) { ['PARTNER'] }
    let(:new_scope) do
      [
        Twitch::Fulton::Beefcake::PermissionScope.new(
          channel_payout: Twitch::Fulton::Beefcake::PermissionScope::ChannelPayoutType::PARTNER
        )
      ]
    end
    let(:method) { -> { attached_permission.update_scope(new_scope_as_strings) } }
    let(:twirp_method) { :update_role_permission_scope }
    let(:twirp_request) do
      Twitch::Fulton::Beefcake::UpdateRolePermissionScopeRequest.new(
        role_id: role_id,
        role_permission_id: role_perm_id,
        scope: new_scope
      )
    end
    let(:twirp_data) { Twitch::Fulton::Beefcake::UpdateRolePermissionScopeResponse.new }
    let(:expected) { true }

    it_behaves_like 'a twirp backed service'
  end

  describe('payout_entity_scope') do
    it 'succeeds' do
      expect(attached_permission.payout_entity_scope).to eq(perm_scope_s)
    end
  end

  describe('permitted_on_twitch_user?') do
    shared_examples 'an authorization check on against a twitch user' do
      let(:attached_permission) { described_class.from_attributes(scope: scope) }
      let(:twitch_user) { Twitch::User.new }
      let(:required_scope) do
        Twitch::Fulton::Beefcake::PermissionScope.new(
          channel_payout: Twitch::Fulton::Beefcake::PermissionScope::ChannelPayoutType.resolve(channel_payout_type)
        )
      end
      let(:non_matching_scope) do
        Twitch::Fulton::Beefcake::PermissionScope.new(
          channel_payout: Twitch::Fulton::Beefcake::PermissionScope::ChannelPayoutType.resolve(non_matching_channel_payout_type)
        )
      end

      context('no scope for permission') do
        let(:scope) { [] }

        it('returns true') do
          expect(attached_permission.permitted_on_twitch_user?(twitch_user)).to eq(true)
        end
      end

      context('scope for permission') do
        context('matches') do
          let(:scope) { [required_scope] }

          it('returns true') do
            expect(attached_permission.permitted_on_twitch_user?(twitch_user)).to eq(true)
          end
        end

        context('does not match') do
          let(:scope) { [non_matching_scope] }

          it('returns false') do
            expect(attached_permission.permitted_on_twitch_user?(twitch_user)).to eq(false)
          end
        end
      end
    end

    context('on partner') do
      let(:channel_payout_type) { :PARTNER }
      let(:non_matching_channel_payout_type) { :NO_PAYOUT_TYPE }

      before(:each) do
        allow(twitch_user).to receive(:partner_program?).and_return(true)
      end

      it_behaves_like 'an authorization check on against a twitch user'
    end

    context('on affiliate') do
      let(:channel_payout_type) { :AFFILIATE }
      let(:non_matching_channel_payout_type) { :NO_PAYOUT_TYPE }

      before(:each) do
        allow(twitch_user).to receive(:partner_program?).and_return(false)
        allow(twitch_user).to receive(:affiliate?).and_return(true)
      end

      it_behaves_like 'an authorization check on against a twitch user'
    end

    context('on developer') do
      let(:channel_payout_type) { :DEVELOPER }
      let(:non_matching_channel_payout_type) { :NO_PAYOUT_TYPE }

      before(:each) do
        allow(twitch_user).to receive(:partner_program?).and_return(false)
        allow(twitch_user).to receive(:affiliate?).and_return(false)
        allow(twitch_user).to receive(:developer?).and_return(true)
      end

      it_behaves_like 'an authorization check on against a twitch user'
    end

    context('on no payout type') do
      let(:channel_payout_type) { :NO_PAYOUT_TYPE }
      let(:non_matching_channel_payout_type) { :DEVELOPER }

      before(:each) do
        allow(twitch_user).to receive(:partner_program?).and_return(false)
        allow(twitch_user).to receive(:affiliate?).and_return(false)
        allow(twitch_user).to receive(:developer?).and_return(false)
      end

      it_behaves_like 'an authorization check on against a twitch user'
    end
  end
end
