import { describe, it, expect, vi } from 'vitest'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Pagination, getPageRange } from './Pagination'

describe('getPageRange', () => {
  it('returns all pages when totalPages is small', () => {
    expect(getPageRange(1, 5, 1)).toEqual([1, 2, 3, 4, 5])
  })

  it('returns only page 1 when totalPages is 1', () => {
    expect(getPageRange(1, 1, 1)).toEqual([1])
  })

  it('adds left ellipsis when current page is far from start', () => {
    const range = getPageRange(10, 20, 1)
    expect(range[0]).toBe(1)
    expect(range[1]).toBe('ellipsis')
  })

  it('adds right ellipsis when current page is far from end', () => {
    const range = getPageRange(1, 20, 1)
    const lastEllipsisIdx = range.lastIndexOf('ellipsis')
    expect(lastEllipsisIdx).toBeGreaterThan(-1)
    expect(range[range.length - 1]).toBe(20)
  })

  it('shows first and last page always', () => {
    const range = getPageRange(5, 20, 1)
    expect(range[0]).toBe(1)
    expect(range[range.length - 1]).toBe(20)
  })

  it('renders pages around current with siblingCount=1', () => {
    // page 5, totalPages 20, siblingCount 1 → 1 ... 4 5 6 ... 20
    const range = getPageRange(5, 20, 1)
    expect(range).toContain(4)
    expect(range).toContain(5)
    expect(range).toContain(6)
  })

  it('renders wider sibling window with siblingCount=2', () => {
    // page 10, totalPages 20, siblingCount 2 → 1 ... 8 9 10 11 12 ... 20
    const range = getPageRange(10, 20, 2)
    expect(range).toContain(8)
    expect(range).toContain(9)
    expect(range).toContain(10)
    expect(range).toContain(11)
    expect(range).toContain(12)
  })

  it('does not duplicate page 1 when siblings reach the start', () => {
    const range = getPageRange(2, 20, 1)
    const ones = range.filter(x => x === 1)
    expect(ones).toHaveLength(1)
  })

  it('does not duplicate last page when siblings reach the end', () => {
    const range = getPageRange(19, 20, 1)
    const twenties = range.filter(x => x === 20)
    expect(twenties).toHaveLength(1)
  })
})

describe('Pagination', () => {
  it('renders prev and next buttons', () => {
    render(<Pagination page={5} totalPages={20} onPageChange={vi.fn()} />)
    expect(screen.getByRole('button', { name: 'Previous page' })).toBeInTheDocument()
    expect(screen.getByRole('button', { name: 'Next page' })).toBeInTheDocument()
  })

  it('marks the current page with aria-current', () => {
    render(<Pagination page={5} totalPages={20} onPageChange={vi.fn()} />)
    const activeBtn = screen.getByRole('button', { name: 'Page 5' })
    expect(activeBtn).toHaveAttribute('aria-current', 'page')
  })

  it('shows ellipsis when pages are far apart', () => {
    render(<Pagination page={10} totalPages={20} onPageChange={vi.fn()} />)
    const ellipses = screen.getAllByText('…')
    expect(ellipses.length).toBeGreaterThanOrEqual(1)
  })

  it('disables prev button on first page', () => {
    render(<Pagination page={1} totalPages={10} onPageChange={vi.fn()} />)
    expect(screen.getByRole('button', { name: 'Previous page' })).toBeDisabled()
  })

  it('does not disable next button on first page', () => {
    render(<Pagination page={1} totalPages={10} onPageChange={vi.fn()} />)
    expect(screen.getByRole('button', { name: 'Next page' })).not.toBeDisabled()
  })

  it('disables next button on last page', () => {
    render(<Pagination page={10} totalPages={10} onPageChange={vi.fn()} />)
    expect(screen.getByRole('button', { name: 'Next page' })).toBeDisabled()
  })

  it('does not disable prev button on last page', () => {
    render(<Pagination page={10} totalPages={10} onPageChange={vi.fn()} />)
    expect(screen.getByRole('button', { name: 'Previous page' })).not.toBeDisabled()
  })

  it('fires onPageChange with page - 1 when prev is clicked', async () => {
    const user = userEvent.setup()
    const onPageChange = vi.fn()
    render(<Pagination page={5} totalPages={20} onPageChange={onPageChange} />)
    await user.click(screen.getByRole('button', { name: 'Previous page' }))
    expect(onPageChange).toHaveBeenCalledWith(4)
  })

  it('fires onPageChange with page + 1 when next is clicked', async () => {
    const user = userEvent.setup()
    const onPageChange = vi.fn()
    render(<Pagination page={5} totalPages={20} onPageChange={onPageChange} />)
    await user.click(screen.getByRole('button', { name: 'Next page' }))
    expect(onPageChange).toHaveBeenCalledWith(6)
  })

  it('fires onPageChange with the clicked page number', async () => {
    const user = userEvent.setup()
    const onPageChange = vi.fn()
    render(<Pagination page={5} totalPages={20} onPageChange={onPageChange} />)
    await user.click(screen.getByRole('button', { name: 'Page 6' }))
    expect(onPageChange).toHaveBeenCalledWith(6)
  })

  it('applies custom className', () => {
    const { container } = render(
      <Pagination page={1} totalPages={5} onPageChange={vi.fn()} className="custom-class" />
    )
    expect(container.firstChild).toHaveClass('custom-class')
  })

  it('renders with siblingCount=0 showing only current page between first and last', () => {
    render(<Pagination page={10} totalPages={20} onPageChange={vi.fn()} siblingCount={0} />)
    expect(screen.getByRole('button', { name: 'Page 10' })).toBeInTheDocument()
    expect(screen.getByRole('button', { name: 'Page 1' })).toBeInTheDocument()
    expect(screen.getByRole('button', { name: 'Page 20' })).toBeInTheDocument()
  })
})
