require "rails_helper"

RSpec.describe "Filters", type: :system do
  describe "Boolean filter without default" do
    let!(:featured_post) { create :post, name: "Featured post", is_featured: true, published_at: nil }
    let!(:unfeatured_post) { create :post, name: "Unfeatured post", is_featured: false, published_at: nil }

    let(:url) { "/admin/resources/posts?view_type=table" }

    it "displays the filter" do
      visit url
      open_filters_menu

      expect(page).to have_text "Featured status"
      expect(page).to have_unchecked_field "Featured"
      expect(page).to have_unchecked_field "Unfeatured"
      expect(page).to have_text "Featured post"
      expect(page).to have_text "Unfeatured post"
      expect(page).to have_button("Reset filters", disabled: true)
    end

    it "changes the query" do
      visit url
      open_filters_menu

      check "Featured"
      wait_for_loaded
      open_filters_menu

      expect(page).to have_text "Featured post"
      expect(page).not_to have_text "Unfeatured post"
      expect(page).to have_checked_field "Featured"
      expect(page).to have_unchecked_field "Unfeatured"
      expect(current_url).to include "encoded_filters="
      expect(page).to have_link("Reset filters")
    end

    it "changes the query back also with reset" do
      visit url
      open_filters_menu

      check "Featured"
      wait_for_loaded
      open_filters_menu

      expect(page).to have_text "Featured post"
      expect(page).not_to have_text "Unfeatured post"
      expect(current_url).to include "encoded_filters="
      expect(page).to have_link("Reset filters")

      uncheck "Featured"
      wait_for_loaded
      open_filters_menu

      expect(page).to have_text "Featured post"
      expect(page).to have_text "Unfeatured post"
      expect(page).to have_unchecked_field "Featured"
      expect(page).to have_unchecked_field "Unfeatured"
      expect(page).to have_link("Reset filters")

      check "Featured"
      wait_for_loaded
      open_filters_menu
      check "Unfeatured"
      wait_for_loaded
      open_filters_menu

      expect(page).to have_text "Featured post"
      expect(page).to have_text "Unfeatured post"
      expect(page).to have_checked_field "Featured"
      expect(page).to have_checked_field "Unfeatured"
      expect(page).to have_link("Reset filters")

      click_on "Reset filters"
      wait_for_loaded
      open_filters_menu

      expect(page).to have_text "Featured post"
      expect(page).to have_text "Unfeatured post"
      expect(page).to have_unchecked_field "Featured"
      expect(page).to have_unchecked_field "Unfeatured"
      expect(current_url).not_to include "encoded_filters="
      expect(page).to have_button("Reset filters", disabled: true)
    end
  end

  describe "Boolean filter with default" do
    let!(:user) { create :user }

    let!(:team_without_members) { create :team, name: "Without Members" }
    let!(:team_with_members) { create :team, name: "With Members" }

    before do
      team_with_members.team_members << user
    end

    let(:url) { "/admin/resources/teams?view_type=table" }

    it "displays the filter" do
      visit url
      open_filters_menu

      expect(page).to have_text "Members filter"
      expect(page).to have_checked_field "Has Members"
      expect(page).not_to have_text "Without Members"
      expect(page).to have_text "With Members"
      expect(page).to have_button("Reset filters", disabled: true)
    end

    it "changes the query and reset" do
      visit url
      open_filters_menu

      uncheck "Has Members"
      wait_for_loaded
      open_filters_menu

      expect(page).to have_text "Members filter"
      expect(page).to have_unchecked_field "Has Members"
      expect(page).to have_text "Without Members"
      expect(page).to have_text "With Members"
      expect(page).to have_link("Reset filters")

      click_on "Reset filters"
      wait_for_loaded

      open_filters_menu

      expect(page).to have_text "Members filter"
      expect(page).to have_checked_field "Has Members"
      expect(page).not_to have_text "Without Members"
      expect(page).to have_text "With Members"
      expect(page).to have_button("Reset filters", disabled: true)
    end
  end

  describe "Select filter" do
    let!(:published_post) { create :post, name: "Published post", published_at: "2019-12-05 08:27:19.295065" }
    let!(:unpublished_post) { create :post, name: "Unpublished post", published_at: nil }

    let(:url) { "/admin/resources/posts?view_type=table" }

    context "without default value" do
      it "displays the filter" do
        visit url
        open_filters_menu

        expect(page).to have_text "Published status"
        expect(page).to have_select "published status", selected: "Published or unpublished", options: ["Published or unpublished", "Published", "Unpublished"]
        expect(page).to have_text "Published post"
        expect(page).to have_text "Unpublished post"
        expect(page).to have_button("Reset filters", disabled: true)
      end

      it "changes the query" do
        visit url
        open_filters_menu

        select "Published", from: "avo_filters_published_status"
        wait_for_loaded
        open_filters_menu

        expect(page).to have_text "Published post"
        expect(page).not_to have_text "Unpublished post"
        expect(page).to have_select "avo_filters_published_status", selected: "Published", options: ["Published or unpublished", "Published", "Unpublished"]
        expect(current_url).to include "encoded_filters="
        expect(page).to have_link("Reset filters")
      end

      it "changes the query back also with reset" do
        visit url
        open_filters_menu

        select "Published", from: "avo_filters_published_status"
        wait_for_loaded
        open_filters_menu

        expect(page).to have_text "Published post"
        expect(page).not_to have_text "Unpublished post"
        expect(page).to have_select "avo_filters_published_status", selected: "Published", options: ["Published or unpublished", "Published", "Unpublished"]
        expect(current_url).to include "encoded_filters="
        expect(page).to have_link("Reset filters")

        select "Published or unpublished", from: "avo_filters_published_status"
        wait_for_loaded
        open_filters_menu

        expect(page).to have_text "Published post"
        expect(page).to have_text "Unpublished post"
        expect(page).to have_select "avo_filters_published_status", selected: "Published or unpublished", options: ["Published or unpublished", "Published", "Unpublished"]
        expect(current_url).not_to include "encoded_filters="
        expect(page).to have_button("Reset filters", disabled: true)

        select "Unpublished", from: "avo_filters_published_status"
        wait_for_loaded
        open_filters_menu

        expect(page).not_to have_text "Published post"
        expect(page).to have_text "Unpublished post"
        expect(page).to have_select "avo_filters_published_status", selected: "Unpublished", options: ["Published or unpublished", "Published", "Unpublished"]
        expect(current_url).to include "encoded_filters="
        expect(page).to have_link("Reset filters")

        click_on "Reset filters"
        wait_for_loaded
        open_filters_menu

        expect(page).to have_text "Published status"
        expect(page).to have_select "avo_filters_published_status", selected: "Published or unpublished", options: ["Published or unpublished", "Published", "Unpublished"]
        expect(page).to have_text "Published post"
        expect(page).to have_text "Unpublished post"
        expect(page).to have_button("Reset filters", disabled: true)
      end
    end
  end

  describe "Multiple select filter" do
    let!(:draft) { create :post, name: "draft post", status: "draft" }
    let!(:published) { create :post, name: "published post", status: "published" }
    let!(:archived) { create :post, name: "archived post", status: "archived" }

    let(:url) { "/admin/resources/posts?view_type=table" }

    context "without default value" do
      it "displays the filter" do
        visit url
        open_filters_menu

        expect(page).to have_text "Status"
        expect(page).to have_select "avo_filters_status", selected: [], options: ["draft", "published", "archived"]
        expect(page).to have_button("Reset filters", disabled: true)
      end

      it "changes the query" do
        visit url
        open_filters_menu

        select "draft", from: "avo_filters_status"
        unselect "published", from: "avo_filters_status"
        unselect "archived", from: "avo_filters_status"
        click_on "Filter by Status"
        wait_for_loaded

        expect(page).to have_text("Displaying 1 item")

        open_filters_menu

        expect(page).to have_select "avo_filters_status", selected: ["draft"], options: ["draft", "published", "archived"]
        expect(current_url).to include "encoded_filters="
        expect(page).to have_link("Reset filters")
      end

      it "allows multiple selections" do
        visit url
        open_filters_menu

        select "draft", from: "avo_filters_status"
        select "published", from: "avo_filters_status"
        unselect "archived", from: "avo_filters_status"
        click_on "Filter by Status"
        wait_for_loaded

        expect(page).to have_text("Displaying 2 items")
      end
    end
  end

  describe "Text filter" do
    let!(:user) { create :user }

    let!(:team_without_members) { create :team, name: "Without Members" }
    let!(:team_with_members) { create :team, name: "With Members" }
    let!(:team) { create :team, name: "音楽 ✓" }

    before do
      team_with_members.team_members << user
      team_without_members.team_members << user
      team.team_members << user
    end

    let(:url) { "/admin/resources/teams?view_type=table" }

    context "without default value" do
      it "displays the filter" do
        visit url
        open_filters_menu

        expect(page).to have_text "Name filter"
      end

      it "filters by name" do
        visit url
        expect(page).to have_text("Displaying 3 item")

        open_filters_menu
        fill_in "avo_filters_name_filter", with: "With Members"
        click_on "Filter by name"
        wait_for_loaded
        expect(page).to have_text("Displaying 1 item")

        open_filters_menu
        expect(page).to have_text "With Members"
        expect(page).to have_link("Reset filters")

        click_on "Reset filters"
        wait_for_loaded
        expect(page).to have_text("Displaying 3 item")
      end

      it "filters by 音楽 ✓" do
        visit url
        expect(page).to have_text("Displaying 3 item")

        open_filters_menu
        fill_in "avo_filters_name_filter", with: "音楽 ✓"
        click_on "Filter by name"
        wait_for_loaded
        expect(page).to have_text("Displaying 1 item")

        open_filters_menu
        expect(page).to have_text "音楽 ✓"
        expect(page).to have_link("Reset filters")

        click_on "Reset filters"
        wait_for_loaded
        expect(page).to have_text("Displaying 3 item")
      end
    end
  end

  describe "pagination resets when filters change" do
    let!(:published_posts) { create_list(:post, 40, published_at: rand((DateTime.now - 3.months)..DateTime.now)) }
    let!(:unpublished_post) { create :post, name: "Unpublished post", published_at: nil }
    let(:url) { "/admin/resources/posts?view_type=table&per_page=12" }

    context "with pagination set" do
      it "resets the pagination" do
        visit url
        click_on "3"
        wait_for_loaded
        click_on "Filters"
        wait_for_loaded
        check "Featured"

        expect(page).to have_css "[data-turbo-frame][aria-label='Next']"
        expect(page).to have_css "[data-turbo-frame][aria-label='Previous']"

        expect(find(".current")).to have_text "1"
        expect(find(".current")).not_to have_text "2"
      end
    end
  end

  describe "date time filters" do
    context "date with range selector" do
      # Flatpickr opens on current year by default, use current year to avoid changing year on tests.
      let!(:current_year) { Time.now.year }
      # Flatpickr opens on current month by default, use current month to avoid changing month on tests.
      let!(:current_month) { Time.now.month }
      let!(:user_15) { create :user, first_name: "Birthday on 15", birthday: "#{current_year}-#{current_month}-15 00:00:00" }
      let!(:user_17) { create :user, first_name: "Birthday on 17", birthday: "#{current_year}-#{current_month}-17 00:00:00" }
      let!(:user_20) { create :user, first_name: "Birthday on 20", birthday: "#{current_year}-#{current_month}-20 00:00:00" }

      subject(:text_input) { find 'input[type="text"][placeholder="Filter by birthday"][data-date-time-filter-target="input"]' }

      it "filters users by birthday range" do
        visit avo.resources_users_path

        expect(page).to have_text user_15.first_name
        expect(page).to have_text user_17.first_name
        expect(page).to have_text user_20.first_name

        open_filters_menu

        expect(page).to have_text "Apply birthday filter"

        open_picker
        set_picker_day "#{Date::MONTHNAMES[current_month]} 15, #{current_year}"
        set_picker_day "#{Date::MONTHNAMES[current_month]} 17, #{current_year}"

        click_on "Apply birthday filter"

        expect(page).to have_text user_15.first_name
        expect(page).to have_text user_17.first_name
        expect(page).not_to have_text user_20.first_name
      end
    end

    # TODO
    # context "date with single selector" do
    # end

    # TODO
    # context "date time with range selector" do
    # end

    # TODO
    # context "date time with single selector" do
    # end

    context "time with single selector" do
      let!(:course_16_10) { create :course, name: "starting at 16:10", starting_at: Time.parse("16:10:00") }
      let!(:course_16_15) { create :course, name: "starting at 16:15", starting_at: Time.parse("16:15:18") }
      let!(:course_16_15_19) { create :course, name: "starting at 16:15:19", starting_at: Time.parse("16:15:19") }
      let!(:course_16_16) { create :course, name: "starting at 16:16", starting_at: Time.parse("16:16:00") }

      subject(:text_input) { find 'input[type="text"][placeholder="Search by start time"][data-date-time-filter-target="input"]' }

      it "filters courses by starting at" do
        visit avo.resources_courses_path

        expect(page).to have_text course_16_10.name
        expect(page).to have_text course_16_15.name
        expect(page).to have_text course_16_15_19.name
        expect(page).to have_text course_16_16.name

        open_filters_menu

        expect(page).to have_text "Filter by start time"

        open_picker
        set_picker_hour 16
        set_picker_minute 15
        set_picker_second 18

        all("button", text: "Filter by start time").first.trigger("click")

        expect(page).not_to have_text course_16_10.name
        expect(page).to have_text course_16_15.name
        expect(page).not_to have_text course_16_15_19.name
        expect(page).not_to have_text course_16_16.name
      end
    end
  end
end
