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

const OPTIONS = [
  { value: 'admin', label: 'ADMIN' },
  { value: 'editor', label: 'EDITOR' },
  { value: 'viewer', label: 'VIEWER' },
  { value: 'operator', label: 'OPERATOR' },
]

describe('MultiSelect', () => {
  it('renders trigger with placeholder', () => {
    render(<MultiSelect options={OPTIONS} value={[]} onChange={vi.fn()} />)
    expect(screen.getByText('Select...')).toBeInTheDocument()
  })

  it('renders trigger with custom placeholder', () => {
    render(<MultiSelect options={OPTIONS} value={[]} onChange={vi.fn()} placeholder="Add roles..." />)
    expect(screen.getByText('Add roles...')).toBeInTheDocument()
  })

  it('shows selected count on trigger', () => {
    render(<MultiSelect options={OPTIONS} value={['admin', 'editor']} onChange={vi.fn()} />)
    expect(screen.getByText('2 selected')).toBeInTheDocument()
  })

  it('opens dropdown on trigger click', async () => {
    const user = userEvent.setup()
    render(<MultiSelect options={OPTIONS} value={[]} onChange={vi.fn()} />)
    await user.click(screen.getByRole('combobox'))
    expect(screen.getByText('ADMIN')).toBeInTheDocument()
    expect(screen.getByText('EDITOR')).toBeInTheDocument()
  })

  it('shows checkboxes for pre-selected values', async () => {
    const user = userEvent.setup()
    render(<MultiSelect options={OPTIONS} value={['admin']} onChange={vi.fn()} />)
    await user.click(screen.getByRole('combobox'))
    const adminCheckbox = screen.getByRole('checkbox', { name: 'ADMIN' })
    expect(adminCheckbox).toBeChecked()
  })

  it('filters options by search text', async () => {
    const user = userEvent.setup()
    render(<MultiSelect options={OPTIONS} value={[]} onChange={vi.fn()} />)
    await user.click(screen.getByRole('combobox'))
    await user.type(screen.getByPlaceholderText('Search...'), 'adm')
    expect(screen.getByText('ADMIN')).toBeInTheDocument()
    expect(screen.queryByText('EDITOR')).not.toBeInTheDocument()
  })

  it('calls onChange with selected values on Apply', async () => {
    const onChange = vi.fn()
    const user = userEvent.setup()
    render(<MultiSelect options={OPTIONS} value={[]} onChange={onChange} />)
    await user.click(screen.getByRole('combobox'))
    await user.click(screen.getByRole('checkbox', { name: 'ADMIN' }))
    await user.click(screen.getByRole('checkbox', { name: 'VIEWER' }))
    await user.click(screen.getByRole('button', { name: /Apply/ }))
    expect(onChange).toHaveBeenCalledWith(['admin', 'viewer'])
  })

  it('discards pending changes on Escape', async () => {
    const onChange = vi.fn()
    const user = userEvent.setup()
    render(<MultiSelect options={OPTIONS} value={[]} onChange={onChange} />)
    await user.click(screen.getByRole('combobox'))
    await user.click(screen.getByRole('checkbox', { name: 'ADMIN' }))
    await user.keyboard('{Escape}')
    expect(onChange).not.toHaveBeenCalled()
  })

  it('closes dropdown on outside click without applying', async () => {
    const onChange = vi.fn()
    const user = userEvent.setup()
    render(
      <div>
        <MultiSelect options={OPTIONS} value={[]} onChange={onChange} />
        <button>Outside</button>
      </div>
    )
    await user.click(screen.getByRole('combobox'))
    await user.click(screen.getByRole('checkbox', { name: 'ADMIN' }))
    await user.click(screen.getByText('Outside'))
    expect(onChange).not.toHaveBeenCalled()
  })

  it('disables trigger when disabled prop is set', () => {
    render(<MultiSelect options={OPTIONS} value={[]} onChange={vi.fn()} disabled />)
    expect(screen.getByRole('combobox')).toHaveAttribute('aria-disabled', 'true')
  })

  it('hides search input when searchable is false', async () => {
    const user = userEvent.setup()
    render(<MultiSelect options={OPTIONS} value={[]} onChange={vi.fn()} searchable={false} />)
    await user.click(screen.getByRole('combobox'))
    expect(screen.queryByPlaceholderText('Search...')).not.toBeInTheDocument()
  })

  it('shows Apply button with count of pending changes', async () => {
    const user = userEvent.setup()
    render(<MultiSelect options={OPTIONS} value={['admin']} onChange={vi.fn()} />)
    await user.click(screen.getByRole('combobox'))
    await user.click(screen.getByRole('checkbox', { name: 'EDITOR' }))
    expect(screen.getByRole('button', { name: /Apply \(2\)/ })).toBeInTheDocument()
  })
})
