require 'rails_helper'

RSpec.describe DirectoriesController, type: :controller do
  render_views

  let(:user) { create(:user) }
  let(:account) { user.primary_account }
  let(:project) { create(:project, account: user.primary_account) }
  let(:directory) { create(:directory, project: project) }
  let(:directory_with_files) { create(:directory, :with_files, project: project) }
  let(:directory_with_many_files) { create(:directory, :many_files, project: project) }

  before do
    sign_in user
  end

  describe "#new" do
    it "responds successfully" do
      get :new, params: { project_id: project }

      expect(response).to be_successful
      expect(assigns(:directory)).to be_a_new(Directory)
      expect(response).to render_template(:new)
    end
  end

  describe "#create" do
    it "responds with a redirect" do
      post :create, params: { project_id: project.id, directory: directory_params }

      expect(response).to be_redirect
      expect(flash.notice).not_to be_nil
    end

    it "does create a new record" do
      expect {
        post :create, params: { project_id: project.id, directory: directory_params }
      }.to change(Directory, :count)
    end

    it "logs an event" do
      expect {
        post :create, params: { project_id: project.id, directory: directory_params }
      }.to have_enqueued_job(TrackAnalyticsJob).with(user,  account, :track_create_custom_folder, user_agent: "Rails Testing", user_ip: "0.0.0.0")
    end

    context "with invalid data" do
      it "does not create a new record" do
        expect {
          post :create, params: { project_id: project.id, directory: { name: "", category: "Other" } }
        }.not_to change(Directory, :count)
      end
    end

    context "with permissions" do
      it "assigns selected permission to directory" do
        post :create, params: { project_id: project.id, directory: directory_params_with_permissions }
  
        expect(Directory.last.permissions).to eq("Account Managers & Project Managers")
      end

      it "sets permissions to everyone when no permission is selected by user" do
        post :create, params: { project_id: project.id, directory: directory_params }
  
        expect(Directory.last.permissions).to eq("Everyone")
      end
    end
  end

  describe "#show" do
    it "responds successfully" do
      get :show, params: { project_id: project.id, id: directory_with_files.id }

      expect(response).to be_successful
    end

    it "renders files" do
      get :show, params: { project_id: project.id, id: directory_with_files.id }

      expect(response.body).to have_content "location_photo.png"
      expect(response.body).to have_link "Add File"
      expect(response.body).to have_content "Manage"
    end

    context "when there are no files" do
      it "renders an empty message" do
        get :show, params: { project_id: project.id, id: directory.id }

        expect(response.body).to have_content("Uploaded files will appear here")
      end
    end

    context "when there are many files" do
      it "paginates the table" do
        get :show, params: { project_id: project.id, id: directory_with_many_files.id }

        expect(response.body).to have_link("2", href: project_directory_path(project, directory_with_many_files.id, page: 2))
      end
    end

    context "for xhr request" do
      it "filters the files by a query param" do
        get :show, params: { project_id: project.id, id: directory_with_many_files.id, query: "loc" }, xhr: true

        expect(response.body).to have_content("location_photo.png")
        expect(response.body).not_to have_content("material_photo.png")
        expect(response.body).not_to have_content("person_photo.png")
      end
    end
  end

  describe "#edit" do
    it "sets directory" do
      get :edit, params: { project_id: project.id, id: directory.id }

      expect(response).to be_successful
      expect(assigns(:directory)).to eq directory
    end
  end

  describe "#update" do
    it "responds with redirect" do
      patch :update, params: { project_id: project.id, id: directory.id, directory: directory_params }

      expect(response).to be_redirect
      expect(flash.notice).not_to be_nil
    end

    it "updates directory with files and redirects" do
      patch :update, params: { project_id: project.id, id: directory.id, directory: directory_params_with_files }

      expect(directory.files.count).to eq(2)
      expect(directory.files.first.filename).to eq("location_photo.png")
      expect(response).to be_redirect
      expect(flash.notice).not_to be_nil
    end

    context "with permissions" do
      let(:directory) { create(:directory, project: project) }

      it "updates directory with permissions" do
        expect {
          patch :update, params: { project_id: project.id, id: directory.id, directory: directory_params_with_permissions }
          directory.reload
        }.to change(directory, :permissions).from("Everyone").to("Account Managers & Project Managers")
      end
    end
  end

  describe "#destroy_file" do
    it "responds with redirect after deleting file" do
      delete :destroy_file, params: { project_id: project.id, id: directory_with_files.id, file_id: directory_with_files.files.first.id }
      
      expect(directory_with_files.files.count).to eq(0)
      expect(response).to be_redirect
      expect(response).to redirect_to(project_directory_path(project, directory_with_files))
      expect(flash.alert).not_to be_nil
    end
  end

  describe "#destroy" do
    let!(:directory_2) { create(:directory, project: project, name: "Stories") }
    
    it "responds with redirect" do
      delete :destroy, params: { project_id: project.id, id: directory.id }

      expect(response).to be_redirect
      expect(response).to redirect_to(project_path(project))
      expect(flash.alert).not_to be_nil
    end

    it "destroys the record" do
      expect {
        delete :destroy, params: { project_id: project.id, id: directory_2.id }
      }.to change(Directory, :count).by(-1)
    end
  end

  private

  def directory_params
    attributes_for(:directory)
  end

  def directory_params_with_files
    files = 2.times.map { Rack::Test::UploadedFile.new(file_fixture("location_photo.png"), "image/png") }

    directory_params.merge({ files: files })
  end

  def directory_params_with_permissions
    directory_params.merge({ permissions: "Account Managers & Project Managers" })
  end
end
