import { composeStories } from "@storybook/react"
import { screen, within } from "@testing-library/react"
import { userEvent } from "@testing-library/user-event"
import React from "react"
import { beforeEach, describe, test, vi, expect } from "vitest"
import { VirtualizedTable } from ".."
import { render } from "../../../tests/render"
import * as stories from "./VirtualizedTable.stories"

const { Sticky, WithSortableHeaders, Interactive } = composeStories(stories)

describe("<VirtualizedTable />", () => {
  beforeEach(() => {
    window.scrollTo = vi.fn().mockImplementation(() => undefined)
  })

  test("is accessible", async () => {
    render(<Sticky />)

    expect(screen.getByRole("columnheader", { name: "Row #" })).toBeVisible()
    expect(screen.getByRole("columnheader", { name: "Primary" })).toBeVisible()
    expect(
      screen.getByRole("columnheader", { name: "Secondary" }),
    ).toBeVisible()
    expect(screen.getByRole("columnheader", { name: "Tertiary" })).toBeVisible()
    expect(
      screen.getByRole("columnheader", { name: "Quaternary" }),
    ).toBeVisible()

    expect(
      within(screen.getAllByRole("row")[1]).getAllByRole("cell"),
    ).toHaveLength(5)
  })

  test("<WithSortableHeaders/>", async () => {
    render(<WithSortableHeaders />)

    await userEvent.click(screen.getByText("Row #"))

    const rows = screen.getAllByRole("row").slice(1)

    for (let i = 1; i < rows.length; i++) {
      const row = rows[i]
      expect(
        +(within(row).getAllByRole("cell")[0].textContent || 0),
      ).toBeLessThanOrEqual(
        +(within(rows[i - 1]).getAllByRole("cell")[0].textContent || 0),
      )
    }
  })

  test("<Interactive/>", async () => {
    const onRowClick = vi.fn()
    render(<Interactive onRowClick={onRowClick} />)
    const rows = screen.getAllByRole("row")

    await userEvent.click(rows[2].firstChild as HTMLElement)

    expect(onRowClick).toHaveBeenCalledTimes(1)
  })

  test("Context propagation", () => {
    render(
      <VirtualizedTable
        context={{ key: "value" }}
        itemKey={item => item?.id}
        items={[{ id: "123" }]}
        renderRow={({ context }) => <>{JSON.stringify(context)}</>}
      />,
    )

    expect(screen.getByText('{"key":"value"}')).toBeInTheDocument()
  })
})
