import React from "react"
import { render, screen } from "@testing-library/react"
import userEvent from "@testing-library/user-event"
import MultiSelectFilter from "../filter"

describe("MultiselectFilter", () => {
  const options = [
    { label: "Walleye", value: "walleye" },
    { label: "Bass", value: "bass" },
    { label: "Perch", value: "perch" }
  ]

  it("applies aria-label to the reference when passed", () => {
    render(
      <MultiSelectFilter
        aria-label="Select an option"
        options={[
          { label: "Option 1", value: "option1" },
          { label: "Option 2", value: "option2" },
          { label: "Option 3", value: "option3" }
        ]}
      />
    )

    const trigger = screen.getByRole("combobox")
    userEvent.click(trigger)

    const listbox = screen.getByRole("listbox")

    expect(trigger).toHaveAttribute("aria-label", "Select an option")
    expect(listbox).not.toHaveAttribute("aria-label", "Select an option")
  })

  it("applies aria-labelledby to the reference when passed", () => {
    render(
      <MultiSelectFilter
        aria-labelledby="my-external-id"
        options={[
          { label: "Option 1", value: "option1" },
          { label: "Option 2", value: "option2" },
          { label: "Option 3", value: "option3" }
        ]}
      />
    )

    const trigger = screen.getByRole("combobox")
    userEvent.click(trigger)

    const listbox = screen.getByRole("listbox")

    expect(trigger).toHaveAttribute("aria-labelledby", "my-external-id")
    expect(listbox).not.toHaveAttribute("aria-labelledby", "my-external-id")
  })

  it("passes the selected options to the onChange callback", () => {
    const handleChange = jest.fn()
    render(<MultiSelectFilter options={options} onChange={handleChange} />)
    const combobox = screen.getByRole("combobox")

    userEvent.click(combobox)

    const listOptions = screen.getAllByRole("option")

    userEvent.click(listOptions[1])
    userEvent.click(listOptions[2])

    expect(handleChange).toHaveBeenCalledWith({
      target: {
        name: undefined,
        value: [options[1], options[2]]
      }
    })
  })

  it("shows an indicator when the filter is active", () => {
    render(<MultiSelectFilter options={options} />)
    const combobox = screen.getByRole("combobox")

    userEvent.click(combobox)

    const indicator = screen.getByRole("status")
    expect(indicator).toBeInTheDocument()
    expect(indicator).toHaveAccessibleName("0 filters active")

    const listOptions = screen.getAllByRole("option")

    userEvent.click(listOptions[1])

    expect(indicator).toHaveAccessibleName("1 filter active")

    userEvent.click(listOptions[0])

    expect(indicator).toHaveAccessibleName("2 filters active")
  })

  it("does not allow interaction with the filter when disabled", () => {
    render(<MultiSelectFilter options={options} disabled />)
    const combobox = screen.getByRole("combobox")

    expect(combobox).toHaveAttribute("aria-disabled", "true")
    userEvent.click(combobox)

    const listOptions = screen.queryAllByRole("option")
    expect(listOptions).toHaveLength(0)
  })

  it("clears selection when value prop changes", async () => {
    render(<ClearableFilter />)

    const clearButton = screen.getByTestId("clear-btn")

    const combobox = screen.getByRole("combobox")

    userEvent.click(combobox)

    let listOptions = screen.getAllByRole("option")

    expect(listOptions).toHaveLength(4)

    let selectedOptions = screen.getAllByRole("option", { selected: true })

    expect(selectedOptions).toHaveLength(2)

    userEvent.click(clearButton)

    userEvent.click(combobox)

    listOptions = screen.getAllByRole("option")
    selectedOptions = screen.queryAllByRole("option", { selected: true })

    expect(listOptions).toHaveLength(4)
    expect(selectedOptions).toHaveLength(0)
  })
})

function ClearableFilter() {
  const options = [
    { label: "Walleye", value: "walleye" },
    { label: "Bass", value: "bass" },
    { label: "Perch", value: "perch" },
    { label: "Pike", value: "pike" }
  ]
  const [value, setValue] = React.useState(["bass", "pike"])

  const handleClick = () => {
    setValue([])
  }

  return (
    <div>
      <MultiSelectFilter options={options} value={value} />
      <button data-testid="clear-btn" onClick={handleClick}>Clear values</button>
    </div>
  )
}
