require "rails_helper"

RSpec.describe BeefCake::MembershipsController do
  include_context "mocked permissions"

  let(:permission) { "admin_permissions" }
  let(:uid) {"testing_user_id"}

  describe "new" do
    describe "memberships" do
      let(:action) {:new}
      context "creating a new membership" do
        include_context "an authorized user"

        before do
          get action, :params => {:uid => uid, :role_id => "123"}
        end
        it_behaves_like "it returns a success response"
        it "assigns @referrer_page" do
          expect(@controller.view_assigns['back_url']).to eq("/beef_cake/users/#{uid}/edit")
        end

      end

      context "creating  new temporary membership" do
        include_context "an authorized user"

        before do
          get action, :params => { :uid => uid, :role_id => "123", :expires_at => Time.now.to_date}
        end
        it_behaves_like "it returns a success response"
      end

      context "creating a new membership" do
        include_context "an unauthorized user"

        before do
          get action, :params => { :beef_cake_memberships => { :uid => uid, :role_id => "123", :expires_at => Time.now.to_date}}
        end

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

      context "creating a new temporary membership" do
        include_context "an unauthorized user"

        before do
          get action, :params => { :beef_cake_memberships => { :uid => uid, :role_id => "123", :expires_at => Time.now.to_date}}
        end

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

  describe "create" do
    let(:action) { :create }
    let(:user) { BeefCake::User.new(ldap_login: uid) }
    describe 'memberships' do

      before do
        allow(BeefCake::User).to receive(:find).with(uid).and_return(user)
        allow(user).to receive(:exists?).and_return(true).once
      end
      context "saving a new membership" do
        include_context "an authorized user"

        before do
          expect_any_instance_of(BeefCake::Membership).to receive(:save).and_return(true)
          post action, :params => {:beef_cake_membership => {:uid => uid, :role_id => "123"}}
        end

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

        it "redirects back to user page" do
          expect(response).to redirect_to(edit_beef_cake_user_path(uid))
        end
      end

      context "saving a new membership json" do
        include_context "an authorized user"

        before do
          expect_any_instance_of(BeefCake::Membership).to receive(:save).and_return(true)
          post action, :params => {:beef_cake_membership => {:uid => uid, :role_id => "123"}}, format: :json
        end
        it "has correct response" do
          parsed_body = JSON.parse(response.body)
          expect(parsed_body["uid"]).not_to be_nil
          expect(parsed_body["role_id"]).not_to be_nil
        end
      end

      context "saving a new membership with blank expiry" do
        include_context "an authorized user"

        before do
          expect_any_instance_of(BeefCake::Membership).to receive(:save).and_return(true)
          post action, :params => {:beef_cake_membership => {:uid => uid, :role_id => "123", :expires_at => ""}}
        end

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

        it "redirects back to user page" do
          expect(response).to redirect_to(edit_beef_cake_user_path(uid))
        end
      end

      context "saving a temp membership" do
        include_context "an authorized user"

        before do
          expect_any_instance_of(BeefCake::Membership).to receive(:save).and_return(true)
          post action, :params => {:beef_cake_membership => {:uid => uid, :role_id => "123", :expires_at => Time.now.to_date }}
        end

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

        it "redirects back to user page" do
          expect(response).to redirect_to(edit_beef_cake_user_path(uid))
        end
      end

      context "failed to save a membership" do
        include_context "an authorized user"

        before do
          expect_any_instance_of(BeefCake::Membership).to receive(:save).and_return(false)
          post action, :params => {:beef_cake_membership => {:uid => uid, :role_id => "123", :expires_at => Time.now.to_date }}
        end

        it "renders new membership page" do
          expect(response).to redirect_to(new_beef_cake_membership_path)
        end
      end

      context "creating a new temporary membership" do
        include_context "an unauthorized user"

        before do
          get action, :params => { :beef_cake_membership => { :uid => uid, :role_id => "123", :expires_at => Time.now.to_date}}
        end

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

    end
    context "create a new membership with invalid user" do
      include_context "an authorized user"
      before do
        allow(BeefCake::User).to receive(:find).with("invalid_user").and_return(nil)
        get action, :params => { :beef_cake_membership => { :uid => "invalid_user", :role_id => "123", }}, format: :json
      end
      it 'returns error if user is nil' do
        expect(response.body).to eq("invalid user invalid_user")
        expect(response.code).to eq("422")
      end
    end
  end

  describe "edit" do
    describe "memberships" do
      let(:action) {:edit}
      let!(:membership) {BeefCake::Membership.new(uid: uid, role_id: 123, id: "12344")}

      context "editing a membership" do
        include_context "an authorized user"

        before do
          expect(BeefCake::Membership).to receive(:find).with(membership.id).and_return(membership)
          expect(membership).to receive(:persisted?).and_return(true)
          get action, :params => {:id => membership.id}
        end

        it_behaves_like 'it returns a success response'
        it "assigns @referrer_page" do
          expect(@controller.view_assigns['back_url']).to eq("/beef_cake/users/#{uid}/edit")
        end
      end

      context "editing a membership" do
        include_context "an unauthorized user"

        before do
          expect(BeefCake::Membership).to receive(:find).with(membership.id).and_return(membership)
          get action, :params => {:id => membership.id}
        end

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

  describe "update" do
    describe "membership" do
      let(:action) { :update }
      let(:membership) {BeefCake::Membership.new(uid: uid, role_id: 123, id: "12344")}
      let(:save_result) { true }

      context 'updating an existing membership' do
        include_context 'an authorized user'

        before do
          expect(BeefCake::Membership).to receive(:find).with(membership.id).and_return(membership)
          expect(membership).to receive(:persisted?).and_return(true)
          expect(membership).to receive(:save).and_return(save_result)

          put action, :params => {:id => membership.id, :beef_cake_membership => {:uid => uid, :role_id => "123"}}
        end
        it_behaves_like 'it redirects the user and displays a success message'
        it "redirects to edit user page" do
          expect(response).to redirect_to(edit_beef_cake_user_path(membership.uid))
        end

        context 'update error' do
          let(:save_result) { false }
          let(:membership) do
            membership = BeefCake::Membership.new(
              uid: uid,
              role_id: 123,
              id: '12344'
            )
            membership.errors.add(:id, message: 'a save error')
            membership
          end

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

      context 'updating an existing membership, save failed' do
        include_context 'an authorized user'

        before do
          expect(BeefCake::Membership).to receive(:find).with(membership.id).and_return(membership)
          expect(membership).to receive(:persisted?).and_return(true)
          expect(membership).to receive(:save).and_return(false)

          put action, :params => {:id => membership.id, :beef_cake_membership => {:uid => uid, :role_id => "123"}}
        end

        it "renders edit membership page" do
          expect(response).to redirect_to(edit_beef_cake_membership_path(membership.id))
        end
      end

      context 'updating an existing membership' do
        include_context 'an unauthorized user'

        before do
          expect(BeefCake::Membership).to receive(:find).with(membership.id).and_return(membership)
          put action, :params => {:id => membership.id, :beef_cake_membership => {:uid => uid, :role_id => "123"}}
        end

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

  describe "destroy" do
    describe "membership" do
      let(:action) { :destroy}
      let!(:membership) {BeefCake::Membership.new(uid: uid, role_id: 123, id: "12344")}

      context 'destroying an existing membership' do
        include_context 'an authorized user'

        before do
          expect(BeefCake::Membership).to receive(:find).with(membership.id).and_return(membership)
          expect(membership).to receive(:persisted?).and_return(true)
          expect(membership).to receive(:destroy).and_return(true)

          delete action, :params => {:id => membership.id}
        end

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

      context 'destroy failed' do
        include_context 'an authorized user'

        before do
          expect(BeefCake::Membership).to receive(:find).with(membership.id).and_return(membership)
          expect(membership).to receive(:persisted?).and_return(true)
          expect(membership).to receive(:destroy).and_return(false)

          delete action, :params => {:id => membership.id}
        end

        it "redirects to home page" do
          expect(response).to redirect_to(root_path)
        end
      end

      context 'destroying an existing membership' do
        include_context 'an unauthorized user'

        before do
          expect(BeefCake::Membership).to receive(:find).with(membership.id).and_return(membership)
          delete action, :params => {:id => membership.id}
        end

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