require "rails_helper"

RSpec.describe MusicReleasesController, type: :controller do
  render_views

  let(:user) { create(:user) }
  let(:account) { user.primary_account }
  let(:project) { create(:project, account: user.primary_account) }

  before :each do
    sign_in user
  end

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

      expect(response).to be_successful
    end

    it "renders content" do
      release = create(:music_release, project: project, name: "My Release")
      create(:note, notable: release, content: "Some notes here")

      get :index, params: { project_id: project }

      expect(response.body).to have_content "My Release"
      expect(response.body).to have_content "0"
      expect(response.body).to have_content "1"
      expect(response.body).to have_content "1"
      expect(response.body).to have_content "Some notes here"
      expect(response.body).to have_link "Import Release"
      expect(response.body).to have_content "Manage"
    end

    context "when there are no music releases" do
      it "renders an empty message" do
        get :index, params: { project_id: project }

        expect(response.body).to have_content("Music Releases will appear here")
      end
    end

    context "when there are many records" do
      it "paginates the table" do
        create_list(:music_release, 20, project: project)

        get :index, params: { project_id: project }

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

    context "for xhr request" do
      it "filters the releases by a query param" do
        music_releases = [
          create(:music_release, name: "Extreme Music Collection", project: project),
          create(:music_release, name: "Audio Networks Music Collection", project: project),
        ]

        get :index, params: { project_id: project, query: "Audio" }, xhr: true

        expect(response.body).not_to have_content("Extreme")
        expect(response.body).to have_content("Audio")
      end
    end
  end

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

      expect(response).to be_successful
    end

    it "initializes with 5 composers and 2 publishers" do
      get :new, params: { project_id: project }

      expect(assigns(:music_release).composers.size).to eq 5
      expect(assigns(:music_release).publishers.size).to eq 2
    end
  end

  describe "#create" do
    it "responds successfully" do
      expect {
        post :create, params: { project_id: project, music_release: music_release_params }
      }.to change(MusicRelease, :count).by(1)

      expect(response).to be_redirect
      expect(response).to redirect_to [project, :music_releases]
      expect(flash.notice).to be_present
    end

    it "creates nested file info records" do
      expect {
        post :create, params: {
          project_id: project,
          music_release: music_release_params.merge(
            file_infos_attributes: {
              0 => attributes_for(:file_info)
            }
          )
        }
      }.to change(FileInfo, :count).by(1)
      expect(MusicRelease.last.file_infos.size).to eq(1)
    end

    it "creates nested composer records" do
      expect {
        post :create, params: {
          project_id: project,
          music_release: music_release_params.merge(
            composers_attributes: {
              0 => {
                name: "name",
                affiliation: "affiliation",
                percentage: 100,
                cae_number: "cae123456789",
              },
            }
          )
        }
      }.to change(Composer, :count).by(1)
      expect(MusicRelease.last.composers.size).to eq(1)
    end

    it "creates nested publisher records" do
      expect {
        post :create, params: {
          project_id: project,
          music_release: music_release_params.merge(
            publishers_attributes: {
              0 => attributes_for(:publisher),
            }
          )
        }
      }.to change(Publisher, :count).by(1)
      expect(MusicRelease.last.publishers.size).to eq(1)
    end

    it "enqueues tagging job" do
      expect {
        post :create, params: { project_id: project, music_release: music_release_params }
      }.to have_enqueued_job(SetTagsForReleasableJob).with(MusicRelease.last)
    end

    it "logs analytics" do
      expect {
        post :create, params: { project_id: project, music_release: music_release_params }
      }.to(
        have_enqueued_job(TrackAnalyticsJob).with(user, account, :track_create_non_native_release, release_type: "MusicRelease", user_agent: "Rails Testing", user_ip: "0.0.0.0")
      )
    end

    context "when the record would be invalid" do
      before :each do
        allow_any_instance_of(MusicRelease).to receive(:save).and_return(false)
      end

      it "re-renders the form" do
        post :create, params: {
          project_id: project,
          music_release: music_release_params.merge(
            publishers_attributes: {
              0 => attributes_for(:publisher),
            }
          )
        }

        expect(response).to render_template :new
        expect(flash.notice).to be_nil
      end

      it "does not enqueue any jobs" do
        expect {
          post :create, params: { project_id: project, music_release: music_release_params }
        }.not_to have_enqueued_job
      end

      it "initializes with 5 composers and 2 publishers" do
        post :create, params: {
          project_id: project,
          music_release: music_release_params.merge(
            publishers_attributes: {
              0 => attributes_for(:publisher),
            }
          )
        }

        expect(assigns(:music_release).composers.size).to eq 5
        expect(assigns(:music_release).publishers.size).to eq 2
      end
    end
  end

  describe "#edit" do
    let(:music_release) { create(:music_release, project: project) }

    it "responds successfully" do
      get :edit, params: { id: music_release }

      expect(response).to be_successful
    end

    it "initializes with 5 composers and 2 publishers" do
      get :edit, params: { id: music_release }

      expect(assigns(:music_release).composers.size).to eq 5
      expect(assigns(:music_release).publishers.size).to eq 2
    end
  end

  describe "#update" do
    let(:music_release) { create(:music_release, project: project) }

    it "responds successfully" do
      put :update, params: { id: music_release, music_release: { name: "Updated name" } }

      expect(response).to redirect_to [project, :music_releases]
      expect(flash.notice).to eq "The music release has been updated"
      expect(music_release.reload.name).to eq "Updated name"
    end

    context "when the record would be invalid" do
      before :each do
        allow_any_instance_of(MusicRelease).to receive(:update).and_return(false)
      end

      it "re-renders the form" do
        put :update, params: { id: music_release, music_release: music_release_params }

        expect(response).to render_template :edit
        expect(flash.notice).to be_nil
      end
    end
  end

  describe "#destroy" do
    let!(:music_release) { create(:music_release, project: project) }

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

    it "redirects to project and sets alert" do
      delete :destroy, params: { id: music_release }

      expect(response).to redirect_to [project, :music_releases]
      expect(flash.alert).to eq "The music release has been deleted"
    end
  end

  private

  def music_release_params
    attributes_for(:music_release).merge(
      composers_attributes: [attributes_for(:composer)],
      publishers_attributes: [attributes_for(:publisher)],
    ).merge(exploitable_rights_params)
  end

  def exploitable_rights_params
    {
      applicable_medium_id: ApplicableMedium.last.id,
      applicable_medium_text: "applicable_media",
      territory_id: Territory.last.id,
      territory_text: "territory",
      term_id: Term.last.id,
      term_text: "term",
      restriction_id: Restriction.last.id,
      restriction_text: "restrictions",
    }
 end
end
