require "rails_helper"

RSpec.describe "UserDestroy" do
  let(:user) { create(:user) }

  describe "GET /settings/account" do
    it "offers to delete account when user has an email" do
      sign_in user
      get "/settings/account"
      expect(response.body).to include("Delete Account").and include("Deleting your account will")
    end

    it "offers to set an email when user doesn't have an email" do
      shallow_user = create(:user, email: nil)
      sign_in shallow_user
      get "/settings/account"
      expect(response.body).not_to include("Deleting your account will")
      expect(response.body).to include("provide an email")
    end
  end

  describe "DELETE /users/full_delete" do
    context "when user has an email" do
      before do
        sign_in user
      end

      it "schedules a user delete job" do
        sidekiq_assert_enqueued_with(job: Users::DeleteWorker) do
          delete "/users/full_delete"
        end
      end

      it "signs out" do
        delete "/users/full_delete"
        expect(controller.current_user).to be_nil
      end

      it "redirects to sign up" do
        delete "/users/full_delete"
        expect(response).to redirect_to new_user_registration_path
        expect(flash[:global_notice]).to include("Your account deletion is scheduled")
      end
    end

    context "when user doesn't have an email" do
      let!(:shallow_user) { create(:user, email: nil) }

      before do
        sign_in shallow_user
      end

      it "redirects to account page" do
        delete "/users/full_delete"
        expect(response).to redirect_to("/settings/account")
        expect(flash[:settings_notice]).to include("provide an email")
      end
    end
  end

  describe "POST /users/request_destroy" do
    let(:mailer_class) { NotifyMailer }
    let(:mailer) { double }
    let(:message_delivery) { double }

    context "when user has an email" do
      before do
        sign_in user
      end

      it "sends an email" do
        allow(mailer_class).to receive(:with).and_return(mailer)
        allow(mailer).to receive(:account_deletion_requested_email).and_return(message_delivery)
        allow(message_delivery).to receive(:deliver_now)

        post user_request_destroy_path

        expect(mailer_class).to have_received(:with).with(user: user, token: instance_of(String))
        expect(mailer).to have_received(:account_deletion_requested_email)
        expect(message_delivery).to have_received(:deliver_now)
      end

      it "updates the destroy_token in cache" do
        allow(Rails.cache).to receive(:write).and_call_original

        post user_request_destroy_path

        user.reload
        expect(Rails.cache).to have_received(:write).with("user-destroy-token-#{user.id}", any_args)
      end

      it "sets flash notice" do
        post user_request_destroy_path

        expect(flash[:settings_notice]).to include("You have requested account deletion")
      end
    end

    context "when user doesn't have an email" do
      let!(:shallow_user) { create(:user, email: nil) }

      before do
        sign_in shallow_user
      end

      it "redirects to account page" do
        post user_request_destroy_path

        expect(response).to redirect_to("/settings/account")
        expect(flash[:settings_notice]).to include("provide an email")
      end
    end

    it "does not send an email if already requested" do
      allow(Rails.cache).to receive(:exist?).with("user-destroy-token-#{user.id}").and_return(true)
      allow(mailer_class).to receive(:with).and_return(mailer)
      allow(mailer).to receive(:account_deletion_requested_email).and_return(message_delivery)
      allow(message_delivery).to receive(:deliver_now)

      sign_in user
      post user_request_destroy_path

      expect(mailer).not_to have_received(:account_deletion_requested_email)
      expect(flash[:settings_notice]).to include("You have already requested")
    end
  end

  describe "GET /users/confirm_destroy" do
    let(:token) { SecureRandom.hex(10) }

    context "with user signed in" do
      before do
        sign_in user
      end

      it "displays a flash message if user doesn't have a destroy_token" do
        get user_confirm_destroy_path(token: token)
        expect(flash[:settings_notice]).to include("Your token has expired,")
      end

      it "renders not_found if destroy_token != token" do
        allow(Rails.cache).to receive(:read).and_return(SecureRandom.hex(8))
        expect do
          get user_confirm_destroy_path(token: token)
        end.to raise_error(ActionController::RoutingError)
      end

      it "renders template if destroy_token is correct" do
        allow(Rails.cache).to receive(:read).and_return(token)
        get user_confirm_destroy_path(token: token)
        expect(response).to have_http_status(:ok)
      end
    end

    context "without a user" do
      it "displays a flash message" do
        get user_confirm_destroy_path(token: token)
        expect(flash[:alert]).to include("You must be logged in")
      end
    end
  end
end
