import { describe, test, expect, vi } from 'vitest'
import { render, screen, fireEvent } from '@testing-library/react'
import { Options } from './options'

describe('Options', () => {
  test('renders options button with default label', () => {
    const options = [
      {
        label: 'Option 1',
        onClick: vi.fn(),
      },
    ]
    render(<Options options={options} />)
    expect(screen.getByLabelText('Options')).toBeTruthy()
  })

  test('renders options button with custom label', () => {
    const options = [
      {
        label: 'Option 1',
        onClick: vi.fn(),
      },
    ]
    const labels = {
      title: 'Custom Options Label',
    }
    render(<Options options={options} labels={labels} />)
    expect(screen.getByLabelText('Custom Options Label')).toBeTruthy()
  })

  test('renders when options array is empty', () => {
    render(<Options options={[]} />)
    // Component still renders button even with empty options
    // (In practice, WrapperUI doesn't render Options when options.length === 0)
    expect(screen.getByLabelText('Options')).toBeTruthy()
  })

  test('renders when options is undefined', () => {
    render(<Options />)
    // Component still renders button even with undefined options
    // (In practice, WrapperUI doesn't render Options when options.length === 0)
    expect(screen.getByLabelText('Options')).toBeTruthy()
  })

  test('opens menu when button is clicked', () => {
    const options = [
      {
        label: 'Option 1',
        onClick: vi.fn(),
      },
    ]
    render(<Options options={options} />)

    const button = screen.getByLabelText('Options')
    fireEvent.click(button)

    expect(screen.getByText('Option 1')).toBeTruthy()
  })

  test('closes menu when option is clicked', () => {
    const onClick = vi.fn()
    const options = [
      {
        label: 'Option 1',
        onClick,
      },
    ]
    render(<Options options={options} />)

    const button = screen.getByLabelText('Options')
    fireEvent.click(button)

    const menuItem = screen.getByText('Option 1')
    fireEvent.click(menuItem)

    expect(onClick).toHaveBeenCalledTimes(1)
    // Menu should be closed after clicking
    expect(screen.queryByRole('menu')).toBeNull()
  })

  test('stops event propagation when opening menu', () => {
    const parentOnClick = vi.fn()
    const options = [
      {
        label: 'Option 1',
        onClick: vi.fn(),
      },
    ]

    render(
      <div
        role='button'
        tabIndex={0}
        onClick={parentOnClick}
        onKeyDown={parentOnClick}
      >
        <Options options={options} />
      </div>,
    )

    const button = screen.getByLabelText('Options')
    fireEvent.click(button)

    // Parent onClick should not be called
    expect(parentOnClick).not.toHaveBeenCalled()
  })

  test('stops event propagation when clicking option', () => {
    const parentOnClick = vi.fn()
    const onClick = vi.fn()
    const options = [
      {
        label: 'Option 1',
        onClick,
      },
    ]

    render(
      <div
        role='button'
        tabIndex={0}
        onClick={parentOnClick}
        onKeyDown={parentOnClick}
      >
        <Options options={options} />
      </div>,
    )

    const button = screen.getByLabelText('Options')
    fireEvent.click(button)

    const menuItem = screen.getByText('Option 1')
    fireEvent.click(menuItem)

    expect(onClick).toHaveBeenCalledTimes(1)
    expect(parentOnClick).not.toHaveBeenCalled()
  })

  test('renders multiple options', () => {
    const options = [
      {
        label: 'Option 1',
        onClick: vi.fn(),
      },
      {
        label: 'Option 2',
        onClick: vi.fn(),
      },
      {
        label: 'Option 3',
        onClick: vi.fn(),
      },
    ]
    render(<Options options={options} />)

    const button = screen.getByLabelText('Options')
    fireEvent.click(button)

    expect(screen.getByText('Option 1')).toBeTruthy()
    expect(screen.getByText('Option 2')).toBeTruthy()
    expect(screen.getByText('Option 3')).toBeTruthy()
  })

  test('renders disabled option', () => {
    const options = [
      {
        label: 'Disabled Option',
        disabled: true,
        onClick: vi.fn(),
      },
    ]
    render(<Options options={options} />)

    const button = screen.getByLabelText('Options')
    fireEvent.click(button)

    const menuItem = screen.getByText('Disabled Option').closest('li')
    expect(menuItem?.classList.contains('Mui-disabled')).toBe(true)
  })

  test('does not call onClick for disabled option', () => {
    const onClick = vi.fn()
    const options = [
      {
        label: 'Enabled Option',
        onClick,
      },
      {
        label: 'Disabled Option',
        disabled: true,
        onClick,
      },
    ]
    render(<Options options={options} />)

    const button = screen.getByLabelText('Options')
    fireEvent.click(button)

    // Click on enabled option first
    const enabled = screen.getByText('Enabled Option')
    fireEvent.click(enabled)

    // onClick should be called once for enabled
    expect(onClick).toHaveBeenCalledTimes(1)

    // Open menu again and try clicking disabled
    fireEvent.click(button)
    const disabled = screen.getByText('Disabled Option').closest('li')

    // Disabled should have the class
    expect(disabled?.classList.contains('Mui-disabled')).toBe(true)
  })

  test('renders option with icon', () => {
    const icon = <span data-testid='test-icon'>Icon</span>
    const options = [
      {
        label: 'Option with Icon',
        icon,
        onClick: vi.fn(),
      },
    ]
    render(<Options options={options} />)

    const button = screen.getByLabelText('Options')
    fireEvent.click(button)

    expect(screen.getByTestId('test-icon')).toBeTruthy()
    expect(screen.getByText('Option with Icon')).toBeTruthy()
  })

  test('renders option without icon', () => {
    const options = [
      {
        label: 'Option without Icon',
        onClick: vi.fn(),
      },
    ]
    render(<Options options={options} />)

    const button = screen.getByLabelText('Options')
    fireEvent.click(button)

    expect(screen.getByText('Option without Icon')).toBeTruthy()
  })

  test('closes menu when clicking outside', () => {
    const options = [
      {
        label: 'Option 1',
        onClick: vi.fn(),
      },
    ]
    render(<Options options={options} />)

    const button = screen.getByLabelText('Options')
    fireEvent.click(button)

    // Menu should be open
    expect(screen.getByText('Option 1')).toBeTruthy()

    // Click outside (on the backdrop)
    const backdrop = document.querySelector('.MuiBackdrop-root')
    if (backdrop) {
      fireEvent.click(backdrop)
    }

    // Menu should be closed
    expect(screen.queryByRole('menu')).toBeNull()
  })

  test('handles multiple option clicks correctly', () => {
    const onClick1 = vi.fn()
    const onClick2 = vi.fn()
    const options = [
      {
        label: 'Option 1',
        onClick: onClick1,
      },
      {
        label: 'Option 2',
        onClick: onClick2,
      },
    ]
    render(<Options options={options} />)

    // Open menu and click first option
    const button = screen.getByLabelText('Options')
    fireEvent.click(button)
    fireEvent.click(screen.getByText('Option 1'))

    expect(onClick1).toHaveBeenCalledTimes(1)
    expect(onClick2).not.toHaveBeenCalled()

    // Open menu again and click second option
    fireEvent.click(button)
    fireEvent.click(screen.getByText('Option 2'))

    expect(onClick1).toHaveBeenCalledTimes(1)
    expect(onClick2).toHaveBeenCalledTimes(1)
  })

  test('renders MoreVert icon', () => {
    const options = [
      {
        label: 'Option 1',
        onClick: vi.fn(),
      },
    ]
    render(<Options options={options} />)

    // Check that the button is rendered
    const button = screen.getByLabelText('Options')
    expect(button).toBeTruthy()
  })

  test('menu has correct attributes', () => {
    const options = [
      {
        label: 'Option 1',
        onClick: vi.fn(),
      },
    ]
    render(<Options options={options} />)

    const button = screen.getByLabelText('Options')
    expect(button.getAttribute('aria-label')).toBe('Options')
    expect(button.getAttribute('aria-controls')).toBe('options-menu')
    expect(button.getAttribute('aria-haspopup')).toBe('true')
  })
})
