#  Copyright (c) 2012-2017, Jungwacht Blauring Schweiz. This file is part of
#  hitobito and licensed under the Affero General Public License version 3
#  or later. See the COPYING file at the top-level directory or at
#  https://github.com/hitobito/hitobito.

require "spec_helper"

describe Event::ApplicationMarketController do
  let(:event) { Fabricate(:course) }

  let(:group) { event.groups.first }

  let(:appl_prio_1) do
    Fabricate(:event_participation,
      event: event,
      application: Fabricate(:event_application, priority_1: event))
  end

  let(:appl_prio_2) do
    Fabricate(:event_participation,
      application: Fabricate(:event_application, priority_2: event))
  end

  let(:appl_prio_3) do
    Fabricate(:event_participation,
      application: Fabricate(:event_application, priority_3: event))
  end

  let(:appl_waiting) do
    Fabricate(:event_participation,
      application: Fabricate(:event_application, waiting_list: true),
      event: Fabricate(:course, kind: event.kind))
  end

  let(:appl_other) do
    Fabricate(:event_participation,
      application: Fabricate(:event_application))
  end
  let(:appl_other_assigned) do
    participation = Fabricate(:event_participation, active: true)
    Fabricate(Event::Course::Role::Participant.name.to_sym, participation: participation)
    Fabricate(:event_application, priority_2: event, participation: participation)
    participation.reload
  end

  let(:appl_participant) do
    participation = Fabricate(:event_participation, event: event, active: true)
    Fabricate(Event::Course::Role::Participant.name.to_sym, participation: participation)
    Fabricate(:event_application, participation: participation, priority_2: event)
    participation.reload
  end

  let(:leader) do
    participation = Fabricate(:event_participation, event: event)
    Fabricate(Event::Role::Leader.name.to_sym, participation: participation)
  end

  before do
    # init required data
    appl_prio_1
    appl_prio_2
    appl_prio_3
    appl_waiting
    appl_other
    appl_other_assigned
    appl_participant
    leader
  end

  describe "requests are mutually undoable", js: true do
    context "waiting_list" do
      it "starting from application", unstable: true do
        obsolete_node_safe do
          sign_in
          visit group_event_application_market_index_path(group.id, event.id)

          participants = find("#participants").text
          applications = find("#applications").text

          appl_id = "event_participation_#{appl_prio_1.id}"
          expect(all("#applications ##{appl_id} td").last).to have_selector(".fa-minus")

          find("#applications ##{appl_id} td div a", text: "Warteliste").click
          fill_in("event_application_waiting_list_comment", with: "only if possible")
          find("button.btn-primary", text: "Anmeldung aktualisieren").click
          skip("cannot find icon .fa-ok")
          expect(all("#applications ##{appl_id} td").last).to have_selector(".fa-ok")
          expect(all("#applications ##{appl_id} td").last).to have_selector(".fa-comment")

          find("#applications ##{appl_id} td div a", text: "Warteliste").click
          expect(all("#applications ##{appl_id} td").last).to have_selector(".fa-minus")
          expect(all("#applications ##{appl_id} td").last).to have_no_selector(".fa-comment")

          visit group_event_application_market_index_path(group.id, event.id)

          expect(find("#participants").text).to eq(participants)
          expect(find("#applications").text).to eq(applications)
        end
      end

      it "starting from application on waiting list" do
        obsolete_node_safe do
          sign_in
          visit group_event_application_market_index_path(group.id, event.id)

          find("#waiting_list").set(true)
          click_button("Aktualisieren")

          participants = find("#participants").text
          applications = find("#applications").text

          appl_id = "event_participation_#{appl_waiting.id}"
          skip("cannot find icon .fa-ok")
          expect(all("#applications ##{appl_id} td").last).to have_selector(".fa-ok")

          find("#applications ##{appl_id} td div a", text: "Warteliste").click

          expect(all("#applications ##{appl_id} td").last).to have_selector(".fa-minus")

          find("#applications ##{appl_id} td div a", text: "Warteliste").click
          find("#applications ##{appl_id} button.btn-primary").click
          expect(all("#applications ##{appl_id} td").last).to have_selector(".fa-ok")
          expect(all("#applications ##{appl_id} td").last).to have_no_selector(".fa-comment")

          visit group_event_application_market_index_path(group.id, event.id, "prio[]" => 1, :waiting_list => true)

          expect(find("#participants").text).to eq(participants)
          expect(find("#applications").text).to eq(applications)
        end
      end
    end

    context "participant" do
      it "starting from application" do
        obsolete_node_safe do
          sign_in
          visit group_event_application_market_index_path(group.id, event.id)

          participants = find("#participants").text
          applications = find("#applications").text

          appl_id = "event_participation_#{appl_prio_1.id}"
          appl_text = appl_prio_1.decorate.to_s(:list)

          all("#applications ##{appl_id} td").first.find("a").click

          expect do
            expect(page).to have_text "Bestätigen ohne E-Mail"
            click_on "Bestätigen ohne E-Mail"
            sleep(0.5)
            click_on "Abbrechen"
            expect(page).to have_no_text "Bestätigen ohne E-Mail"
          end.not_to change { Delayed::Job.where("handler LIKE '%Event::ParticipationConfirmationJob%'").count }

          expect(page).to have_no_selector("#applications ##{appl_id}")

          # first do find().should have_content to make capybara wait for animation, then all().last
          expect(find("#participants")).to have_content(appl_prio_1.person.to_s(:list))
          expect(all("#participants tr").last).to have_content(appl_prio_1.person.to_s(:list))

          expect(page).to have_selector("#participants ##{appl_id}")
          expect(page).to have_css("#participants", text: appl_text)

          all("#participants ##{appl_id} td").last.find("a").click

          expect do
            expect(page).to have_text "Bestätigen und E-Mail senden"
            click_on "Bestätigen und E-Mail senden"
            sleep(0.5)
            click_on "Abbrechen"
            expect(page).to have_no_text "Bestätigen und E-Mail senden"
          end.to change { Delayed::Job.where("handler LIKE '%Event::ParticipationConfirmationJob%'").count }.by(1)

          expect(page).to have_css("#applications", text: appl_text)
          expect(page).to have_no_selector("#participants ##{appl_id}")

          # first do find().should have_content to make capybara wait for animation, then all().last
          expect(find("#applications")).to have_content(appl_prio_1.person.to_s(:list))
          expect(all("#applications tr").last).to have_content(appl_prio_1.person.to_s(:list))

          visit group_event_application_market_index_path(group.id, event.id)

          expect(find("#participants").text).to eq(participants)
          expect(find("#applications").text).to eq(applications)
        end
      end

      it "starting from application on waiting list" do
        obsolete_node_safe do
          sign_in
          visit group_event_application_market_index_path(group.id, event.id)

          find("#waiting_list").set(true)
          click_button("Aktualisieren")
          expect(page).to have_css("#applications tr", count: 2)

          participants = find("#participants").text
          applications = find("#applications").text

          appl_id = "event_participation_#{appl_waiting.id}"

          all("#applications ##{appl_id} td").first.find("a").click

          expect do
            expect(page).to have_text "Bestätigen ohne E-Mail"
            click_on "Bestätigen ohne E-Mail"
            sleep(0.5)
            click_on "Abbrechen"
            expect(page).to have_no_text "Bestätigen ohne E-Mail"
          end.not_to change { Delayed::Job.where("handler LIKE '%Event::ParticipationConfirmationJob%'").count }

          # first do find().should have_content to make capybara wait for animation, then all().last
          expect(find("#participants")).to have_content(appl_waiting.person.to_s(:list))
          expect(all("#participants tr").last).to have_content(appl_waiting.person.to_s(:list))
          expect(page).to have_no_selector("#applications ##{appl_id}")

          all("#participants ##{appl_id} td").last.find("a").click

          expect do
            expect(page).to have_text "Bestätigen und E-Mail senden"
            click_on "Bestätigen und E-Mail senden"
            sleep(0.5)
            click_on "Abbrechen"
            expect(page).to have_no_text "Bestätigen und E-Mail senden"
          end.to change { Delayed::Job.where("handler LIKE '%Event::ParticipationConfirmationJob%'").count }.by(1)

          expect(page).to have_no_selector("#participants ##{appl_id}")

          # first do find().should have_content to make capybara wait for animation, then all().last
          expect(find("#applications")).to have_content(appl_waiting.person.to_s(:list))
          expect(all("#applications tr").last).to have_content(appl_waiting.person.to_s(:list))
          expect(all("#applications tr").last).to have_selector(".fa-minus")

          visit group_event_application_market_index_path(group.id, event.id, "prio[]" => 1, :waiting_list => true)

          # once assigned, a participant is removed from the waiting list
          expect(page).to have_no_selector("#applications ##{appl_id}")

          expect(find("#participants").text).to eq(participants)
          expect(find("#applications").text).not_to eq(applications)
        end
      end

      it "starting from participant" do
        obsolete_node_safe do
          sign_in
          visit group_event_application_market_index_path(group.id, event.id)

          participants = find("#participants").text
          applications = find("#applications").text

          appl_id = "event_participation_#{appl_participant.id}"

          all("#participants ##{appl_id} td").last.find("a").click

          expect do
            expect(page).to have_text "Bestätigen und E-Mail senden"
            click_on "Bestätigen und E-Mail senden"
            sleep(0.5)
            click_on "Abbrechen"
            expect(page).to have_no_text "Bestätigen und E-Mail senden"
          end.to change { Delayed::Job.where("handler LIKE '%Event::ParticipationConfirmationJob%'").count }.by(1)

          expect(page).to have_no_selector("#participants ##{appl_id}")

          # first do find().should have_content to make capybara wait for animation, then all().last
          expect(find("#applications")).to have_content(appl_participant.person.to_s(:list))
          expect(all("#applications tr").last).to have_content(appl_participant.person.to_s(:list))
          all("#applications ##{appl_id} td").first.find("a").click

          expect do
            expect(page).to have_text "Bestätigen ohne E-Mail"
            click_on "Bestätigen ohne E-Mail"
            sleep(0.5)
            click_on "Abbrechen"
            expect(page).to have_no_text "Bestätigen ohne E-Mail"
          end.not_to change { Delayed::Job.where("handler LIKE '%Event::ParticipationConfirmationJob%'").count }

          # first do find().should have_content to make capybara wait for animation, then all().last
          expect(find("#participants tr")).to have_content(appl_participant.person.to_s(:list))
          expect(all("#participants tr").last).to have_content(appl_participant.person.to_s(:list))
          expect(page).to have_no_selector("#applications ##{appl_id}")

          visit group_event_application_market_index_path(group.id, event.id)

          expect(find("#participants").text).to eq(participants)
          expect(find("#applications").text).to eq(applications)
        end
      end

      it "displays custom error alert when person from national waiting list did not accept J&S data sharing" do
        event.update!(maximum_participants: 1)
        sign_in
        visit group_event_application_market_index_path(group_id: group.id, event_id: event.id)
        click_button("Aktualisieren")
        expect(page).to have_text(appl_prio_1.person.first_name)
        find(".fa-arrow-left").click
        expect(page).to have_text "Bestätigen ohne E-Mail"
        click_on "Bestätigen ohne E-Mail"
        sleep(3)
        alert_text = page.driver.browser.switch_to.alert.text
        expect(alert_text).to include(
          # rubocop:todo Layout/LineLength
          "Die maximal erlaubte Teilnehmerzahl ist erreicht. Um weitere Anmeldungen zu bestätigen, muss die maximale Teilnehmerzahl erhöht werden."
          # rubocop:enable Layout/LineLength
        )
      end
    end
  end

  describe "popovers", js: true do
    it "opening one closes the others" do
      sign_in
      visit group_event_application_market_index_path(group.id, event.id)

      check("Prio 1")
      check("Prio 2")
      check("Prio 3")
      click_button("Aktualisieren")

      appl1_id = "event_participation_#{appl_prio_1.id}"
      expect(page).to have_selector("#applications ##{appl1_id} td .fa-minus")

      appl2_id = "event_participation_#{appl_prio_2.id}"
      expect(page).to have_selector("#applications ##{appl2_id} td .fa-minus")

      find("#applications ##{appl2_id} td div a", text: "Warteliste").click
      sleep(2)
      expect(body).to have_selector(".popover[role='tooltip']", count: 1)

      find("#applications ##{appl1_id} td div a", text: "Warteliste").click
      sleep(2)
      expect(body).to have_selector(".popover[role='tooltip']", count: 1)
    end

    it "may be closed with cancel link" do
      sign_in
      visit group_event_application_market_index_path(group.id, event.id)
      sleep 0.1 # wait for popover to be setup

      appl1_id = "event_participation_#{appl_prio_1.id}"
      expect(page).to have_selector("#applications ##{appl1_id} td .fa-minus")

      find("#applications ##{appl1_id} td div a", text: "Warteliste").click
      expect(page).to have_selector(".popover")

      find(".popover .cancel", text: "Abbrechen").click
      expect(page).to have_no_selector(".popover")
    end
  end
end
