require 'rails_helper'

RSpec.describe Bits::UsersController do
  include_context 'mocked permissions'

  let(:permission) { 'user_bits' }
  let(:test_user_id) { '123' }
  let(:test_bits_user) { Bits::User.new(id: test_user_id) }
  let(:test_twitch_user) { Twitch::User.new(id: test_user_id) }

  class SuccessResponse
    attr_accessor :body
    def initialize(options = {})
      @body = options[:body]
    end

    def success?()
      true
    end
  end

  describe 'index' do
    context 'a user without permission' do
      include_context 'an unauthorized user'

      before do
        get :index
      end

      it_behaves_like 'it redirects the user and displays an error'
    end

    context 'a user with permission' do
      include_context 'an authorized user'

      let(:permission) { ['user_bits', 'user_bits'] }

      before do
        get :index
      end

      it_behaves_like 'it returns a success response'
    end
  end

  describe 'show' do
    context 'a user without permission' do
      include_context 'an unauthorized user'

      before do
        get :show, params: {id: test_user_id}
      end

      it_behaves_like 'it redirects the user and displays an error'
    end

    context 'a user with permission' do
      include_context 'an authorized user'

      let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

      before do
        expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
        expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
        expect(Bits::Campaign).to receive(:all).and_return(double(success?: true, status: 200, body: {'bulk_grant_campaigns' => []}))
        get :show, params: {id: test_user_id}
      end

      it_behaves_like 'it returns a success response'
    end
  end

  describe 'add_bits' do
    describe 'permissions' do
      context 'a user without permission' do
        include_context 'an unauthorized user'

        before do
          post :add_bits, params: {user_id: test_user_id, bits_amount: 10, reason: 'test_reason'}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end

      context 'a user with permission' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        context 'sending base add bits request' do
          before do
            expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
            expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
            expect(test_bits_user).to receive(:add_bits).with(10, 'test_reason', 'cool_ldap_login', nil, nil).and_return(SuccessResponse.new)
            post :add_bits, params: {user_id: test_user_id, bits_amount: 10, reason: 'test_reason'}
          end

          it_behaves_like 'it redirects the user and displays a success message'
        end

        context 'sending admin bits request with notify user and origin' do
          before do
            expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
            expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
            expect(test_bits_user).to receive(:add_bits).with(10, 'test_reason', 'cool_ldap_login', 'true', 'test_origin').and_return(SuccessResponse.new)
            post :add_bits, params: {user_id: test_user_id, bits_amount: 10, reason: 'test_reason', notify_user: 'true', origin: 'test_origin'}
          end

          it_behaves_like 'it redirects the user and displays a success message'
        end
      end
    end

    describe 'missing parameters' do
      context 'a request missing bits amount' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          post :add_bits, params: {user_id: test_user_id, reason: 'test_reason'}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end

      context 'a request missing reason' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          post :add_bits, params: {user_id: test_user_id, bits_amount: 10}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end

      context 'a request with notify_user but missing origin' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          post :add_bits, params: {user_id: test_user_id, bits_amount: 10, reason: 'test_reason', notify_user: 'true'}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end
    end
  end

  describe 'add_bits_for_campaign' do
    describe 'permissions' do
      context 'a user without permission' do
        include_context 'an unauthorized user'

        before do
          post :add_bits_for_campaign, params: {user_id: test_user_id, campaign_id: 'a_fake_campaign'}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end

      context 'a user with permission' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        context 'sending base add bits for campaign request' do
          before do
            expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
            expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
            expect(test_bits_user).to receive(:add_bits_for_campaign).with('a_fake_campaign', 'cool_ldap_login').and_return(SuccessResponse.new)
            post :add_bits_for_campaign, params: {user_id: test_user_id, campaign_id: 'a_fake_campaign'}
          end

          it_behaves_like 'it redirects the user and displays a success message'
        end
      end
    end

    describe 'missing parameters' do
      context 'a request missing campaign id' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          post :add_bits_for_campaign, params: {user_id: test_user_id}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end
    end
  end

  describe 'remove_bits' do
    describe 'permissions' do
      context 'a user without permission' do
        include_context 'an unauthorized user'

        before do
          post :remove_bits, params: {user_id: test_user_id, bits_amount: 10, reason: 'test_reason'}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end

      context 'a user with permission' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          expect(test_bits_user).to receive(:remove_bits).with(10, 'test_reason', 'cool_ldap_login').and_return(SuccessResponse.new)
          post :remove_bits, params: {user_id: test_user_id, bits_amount: 10, reason: 'test_reason'}
        end

        it_behaves_like 'it redirects the user and displays a success message'
      end
    end

    describe 'missing parameters' do
      context 'a request missing bits amount' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          post :remove_bits, params: {user_id: test_user_id, reason: 'test_reason'}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end

      context 'a request missing reason' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          post :remove_bits, params: {user_id: test_user_id, bits_amount: 10}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end
    end
  end

  describe 'set_ban_status' do
    describe 'permissions' do
      context 'a user without permission' do
        include_context 'an unauthorized user'

        before do
          post :set_ban_status, params: {user_id: test_user_id, ban_action: 'ban', reason: 'test_reason'}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end

      context 'a user with permission performs ban' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          expect(test_bits_user).to receive(:set_ban_status).with(true, 'test_reason', 'cool_ldap_login').and_return(SuccessResponse.new)
          post :set_ban_status, params: {user_id: test_user_id, ban_action: 'ban', reason: 'test_reason'}
        end

        it_behaves_like 'it redirects the user and displays a success message'
      end

      context 'a user with permission performs unban' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          expect(test_bits_user).to receive(:set_ban_status).with(false, 'test_reason', 'cool_ldap_login').and_return(SuccessResponse.new)
          post :set_ban_status, params: {user_id: test_user_id, ban_action: 'unban', reason: 'test_reason'}
        end

        it_behaves_like 'it redirects the user and displays a success message'
      end
    end

    describe 'missing parameters' do
      context 'a request missing reason' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          post :set_ban_status, params: {user_id: test_user_id, ban_action: 'unban'}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end

      context 'a request with an invalid ban action' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          post :set_ban_status, params: {user_id: test_user_id, ban_action: 'abc', reason: 'test_reason'}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end
    end
  end

  describe 'set_opt_out_status' do
    describe 'permissions' do
      context 'a user without permission' do
        include_context 'an unauthorized user'

        before do
          post :set_opt_out_status, params: {user_id: test_user_id, opt_out_action: 'opt-out', reason: 'test_reason'}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end

      context 'a user with permission performs opt-out' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          expect(test_bits_user).to receive(:set_opt_out_status).with(true, 'test_reason').and_return(SuccessResponse.new)
          post :set_opt_out_status, params: {user_id: test_user_id, opt_out_action: 'opt-out', reason: 'test_reason'}
        end

        it_behaves_like 'it redirects the user and displays a success message'
      end

      context 'a user with permission performs opt-in' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          expect(test_bits_user).to receive(:set_opt_out_status).with(false, 'test_reason').and_return(SuccessResponse.new)
          post :set_opt_out_status, params: {user_id: test_user_id, opt_out_action: 'opt-in', reason: 'test_reason'}
        end

        it_behaves_like 'it redirects the user and displays a success message'
      end
    end

    describe 'missing parameters' do
      context 'a request missing reason' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          post :set_opt_out_status, params: {user_id: test_user_id, opt_out_action: 'opt-out'}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end

      context 'a request with an invalid opt-out action' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          post :set_opt_out_status, params: {user_id: test_user_id, opt_out_action: 'abc', reason: 'test_reason'}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end
    end
  end

  describe 'moderate_cheermote' do
    describe 'permissions' do
      context 'a user without permission' do
        include_context 'an unauthorized user'

        before do
          post :moderate_cheermote, params: {user_id: test_user_id}
        end

        it_behaves_like 'it redirects the user and displays an error'
      end

      context 'a user with permission' do
        include_context 'an authorized user'

        let(:permission) { ['user_bits', 'user_bits', 'user_bits'] }

        before do
          expect(Twitch::User).to receive(:find).with(test_user_id).and_return(test_twitch_user)
          expect(Bits::User).to receive(:find).with(test_user_id).and_return(test_bits_user)
          expect(test_bits_user).to receive(:moderate_cheermote).and_return(SuccessResponse.new)
          post :moderate_cheermote, params: {user_id: test_user_id}
        end

        it_behaves_like 'it redirects the user and displays a success message'
      end
    end
  end
end
