require_relative './helpers'

RSpec.configure do |c|
  c.include BeefCake::Helpers
end

describe BeefCake::User do
  include_context 'with example users'

  describe('all') do
    let(:expected) { [] }
    let(:options) { {} }

    shared_examples 'a successful request' do
      specify do
        expect(described_class.all(options)).to eq(expected)
      end
    end

    context('text not sent') do
      it_behaves_like 'a successful request'
    end

    context('text sent') do
      let(:options) { { text: text } }
      before(:each) do
        expect(Guardian::User).to receive(:all)
          .with(options)
          .and_return([guardian_user])
      end

      context('matches') do
        let(:expected) do
          [described_class.new(
            ldap_login: user_id,
            email: user_email,
            name: user_name
          )]
        end

        context('ldap_login matches') do
          let(:text) { user_id }
          it_behaves_like 'a successful request'
        end

        context('email matches') do
          let(:text) { user_email }
          it_behaves_like 'a successful request'
        end

        context('name matches') do
          let(:text) { user_name }
          it_behaves_like 'a successful request'
        end
      end

      context('does not match') do
        let(:text) { 'obvious-non-match' }
        it_behaves_like 'a successful request'
      end
    end
  end

  describe('find') do
    let(:method) { -> { described_class.find(user_id, email: user_email) } }
    let(:twirp_method) { :get_user }
    let(:twirp_request) do
      Twitch::Fulton::Beefcake::GetUserRequest.new(id: user_id)
    end

    context('with existing permissions') do
      let(:twirp_data) { twirp_user }
      let(:expected) do
        res = user
        res.email = user_email
        res.active = false
        res
      end

      it_behaves_like 'a twirp backed service'
    end

    context('with no existing permissions') do
      let(:twirp_data) { Twitch::Fulton::Beefcake::User.new }
      let(:expected) do
        described_class.from_attributes(
          ldap_login: user_id,
          email: user_email,
          active: false,
          attached_permissions: {}
        )
      end

      it_behaves_like 'a twirp backed service'
    end
  end

  describe('save') do
    let(:method) { -> { user.save } }
    let(:twirp_method) { :add_user_to_role }
    let(:twirp_request) do
      Twitch::Fulton::Beefcake::AddUserToRoleRequest.new(
        role_id: role_id,
        user_id: user_id
      )
    end
    let(:twirp_data) { twirp_user }
    let(:expected) { true }

    it_behaves_like 'a twirp backed service'
  end

  describe('reactivate_user') do
    let(:method) { -> { user.reactivate } }
    let(:twirp_method) { :reactivate_user }
    let(:twirp_data) { true }
    let(:expected) { true }
    let(:twirp_request) do
      Twitch::Fulton::Beefcake::ReactivateUserRequest.new(
        id: user_id
      )
    end

    it_behaves_like 'a twirp backed service'
  end

  describe('twitch_ldap_user_name') do
    let(:user) { BeefCake::User.from_attributes(ldap_login: ldap_login) }

    context 'a non-titan user' do
      let(:ldap_login) { 'something-else' }
      let(:expected) { 'something-else' }

      it 'returns the expected value' do
        expect(user.twitch_ldap_user_name).to eq(expected)
      end
    end

    context 'a titan user' do
      let(:ldap_login) { 'titan:something' }
      let(:expected) { 'titan-user' }

      it 'returns the expected value' do
        expect(user.twitch_ldap_user_name).to eq(expected)
      end
    end
  end

  describe('permitted?') do
    it('match') do
      expect(user.permitted?(perm_id)).to eq(true)
    end

    it('miss') do
      expect(user.permitted?('something-else')).to eq(false)
    end
  end

  describe('permission_names') do
    it('returns permission ids') do
      expect(user.permission_names).to eq([perm_id])
    end
  end

  describe('admin?') do
    let(:user) do
      res = described_class.new
      res.permissions = permissions.map { |x| BeefCake::Permission.new(id: x) }
      res
    end

    shared_examples 'it checks admin' do
      specify do
        expect(user.admin?).to eq(expected)
      end
    end

    context('admin') do
      let(:permissions) { ['admin_permissions'] }
      let(:expected) { true }
      it_behaves_like 'it checks admin'
    end

    context('non admin') do
      let(:permissions) { ['audits'] }
      let(:expected) { false }
      it_behaves_like 'it checks admin'
    end
  end

  describe('permitted_on_twitch_user?') do
    let(:required_permission_id) { 'users' }
    let(:twitch_user) { Twitch::User.new }

    shared_examples 'it tests against expected' do
      it 'successfully' do
        expect(
          beefcake_user.permitted_on_twitch_user?(required_permission_id, twitch_user)
        ).to eq(expected)
      end
    end

    context('doesnt have attached permission') do
      before(:each) do
      end

      let(:beefcake_user) do
        BeefCake::User.from_attributes(attached_permissions: {})
      end
      let(:expected) { false }

      it_behaves_like 'it tests against expected'
    end

    context('has attached permission') do
      let(:attached_permission) { BeefCake::AttachedPermission.new }
      let(:beefcake_user) do
        BeefCake::User.from_attributes(
          attached_permissions: {
            required_permission_id => attached_permission
          }
        )
      end

      before(:each) do
        expect(attached_permission).to receive(:permitted_on_twitch_user?)
          .with(twitch_user)
          .and_return(permitted_on_twitch_user)
      end

      context('with context') do
        let(:permitted_on_twitch_user) { true }
        let(:expected) { true }

        it_behaves_like 'it tests against expected'
      end

      context('without context') do
        let(:permitted_on_twitch_user) { false }
        let(:expected) { false }

        it_behaves_like 'it tests against expected'
      end
    end
  end
end
