require "rails_helper"

RSpec.describe Admin::UsersController, type: :controller do
  render_views

  let!(:current_user) { create(:user, :admin) }

  before do
    sign_in(current_user)
  end

  describe "#index" do
    it "returns a successful response" do
      get :index

      expect(response).to be_successful
    end

    describe "for xhr request" do
      before do
        users = [
            create(:user, :with_name),
            create(:user, :with_different_name)
        ]
      end

      it "shows all users if search field is empty" do
        get :index, xhr: true
        expect(response.body).to have_content("John")
        expect(response.body).to have_content("Specimen")
      end

      it "shows only users with first name, last name or email matching search query" do
        get :index, params: { query: "John" }, xhr: true
        expect(response.body).to have_content("John")
        expect(response.body).not_to have_content("Specimen")

        get :index, params: { query: "Simpson" }, xhr: true
        expect(response.body).not_to have_content("John")
        expect(response.body).to have_content("Specimen")

        get :index, params: { query: "different@" }, xhr: true
        expect(response.body).not_to have_content("John")
        expect(response.body).to have_content("Specimen")
      end
    end
  end

  describe "#new" do
    it "returns a successful response" do
      get :new

      expect(response).to be_successful
    end

    it "assigns user, accounts" do
      get :new

      expect(assigns(:user)).not_to be_nil
      expect(assigns(:accounts)).to eq Account.all
    end
  end

  describe "#create" do
    it "responds with a redirect" do
      post :create, params: { user: user_create_params }

      expect(response).to be_redirect
      expect(response).to redirect_to [:admin, :users]
    end

    it "sets a flash notice" do
      post :create, params: { user: user_create_params }

      expect(flash.notice).to eq "The user was created"
    end

    it "creates a new User record" do
      expect {
        post :create, params: { user: user_create_params }
      }.to change(User, :count).by(1)

      expect(assigns(:user)).to have_attributes(
        email: "bob@example.com",
        admin: false,
      )
    end

    it "sends a welcome email" do
      assert_enqueued_emails 1 do
        post :create, params: { user: user_create_params }
      end
    end

    context "when record cannot be saved" do
      before do
        allow_any_instance_of(User).to receive(:valid?).and_return(false)
      end

      it "re-displays the form" do
        post :create, params: { user: user_create_params }

        expect(response).to be_successful
        expect(flash.notice).to be_nil
      end

      it "does not create a new User record" do
        expect {
          post :create, params: { user: user_create_params }
        }.not_to change(User, :count)
      end

      it "assigns accounts" do
        post :create, params: { user: user_create_params }

        expect(assigns(:accounts)).to eq Account.all
      end
    end
  end

  describe "#edit" do
    let(:user) { create(:user) }

    it "returns a successful response" do
      get :edit, params: { id: user }

      expect(response).to be_successful
    end

    it "assigns user, accounts" do
      get :edit, params: { id: user }

      expect(assigns(:user)).to eq user
      expect(assigns(:accounts)).to eq Account.all
    end
  end

  describe "#update" do
    let(:user) { create(:user) }

    it "redirects to users page" do
      patch :update, params: { id: user, user: user_update_params }

      expect(response).to be_redirect
      expect(response).to redirect_to admin_users_path
    end

    it "sets a flash notice" do
      patch :update, params: { id: user, user: user_update_params }

      expect(flash.notice).to eq "The user was updated"
    end

    it "updates the user record" do
      patch :update, params: { id: user, user: { email: "new-email@example.com" } }

      expect(assigns(:user)).to have_attributes(
                                    email: "new-email@example.com",
                                    admin: false,
                                    )
    end

    it "updates user's password" do
      patch :update, params: { id: user, user: { email: "new-email@example.com", password: "New Pass" } }

      expect(user.reload.password_digest).to eq("New Pass")
    end

    context "when record cannot be saved" do
      before do
        allow_any_instance_of(User).to receive(:update).and_return(false)
      end

      it "re-displays the form" do
        patch :update, params: { id: user, user: user_update_params }

        expect(response).to be_successful
        expect(flash.notice).to be_nil
      end

      it "assigns accounts" do
        patch :update, params: { id: user, user: user_update_params }

        expect(assigns(:accounts)).to eq Account.all
      end
    end
  end

  describe "#destroy" do
    let!(:user) { create(:user, accounts: current_user.accounts) }
    let(:note_author_user) { create(:user, accounts: current_user.accounts) }

    it "deletes user" do
      expect {
        delete :destroy, params: { id: user }
      }.to change(User, :count).by(-1)
    end

    it "redirects to account edit page" do
      delete :destroy, params: { id: user }

      expect(response).to redirect_to admin_users_path
    end

    it "deletes user who posted notes" do
      note = create(:note, user: note_author_user, email: note_author_user.email)

      expect {
        delete :destroy, params: { id: note_author_user }
      }.to change(User, :count).by(-1)
      expect(response).to redirect_to admin_users_path
      expect(Note.find(note.id).email).to eq note.email
    end
  end

  private

  def user_create_params
    {
      email: "bob@example.com",
      password: "password",
      account_id: current_user.primary_account.id,
      admin: false,
      role: "account_manager",
    }
  end

  def user_update_params
    {
      email: "bob@example.com",
    }
  end
end
