import { describe, it, expect, vi } from 'vitest'
import { fireEvent, render, screen, within } from '@testing-library/react'
import { TableUI } from './table-ui'
import type { TableColumn } from './types'

const COLUMNS: TableColumn[] = [
  { id: 'name', label: 'Name', sortable: true },
  { id: 'score', label: 'Score', sortable: true, align: 'right' },
]

const ROWS = [
  { id: 1, name: 'Alpha', score: 12 },
  { id: 2, name: 'Beta', score: 7 },
]

describe('<TableUI>', () => {
  it('renders one row per item with each column cell', () => {
    render(
      <TableUI
        columns={COLUMNS}
        rows={ROWS}
        total={ROWS.length}
        page={0}
        pageSize={10}
      />,
    )
    expect(screen.getByText('Alpha')).toBeTruthy()
    expect(screen.getByText('Beta')).toBeTruthy()
    expect(screen.getByText('12')).toBeTruthy()
    expect(screen.getByText('7')).toBeTruthy()
  })

  it('fires onSortChange with new column id and asc on first click', () => {
    const onSortChange = vi.fn()
    render(
      <TableUI
        columns={COLUMNS}
        rows={ROWS}
        total={ROWS.length}
        page={0}
        pageSize={10}
        onSortChange={onSortChange}
      />,
    )
    fireEvent.click(screen.getByText('Name'))
    expect(onSortChange).toHaveBeenCalledWith({
      columnId: 'name',
      direction: 'asc',
    })
  })

  it('flips direction on the same column', () => {
    const onSortChange = vi.fn()
    render(
      <TableUI
        columns={COLUMNS}
        rows={ROWS}
        total={ROWS.length}
        page={0}
        pageSize={10}
        sort={{ columnId: 'name', direction: 'asc' }}
        onSortChange={onSortChange}
      />,
    )
    fireEvent.click(screen.getByText('Name'))
    expect(onSortChange).toHaveBeenCalledWith({
      columnId: 'name',
      direction: 'desc',
    })
  })

  it('renders a checkbox column when selectable', () => {
    render(
      <TableUI
        columns={COLUMNS}
        rows={ROWS}
        total={ROWS.length}
        page={0}
        pageSize={10}
        selectable
      />,
    )
    expect(screen.getAllByRole('checkbox').length).toBe(ROWS.length + 1)
  })

  it('select-all toggles selection of all rows on the page', () => {
    const onSelectionChange = vi.fn()
    render(
      <TableUI
        columns={COLUMNS}
        rows={ROWS}
        total={ROWS.length}
        page={0}
        pageSize={10}
        selectable
        selection={[]}
        onSelectionChange={onSelectionChange}
      />,
    )
    const headerCheckbox = screen.getAllByRole('checkbox')[0]!
    fireEvent.click(headerCheckbox)
    expect(onSelectionChange).toHaveBeenCalledWith([1, 2])
  })

  it('row checkbox toggles individual rows', () => {
    const onSelectionChange = vi.fn()
    render(
      <TableUI
        columns={COLUMNS}
        rows={ROWS}
        total={ROWS.length}
        page={0}
        pageSize={10}
        selectable
        selection={[]}
        onSelectionChange={onSelectionChange}
      />,
    )
    const rowCheckbox = screen.getByLabelText('Select row 1')
    fireEvent.click(rowCheckbox)
    expect(onSelectionChange).toHaveBeenCalledWith([1])
  })

  it('marks already-selected rows as checked', () => {
    render(
      <TableUI
        columns={COLUMNS}
        rows={ROWS}
        total={ROWS.length}
        page={0}
        pageSize={10}
        selectable
        selection={[2]}
      />,
    )
    const rowCheckbox = screen.getByLabelText('Select row 2')
    expect((rowCheckbox as HTMLInputElement).checked).toBe(true)
  })

  it('uses the column formatter when provided', () => {
    const cols: TableColumn[] = [
      { id: 'score', label: 'Score', formatter: (v) => `<<${String(v)}>>` },
    ]
    render(
      <TableUI
        columns={cols}
        rows={ROWS}
        total={ROWS.length}
        page={0}
        pageSize={10}
      />,
    )
    expect(screen.getByText('<<12>>')).toBeTruthy()
  })

  it('fires onRowClick with the row when a row is clicked', () => {
    const onRowClick = vi.fn()
    render(
      <TableUI
        columns={COLUMNS}
        rows={ROWS}
        total={ROWS.length}
        page={0}
        pageSize={10}
        onRowClick={onRowClick}
      />,
    )
    fireEvent.click(screen.getByText('Alpha'))
    expect(onRowClick).toHaveBeenCalledWith(ROWS[0])
  })

  it('shows the empty content when rows is empty', () => {
    render(
      <TableUI
        columns={COLUMNS}
        rows={[]}
        total={0}
        page={0}
        pageSize={10}
        emptyContent={<span>No rows</span>}
      />,
    )
    expect(screen.getByText('No rows')).toBeTruthy()
  })

  it('renders pagination row count using the labels formatter', () => {
    const { container } = render(
      <TableUI
        columns={COLUMNS}
        rows={ROWS}
        total={42}
        page={0}
        pageSize={10}
        labels={{ paginationOf: (f, t, total) => `${f}…${t} / ${total}` }}
      />,
    )
    expect(container.textContent).toContain('1…10 / 42')
    void within
  })
})
