require "rails_helper"

RSpec.describe ProjectsController, type: :controller do
  render_views

  let(:current_user) { create(:user, :account_manager) }
  let(:user) { current_user }
  let(:account) { user.primary_account }
  let!(:project) { create(:project, name: "My Project", client_name: "My Client", members: current_user, account: current_user.primary_account) }

  before do
    sign_in(current_user)
  end

  describe "#index" do
    let!(:project_one) { create(:project, name: "Avengers", members: current_user, account: current_user.primary_account) }
    let!(:project_two) { create(:project, name: "Justice League", members: [], account: current_user.primary_account) }

    it "responds successfully" do
      get :index

      expect(response).to be_successful
    end

    it "redirects to accountless page if user is accountless" do
      sign_in(create(:user, :accountless))

      get :index

      expect(response).to redirect_to(accountless_user_path)
    end

    context "for an associate" do
      let(:current_user) { create(:user, :associate) }

      it "only shows projects that the user has been invited to" do
        get :index

        expect(response.body).to have_content("Avengers")
        expect(response.body).not_to have_content("Justice League")
      end
    end

    context "for a project manager" do
      let(:current_user) { create(:user, :manager) }

      it "only shows projects that the user has been invited to" do
        get :index

        expect(response.body).to have_content("Avengers")
        expect(response.body).not_to have_content("Justice League")
      end
    end

    context "for an account manager" do
      let(:current_user) { create(:user, :account_manager) }

      it "shows all projects" do
        get :index

        expect(response.body).to have_content("Avengers")
        expect(response.body).to have_content("Justice League")
      end
    end
  end

  describe "#new" do
    it "sets project" do
      get :new
      expect(response).to be_successful
      expect(assigns(:project)).to have_attributes(account: current_user.primary_account)
    end

    it "renders project content" do
      get :index

      expect(response.body).to have_link("Create New Project", href: new_project_path)
      expect(response.body).to have_link("My Project", href: project_path(project))
      expect(response.body).to have_content("My Client")
      expect(response.body).to have_link(href: project_project_memberships_path(project))
    end

    context "when there are no projects" do
      it "renders prompt to create new one" do
        Project.destroy_all

        get :index

        expect(response.body).to have_link("Create Your First Project", href: new_project_path)
      end
    end

    context "for an associate" do
      let(:current_user) { create(:user, :associate) }

      it "renders doesn't prompt to create new one" do
        current_user.project_memberships.delete_all

        get :index

        expect(response.body).to have_content("Click on a project you are invited to and get started.")
        expect(response.body).not_to have_content("Create New Project")
      end
    end
  end

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

      expect(response).to be_successful
    end

    it "renders content" do
      create(:talent_release, project: project)
      create(:appearance_release, project: project)
      create(:location_release, project: project)
      create(:acquired_media_release, project: project)
      create(:material_release, project: project)
      create(:music_release, project: project)

      get :show, params: { id: project }

      expect(response.body).to have_content("My Project")
      expect(response.body).to have_content("My Client")
      expect(response.body).to have_link("Files", href: project_path(project))
      expect(response.body).to have_link("Release", href: project_contract_templates_path(project))
      expect(response.body).to have_link("Edit", href: "#")
      expect(response.body).to have_link("Deliver", href: project_videos_path(project))
      expect(response.body).to have_content("1 Team Member")
      expect(response.body).to have_link("Talent Releases (1)", href: project_talent_releases_path(project))
      expect(response.body).to have_link("Appearance Releases (1)", href: project_appearance_releases_path(project))
      expect(response.body).to have_link("Location Releases (1)", href: project_location_releases_path(project))
      expect(response.body).to have_link("Acquired Media Releases (1)", href: project_acquired_media_releases_path(project))
      expect(response.body).to have_link("Material Releases (1)", href: project_material_releases_path(project))
      expect(response.body).to have_link("Music Releases (1)", href: project_music_releases_path(project))
      expect(response.body).to have_link("Reports", href: project_reports_path(project))
      expect(response.body).to have_link(href: project_project_memberships_path(project))
    end

    context "for associates" do
      let(:current_user) { create(:user, :associate) }
      let!(:project) { create(:project_with_directories, name: "My Project", client_name: "My Client", members: current_user, account: current_user.primary_account) }

      it "only returns directories with 'Everyone' permissons" do
        get :show, params: { id: project }

        expect(response.body).to have_content("Shared")
        expect(response.body).not_to have_content("Financial Documents")
        expect(response.body).not_to have_content("Salaries")
      end

      it "does not show reports folder" do
        get :show, params: { id: project }

        expect(response.body).not_to have_content("Reports")
      end
    end

    context "for project managers" do
      let(:current_user) { create(:user, :manager) }
      let!(:project) { create(:project_with_directories, name: "My Project", client_name: "My Client", members: current_user, account: current_user.primary_account) }

      it "only returns directories with 'Everyone' & 'Account Managers & Project Managers' permissons" do
        get :show, params: { id: project }

        expect(response.body).to have_content("Shared")
        expect(response.body).to have_content("Financial Documents")
        expect(response.body).not_to have_content("Salaries")
      end
    end

    context "for account managers" do
      let(:current_user) { create(:user, :account_manager) }
      let!(:project) { create(:project_with_directories, name: "My Project", client_name: "My Client", account: current_user.primary_account) }

      it "returns all directories" do
        get :show, params: { id: project }

        expect(response.body).to have_content("Shared")
        expect(response.body).to have_content("Financial Documents")
        expect(response.body).to have_content("Salaries")
      end
    end
  end

  describe "#new" do
    it "sets project" do
      get :new

      expect(response).to be_successful
    end
  end

  describe "#create" do
    it "responds with redirect" do
      post :create, params: { project: project_params }

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

    it "creates a new record" do
      expect {
        post :create, params: { project: project_params }
      }.to change(Project, :count).by(1)
    end

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

    context "with invalid data" do
      before do
        allow_any_instance_of(Project).to receive(:save).and_return(false)
      end

      it "shows the video analysis status and button" do
        project = create(:project, account: current_user.primary_account, videos: create_list(:video, 1))

        expect(response).to be_successful
      end

      it "does not create a new record" do
        expect {
          post :create, params: { project: project_params }
        }.not_to change(Project, :count)
      end
    end

    context "for associates" do
      let(:current_user) { create(:user, :associate) }

      it "raises exception" do
        expect {
          post :create, params: { project: project_params }
        }.to raise_error(Pundit::NotAuthorizedError)
      end
    end
  end

  describe "#edit" do
    it "sets project, available_release_types" do
      get :edit, params: { id: project }

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

  describe "#update" do
    it "responds with redirect" do
      patch :update, params: { id: project, project: project_params }

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

    context "for associates" do
      let(:current_user) { create(:user, :associate) }

      it "raises exception" do
        expect {
          patch :update, params: { id: project, project: project_params }
        }.to raise_error(Pundit::NotAuthorizedError)
      end
    end
  end

  describe "#destroy" do
    it "responds with redirect" do
      skip "This functionality is no longer available"

      delete :destroy, params: { id: project }

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

    it "destroys the record" do
      skip "This functionality is no longer available"

      expect {
        delete :destroy, params: { id: project }
      }.to change(Project, :count).by(-1)
    end

    context "for associates" do
      let(:current_user) { create(:user, :associate) }

      it "raises exception" do
        expect {
          delete :destroy, params: { id: project }
        }.to raise_error(Pundit::NotAuthorizedError)
      end
    end
  end

  private

  def project_params
    attributes_for(:project)
  end
end
