/**
 * Tests for SortableColumnItem — a DnD-kit sortable menu item.
 *
 * `useSortable` is mocked so we can drive isDragging / transform independently
 * and exercise the conditional style branches without spinning up a real
 * DndContext + SortableContext.
 */
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render } from '@testing-library/react'

// Mock @dnd-kit/sortable's useSortable. Tests can override the return value
// per-test via setSortableReturn.
interface SortableReturn {
  attributes: Record<string, unknown>
  listeners: Record<string, unknown>
  setNodeRef: (el: HTMLElement | null) => void
  transform: { x: number; y: number; scaleX: number; scaleY: number } | null
  transition: string | undefined
  isDragging: boolean
}

let sortableReturn: SortableReturn = {
  attributes: { 'aria-roledescription': 'sortable' },
  listeners: {},
  setNodeRef: () => undefined,
  transform: null,
  transition: undefined,
  isDragging: false,
}

const setSortableReturn = (overrides: Partial<SortableReturn>) => {
  sortableReturn = { ...sortableReturn, ...overrides }
}

vi.mock('@dnd-kit/sortable', () => ({
  useSortable: () => sortableReturn,
}))

import { SortableColumnItem } from './sortable-column-item'
import type { TableColumn } from '../../table/types'

const baseColumn: TableColumn = {
  id: 'col-1',
  label: 'Name',
}

beforeEach(() => {
  // Reset to defaults so each test starts clean.
  sortableReturn = {
    attributes: { 'aria-roledescription': 'sortable' },
    listeners: {},
    setNodeRef: () => undefined,
    transform: null,
    transition: undefined,
    isDragging: false,
  }
})

describe('SortableColumnItem', () => {
  it('renders the column label', () => {
    const { getByText } = render(<SortableColumnItem column={baseColumn} />)
    expect(getByText('Name')).toBeDefined()
  })

  it('renders as a menuitem role', () => {
    const { getByRole } = render(<SortableColumnItem column={baseColumn} />)
    expect(getByRole('menuitem')).toBeDefined()
  })

  it('applies grab cursor + opacity=1 when not dragging', () => {
    setSortableReturn({ isDragging: false })
    const { getByRole } = render(<SortableColumnItem column={baseColumn} />)
    const item = getByRole('menuitem')
    expect(item.style.cursor).toBe('grab')
    expect(item.style.opacity).toBe('1')
  })

  it('applies grabbing cursor + opacity=0.5 when dragging', () => {
    setSortableReturn({ isDragging: true })
    const { getByRole } = render(<SortableColumnItem column={baseColumn} />)
    const item = getByRole('menuitem')
    expect(item.style.cursor).toBe('grabbing')
    expect(item.style.opacity).toBe('0.5')
  })

  it('forces transform.x to 0 when transform is non-null (vertical-only drag)', () => {
    setSortableReturn({
      transform: { x: 50, y: 20, scaleX: 1, scaleY: 1 },
      transition: 'transform 200ms ease',
    })
    const { getByRole } = render(<SortableColumnItem column={baseColumn} />)
    const item = getByRole('menuitem')
    // CSS.Transform.toString({x: 0, y: 20, ...}) → 'translate3d(0px, 20px, 0)'
    expect(item.style.transform).toContain('0px')
    expect(item.style.transform).toContain('20px')
  })

  it('handles a null transform (no drag offset applied)', () => {
    setSortableReturn({ transform: null })
    const { getByRole } = render(<SortableColumnItem column={baseColumn} />)
    const item = getByRole('menuitem')
    // CSS.Transform.toString(null) is undefined → no transform attr
    expect(item.style.transform).toBe('')
  })

  it('threads dnd-kit attributes onto the rendered element', () => {
    setSortableReturn({
      attributes: { 'aria-roledescription': 'draggable column' },
    })
    const { getByRole } = render(<SortableColumnItem column={baseColumn} />)
    expect(getByRole('menuitem').getAttribute('aria-roledescription')).toBe(
      'draggable column',
    )
  })

  it('renders a column with a ReactNode label', () => {
    const column: TableColumn = {
      id: 'col-x',
      label: <span data-testid='custom-label'>Custom</span>,
    }
    const { getByTestId } = render(<SortableColumnItem column={column} />)
    expect(getByTestId('custom-label')).toBeDefined()
  })
})
