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

describe('RadioGroup + RadioItem', () => {
  it('renders all options with correct labels', () => {
    render(
      <RadioGroup name="color" value="red" onChange={vi.fn()}>
        <RadioItem value="red" label="Red" />
        <RadioItem value="blue" label="Blue" />
        <RadioItem value="green" label="Green" />
      </RadioGroup>,
    )
    expect(screen.getByLabelText('Red')).toBeInTheDocument()
    expect(screen.getByLabelText('Blue')).toBeInTheDocument()
    expect(screen.getByLabelText('Green')).toBeInTheDocument()
  })

  it('marks the current value as checked', () => {
    render(
      <RadioGroup name="color" value="blue" onChange={vi.fn()}>
        <RadioItem value="red" label="Red" />
        <RadioItem value="blue" label="Blue" />
      </RadioGroup>,
    )
    expect(screen.getByLabelText('Red')).not.toBeChecked()
    expect(screen.getByLabelText('Blue')).toBeChecked()
  })

  it('calls onChange with the selected value when clicking an option', async () => {
    const onChange = vi.fn()
    const user = userEvent.setup()
    render(
      <RadioGroup name="color" value="red" onChange={onChange}>
        <RadioItem value="red" label="Red" />
        <RadioItem value="blue" label="Blue" />
      </RadioGroup>,
    )
    await user.click(screen.getByLabelText('Blue'))
    expect(onChange).toHaveBeenCalledWith('blue')
  })

  it('does not call onChange when clicking a disabled item', async () => {
    const onChange = vi.fn()
    const user = userEvent.setup()
    render(
      <RadioGroup name="color" value="red" onChange={onChange}>
        <RadioItem value="red" label="Red" />
        <RadioItem value="blue" label="Blue" disabled />
      </RadioGroup>,
    )
    await user.click(screen.getByLabelText('Blue'))
    expect(onChange).not.toHaveBeenCalled()
  })

  it('disabled item has disabled attribute', () => {
    render(
      <RadioGroup name="color" value="red" onChange={vi.fn()}>
        <RadioItem value="red" label="Red" />
        <RadioItem value="blue" label="Blue" disabled />
      </RadioGroup>,
    )
    expect(screen.getByLabelText('Blue')).toBeDisabled()
    expect(screen.getByLabelText('Red')).not.toBeDisabled()
  })

  it('all inputs share the same name', () => {
    render(
      <RadioGroup name="size" value="md" onChange={vi.fn()}>
        <RadioItem value="sm" label="Small" />
        <RadioItem value="md" label="Medium" />
        <RadioItem value="lg" label="Large" />
      </RadioGroup>,
    )
    const inputs = screen.getAllByRole('radio')
    inputs.forEach((input) => {
      expect(input).toHaveAttribute('name', 'size')
    })
  })

  it('supports keyboard navigation between items', async () => {
    const onChange = vi.fn()
    const user = userEvent.setup()
    render(
      <RadioGroup name="color" value="red" onChange={onChange}>
        <RadioItem value="red" label="Red" />
        <RadioItem value="blue" label="Blue" />
      </RadioGroup>,
    )
    const redInput = screen.getByLabelText('Red')
    redInput.focus()
    await user.keyboard('{ArrowDown}')
    expect(onChange).toHaveBeenCalledWith('blue')
  })

  it('applies horizontal layout class when orientation is horizontal', () => {
    const { container } = render(
      <RadioGroup name="color" value="red" onChange={vi.fn()} orientation="horizontal">
        <RadioItem value="red" label="Red" />
        <RadioItem value="blue" label="Blue" />
      </RadioGroup>,
    )
    const group = container.firstChild as HTMLElement
    expect(group.className).toMatch(/horizontal/)
  })

  it('applies vertical layout class by default', () => {
    const { container } = render(
      <RadioGroup name="color" value="red" onChange={vi.fn()}>
        <RadioItem value="red" label="Red" />
      </RadioGroup>,
    )
    const group = container.firstChild as HTMLElement
    expect(group.className).toMatch(/vertical/)
  })

  it('accepts a ReactNode as label', () => {
    render(
      <RadioGroup name="color" value="red" onChange={vi.fn()}>
        <RadioItem value="red" label={<strong>Bold Red</strong>} />
      </RadioGroup>,
    )
    expect(screen.getByText('Bold Red')).toBeInTheDocument()
  })

  it('applies custom className to RadioGroup', () => {
    const { container } = render(
      <RadioGroup name="color" value="red" onChange={vi.fn()} className="custom-class">
        <RadioItem value="red" label="Red" />
      </RadioGroup>,
    )
    const group = container.firstChild as HTMLElement
    expect(group.className).toContain('custom-class')
  })
})
