import '@testing-library/jest-dom'
import { axe, toHaveNoViolations } from 'jest-axe'
import { fireEvent } from '@testing-library/dom'
import { vi } from 'vitest'

expect.extend(toHaveNoViolations)

import './combobox'
import { PktCombobox } from './combobox'
import type { IPktComboboxOption } from './combobox'

const waitForCustomElements = async () => {
  await customElements.whenDefined('pkt-combobox')
}

// Helper function to create combobox markup
const createCombobox = async (comboboxProps = '', options = '') => {
  const container = document.createElement('div')
  container.innerHTML = `
    <pkt-combobox ${comboboxProps}>
      ${options}
    </pkt-combobox>
  `
  document.body.appendChild(container)
  await waitForCustomElements()
  return container
}

// Helper function to create options
const createOptions = (optionData: { value: string; label?: string; disabled?: boolean }[]) => {
  return optionData
    .map(
      (opt) =>
        `<option value="${opt.value}" ${opt.disabled ? 'disabled' : ''}>${opt.label || opt.value}</option>`,
    )
    .join('')
}

// Cleanup after each test
afterEach(() => {
  document.body.innerHTML = ''
})

describe('PktCombobox', () => {
  describe('Rendering and basic functionality', () => {
    test('renders without errors', async () => {
      const container = await createCombobox('id="test-combobox" name="test" label="Test Combobox"')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      expect(combobox).toBeInTheDocument()

      await combobox.updateComplete
      expect(combobox).toBeTruthy()

      const wrapper = combobox.querySelector('pkt-input-wrapper')
      const comboboxDiv = combobox.querySelector('.pkt-combobox')
      expect(wrapper).toBeInTheDocument()
      expect(comboboxDiv).toBeInTheDocument()
    })

    test('renders with correct structure', async () => {
      const container = await createCombobox('id="test" name="test" label="Test Label"')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const wrapper = combobox.querySelector('pkt-input-wrapper')
      const comboboxDiv = wrapper?.querySelector('.pkt-combobox')
      const inputDiv = comboboxDiv?.querySelector('.pkt-combobox__input')
      const arrowIcon = inputDiv?.querySelector('.pkt-combobox__arrow-icon')
      const listbox = comboboxDiv?.querySelector('pkt-listbox')

      expect(wrapper).toBeInTheDocument()
      expect(comboboxDiv).toBeInTheDocument()
      expect(inputDiv).toBeInTheDocument()
      expect(arrowIcon).toBeInTheDocument()
      expect(listbox).toBeInTheDocument()
    })

    test('renders select-only combobox with correct ARIA attributes', async () => {
      const container = await createCombobox('id="test-arrow" name="test" label="Test"')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const comboboxInput = combobox.querySelector('.pkt-combobox__input')
      const icon = comboboxInput?.querySelector('pkt-icon')

      expect(comboboxInput?.getAttribute('id')).toBe('test-arrow-combobox')
      expect(comboboxInput?.getAttribute('aria-expanded')).toBe('false')
      expect(comboboxInput?.getAttribute('aria-controls')).toBe('test-arrow-listbox')
      expect(comboboxInput?.getAttribute('aria-haspopup')).toBe('listbox')
      expect(comboboxInput?.getAttribute('aria-labelledby')).toBe('test-arrow-combobox-label')
      expect(comboboxInput?.getAttribute('role')).toBe('combobox')
      expect(icon?.getAttribute('name')).toBe('chevron-thin-down')
    })
  })

  describe('Properties and attributes', () => {
    test('applies default properties correctly', async () => {
      const container = await createCombobox('id="test" name="test"')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      expect(combobox.value).toBe('')
      expect(combobox.allowUserInput).toBe(false)
      expect(combobox.typeahead).toBe(false)
      expect(combobox.includeSearch).toBe(false)
      expect(combobox.multiple).toBe(false)
      expect(combobox.disabled).toBe(false)
      expect(combobox.options).toEqual([])
      expect(combobox.tagPlacement).toBe(null)
      expect(combobox.maxlength).toBe(null)
      expect(combobox.displayValueAs).toBe('label')
    })

    test('handles multiple property correctly', async () => {
      const container = await createCombobox('id="test" name="test" multiple')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      expect(combobox.multiple).toBe(true)

      const listbox = combobox.querySelector('pkt-listbox')
      expect(listbox?.hasAttribute('is-multi-select')).toBe(true)
    })

    test('handles allowUserInput property correctly', async () => {
      const container = await createCombobox('id="test" name="test" allow-user-input')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      expect(combobox.allowUserInput).toBe(true)

      const input = combobox.querySelector('input[type="text"]')
      expect(input).toBeInTheDocument()
      expect(input?.getAttribute('role')).toBe('combobox')
    })

    test('handles typeahead property correctly', async () => {
      const container = await createCombobox('id="test" name="test" typeahead')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      expect(combobox.typeahead).toBe(true)

      const input = combobox.querySelector('input[type="text"]')
      expect(input).toBeInTheDocument()
      expect(input?.getAttribute('aria-autocomplete')).toBe('both')
    })

    test('handles includeSearch property correctly', async () => {
      const container = await createCombobox('id="test" name="test" include-search')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      expect(combobox.includeSearch).toBe(true)

      const listbox = combobox.querySelector('pkt-listbox')
      expect(listbox?.hasAttribute('include-search')).toBe(true)
    })

    test('handles disabled property correctly', async () => {
      const container = await createCombobox('id="test" name="test" disabled')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      expect(combobox.disabled).toBe(true)

      const comboboxInput = combobox.querySelector('.pkt-combobox__input')
      expect(comboboxInput).toHaveClass('pkt-combobox__input--disabled')
      expect(comboboxInput?.getAttribute('tabindex')).toBe('-1')
    })

    test('handles fullwidth property correctly', async () => {
      const container = await createCombobox('id="test" name="test" fullwidth')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      expect(combobox.fullwidth).toBe(true)

      const inputDiv = combobox.querySelector('.pkt-combobox__input')
      expect(inputDiv).toHaveClass('pkt-combobox__input--fullwidth')
    })
  })

  describe('Options handling', () => {
    test('handles options provided via property', async () => {
      const testOptions: IPktComboboxOption[] = [
        { value: 'option1', label: 'Option 1' },
        { value: 'option2', label: 'Option 2' },
        { value: 'option3', label: 'Option 3', disabled: true },
      ]

      const container = await createCombobox('id="test" name="test"')
      const combobox = container.querySelector('pkt-combobox') as PktCombobox

      // Set options via property
      combobox.options = testOptions
      await combobox.updateComplete

      // Ensure listbox has also updated
      const listbox = combobox.querySelector('pkt-listbox') as any
      await listbox?.updateComplete

      expect(combobox.options).toHaveLength(3)
      expect(combobox.options[0].value).toBe('option1')
      expect(combobox.options[0].label).toBe('Option 1')
      expect(combobox.options[2].disabled).toBe(true)

      expect(listbox?.options).toEqual(
        expect.arrayContaining([expect.objectContaining({ value: 'option1', label: 'Option 1' })]),
      )
    })

    test('handles options provided via slot', async () => {
      const optionsMarkup = createOptions([
        { value: 'value1', label: 'Label 1' },
        { value: 'value2', label: 'Label 2' },
      ])

      const container = await createCombobox('id="test" name="test"', optionsMarkup)
      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      // Options should be extracted from slot
      expect(combobox.options.length).toBeGreaterThan(0)
      expect(combobox.options.some((opt) => opt.value === 'value1')).toBe(true)
      expect(combobox.options.some((opt) => opt.value === 'value2')).toBe(true)
    })

    test('handles defaultOptions property', async () => {
      const defaultOptions: IPktComboboxOption[] = [
        { value: 'default1', label: 'Default 1' },
        { value: 'default2', label: 'Default 2' },
      ]

      const container = await createCombobox('id="test" name="test"')
      const combobox = container.querySelector('pkt-combobox') as PktCombobox

      combobox.defaultOptions = defaultOptions
      await combobox.updateComplete

      expect(combobox.options).toHaveLength(2)
      expect(combobox.options[0].value).toBe('default1')
      expect(combobox.options[1].value).toBe('default2')
    })

    test('preserves userAdded options when defaultOptions change', async () => {
      const container = await createCombobox('id="test" name="test" allow-user-input')
      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      // Add a user option
      const userOption: IPktComboboxOption = {
        value: 'user-added',
        label: 'User Added',
        userAdded: true,
      }
      combobox.options = [userOption]
      await combobox.updateComplete

      // Set default options
      const defaultOptions: IPktComboboxOption[] = [{ value: 'default1', label: 'Default 1' }]
      combobox.defaultOptions = defaultOptions
      await combobox.updateComplete

      // Should have both user-added and default options
      expect(combobox.options).toHaveLength(2)
      expect(combobox.options.some((opt) => opt.userAdded)).toBe(true)
      expect(combobox.options.some((opt) => opt.value === 'default1')).toBe(true)
    })

    test('preserves userAdded option when parent replaces options by overwriting options property', async () => {
      const container = await createCombobox('id="test" name="test" allow-user-input')
      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete
      ;(combobox as any).addNewUserValue('userAdded')
      await combobox.updateComplete

      expect(combobox.options.some((o: any) => o.value === 'userAdded' && o.userAdded)).toBe(true)
      expect(combobox['_value']).toContain('userAdded')

      combobox.options = [{ value: 'external1', label: 'External 1' }]
      await combobox.updateComplete

      const hasUserAdded = combobox.options.some((o: any) => o.value === 'userAdded' && o.userAdded)
      const hasExternal = combobox.options.some((o: any) => o.value === 'external1')

      expect(hasExternal).toBe(true)
      expect(hasUserAdded).toBe(true)

      expect(combobox['_value']).toContain('userAdded')
    })
  })

  describe('Value handling', () => {
    test('handles single value correctly', async () => {
      const container = await createCombobox('id="test" name="test" value="test-value"')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      expect(combobox.value).toBe('test-value')

      // Internal _value should be an array with single item
      expect(combobox['_value']).toEqual(['test-value'])
    })

    test('handles multiple values correctly', async () => {
      const container = await createCombobox('id="test" name="test" value="value1,value2" multiple')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      expect(combobox.value).toBe('value1,value2')
      expect(combobox['_value']).toEqual(['value1', 'value2'])
    })

    test('handles array value correctly', async () => {
      const container = await createCombobox('id="test" name="test" multiple')
      const combobox = container.querySelector('pkt-combobox') as PktCombobox

      combobox.value = ['array1', 'array2']
      await combobox.updateComplete

      expect(combobox['_value']).toEqual(['array1', 'array2'])
    })

    test('limits to single value when not multiple', async () => {
      const container = await createCombobox('id="test" name="test"')
      const combobox = container.querySelector('pkt-combobox') as PktCombobox

      combobox.value = ['value1', 'value2']
      await combobox.updateComplete

      // Should only keep the first value when not multiple
      expect(combobox['_value']).toEqual(['value1'])
    })
  })

  describe('Placeholder functionality', () => {
    test('shows placeholder when no value selected', async () => {
      const container = await createCombobox('id="test" name="test" placeholder="Select an option"')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      expect(combobox.placeholder).toBe('Select an option')

      const placeholder = combobox.querySelector('.pkt-combobox__placeholder')
      expect(placeholder).toBeInTheDocument()
      expect(placeholder?.textContent).toBe('Select an option')
    })

    test('hides placeholder when value is selected', async () => {
      const testOptions: IPktComboboxOption[] = [{ value: 'option1', label: 'Option 1' }]

      const container = await createCombobox(
        'id="test" name="test" placeholder="Select an option" value="option1"',
      )
      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      combobox.options = testOptions
      await combobox.updateComplete

      const placeholder = combobox.querySelector('.pkt-combobox__placeholder')
      expect(placeholder).not.toBeInTheDocument()
    })

    test('shows placeholder in multiple mode with outside tag placement', async () => {
      const container = await createCombobox(
        'id="test" name="test" placeholder="Select options" multiple tag-placement="outside"',
      )

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const placeholder = combobox.querySelector('.pkt-combobox__placeholder')
      expect(placeholder).toBeInTheDocument()
      expect(placeholder?.textContent).toBe('Select options')
    })
  })

  describe('Tag placement functionality', () => {
    test('renders tags inside input by default in multiple mode', async () => {
      const testOptions: IPktComboboxOption[] = [{ value: 'option1', label: 'Option 1' }]

      const container = await createCombobox('id="test" name="test" multiple value="option1"')
      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      combobox.options = testOptions
      await combobox.updateComplete

      const outsideTags = combobox.querySelector('.pkt-combobox__tags-outside')
      expect(outsideTags).not.toBeInTheDocument()
    })

    test('renders tags outside input when tagPlacement is outside', async () => {
      const testOptions: IPktComboboxOption[] = [{ value: 'option1', label: 'Option 1' }]

      const container = await createCombobox(
        'id="test" name="test" multiple tag-placement="outside" value="option1"',
      )
      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      combobox.options = testOptions
      await combobox.updateComplete

      const outsideTags = combobox.querySelector('.pkt-combobox__tags-outside')
      expect(outsideTags).toBeInTheDocument()
    })
  })

  describe('Input field functionality', () => {
    test('renders hidden input when not allowUserInput or typeahead', async () => {
      const container = await createCombobox('id="test" name="test-name"')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const hiddenInput = combobox.querySelector('input[type="hidden"]')
      const textInput = combobox.querySelector('input[type="text"]')

      expect(hiddenInput).toBeInTheDocument()
      expect(textInput).not.toBeInTheDocument()
      expect(hiddenInput?.getAttribute('id')).toBe('test-input')
      expect(hiddenInput?.getAttribute('name')).toBe('test-name-input')
    })

    test('renders text input when allowUserInput is true', async () => {
      const container = await createCombobox('id="test" name="test-name" allow-user-input')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const textInput = combobox.querySelector('input[type="text"]')
      const hiddenInput = combobox.querySelector('input[type="hidden"]')

      expect(textInput).toBeInTheDocument()
      expect(hiddenInput).not.toBeInTheDocument()
      expect(textInput?.getAttribute('id')).toBe('test-input')
      expect(textInput?.getAttribute('name')).toBe('test-name-input')
      expect(textInput?.getAttribute('role')).toBe('combobox')
      expect(textInput?.getAttribute('aria-controls')).toBe('test-listbox')
    })

    test('renders text input when typeahead is true', async () => {
      const container = await createCombobox('id="test" name="test" typeahead')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const textInput = combobox.querySelector('input[type="text"]')
      expect(textInput).toBeInTheDocument()
      expect(textInput?.getAttribute('aria-autocomplete')).toBe('both')
    })

    test('sets correct aria-autocomplete for allowUserInput', async () => {
      const container = await createCombobox('id="test" name="test" allow-user-input')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const textInput = combobox.querySelector('input[type="text"]')
      expect(textInput?.getAttribute('aria-autocomplete')).toBe('list')
    })
  })

  describe('Dropdown functionality', () => {
    test('opens dropdown when arrow button is clicked', async () => {
      const container = await createCombobox('id="test" name="test"')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const arrowButton = combobox.querySelector('.pkt-combobox__input')
      const inputDiv = combobox.querySelector('.pkt-combobox__input')

      expect(combobox['_isOptionsOpen']).toBe(false)
      expect(arrowButton?.getAttribute('aria-expanded')).toBe('false')
      expect(inputDiv).not.toHaveClass('pkt-combobox__input--open')

      // Click arrow to open
      fireEvent.click(arrowButton!)
      await combobox.updateComplete

      expect(combobox['_isOptionsOpen']).toBe(true)
      expect(arrowButton?.getAttribute('aria-expanded')).toBe('true')
      expect(inputDiv).toHaveClass('pkt-combobox__input--open')
    })

    test('toggles dropdown state with multiple clicks', async () => {
      const container = await createCombobox('id="test" name="test"')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const arrowButton = combobox.querySelector('.pkt-combobox__input')

      // Click to open
      fireEvent.click(arrowButton!)
      await combobox.updateComplete
      expect(combobox['_isOptionsOpen']).toBe(true)

      // Click to close
      fireEvent.click(arrowButton!)
      await combobox.updateComplete
      expect(combobox['_isOptionsOpen']).toBe(false)
    })

    test('does not open when disabled', async () => {
      const container = await createCombobox('id="test" name="test" disabled')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const arrowButton = combobox.querySelector('.pkt-combobox__input')

      // Try to click when disabled
      fireEvent.click(arrowButton!)
      await combobox.updateComplete

      expect(combobox['_isOptionsOpen']).toBe(false)
    })
  })

  describe('Search functionality', () => {
    test('handles search input when includeSearch is true', async () => {
      const container = await createCombobox('id="test" name="test" include-search')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const listbox = combobox.querySelector('pkt-listbox')
      expect(listbox?.hasAttribute('include-search')).toBe(true)
    })

    test('sets search placeholder correctly', async () => {
      const container = await createCombobox(
        'id="test" name="test" include-search search-placeholder="Search items..."',
      )

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      expect(combobox.searchPlaceholder).toBe('Search items...')

      const listbox = combobox.querySelector('pkt-listbox') as any
      expect(listbox?.searchPlaceholder).toBe('Search items...')
    })
  })

  describe('Keyboard navigation', () => {
    test('handles keyboard events on arrow button', async () => {
      const container = await createCombobox('id="test" name="test"')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const arrowButton = combobox.querySelector('.pkt-combobox__input')

      // Test Enter key
      fireEvent.keyDown(arrowButton!, { key: 'Enter' })
      await combobox.updateComplete

      expect(combobox['_isOptionsOpen']).toBe(true)

      // Test Space key
      fireEvent.keyDown(arrowButton!, { key: ' ' })
      await combobox.updateComplete

      expect(combobox['_isOptionsOpen']).toBe(false)
    })

    test('handles input focus for text inputs', async () => {
      const container = await createCombobox('id="test" name="test" allow-user-input')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const textInput = combobox.querySelector('input[type="text"]')

      // Test focus event
      fireEvent.focus(textInput!)
      await combobox.updateComplete

      // Test blur event
      fireEvent.blur(textInput!)
      await combobox.updateComplete

      // Should not throw errors
      expect(combobox).toBeInTheDocument()
    })
  })

  describe('Max length functionality', () => {
    test('handles maxlength property correctly', async () => {
      const container = await createCombobox('id="test" name="test" multiple maxlength="3"')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      expect(combobox.maxlength).toBe(3)

      const listbox = combobox.querySelector('pkt-listbox') as any
      expect(listbox?.maxLength).toBe(3)
    })

    test('disables user input when max is reached', async () => {
      const testOptions: IPktComboboxOption[] = [
        { value: 'option1', label: 'Option 1' },
        { value: 'option2', label: 'Option 2' },
        { value: 'option3', label: 'Option 3' },
      ]

      const container = await createCombobox(
        'id="test" name="test" multiple allow-user-input maxlength="2"',
      )
      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      combobox.options = testOptions
      combobox.value = ['option1', 'option2'] // Set to max
      await combobox.updateComplete

      const listbox = combobox.querySelector('pkt-listbox') as any
      await listbox?.updateComplete

      expect(listbox?.maxIsReached).toBe(true)
    })
  })

  describe('Error handling', () => {
    test('applies error styling when hasError is true', async () => {
      const container = await createCombobox('id="test" name="test"')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      combobox.hasError = true
      await combobox.updateComplete

      const inputDiv = combobox.querySelector('.pkt-combobox__input')
      expect(inputDiv).toHaveClass('pkt-combobox__input--error')
    })

    test('passes error state to input wrapper', async () => {
      const container = await createCombobox('id="test" name="test" error-message="Test error"')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      combobox.hasError = true
      await combobox.updateComplete

      const wrapper = combobox.querySelector('pkt-input-wrapper')
      expect(wrapper?.hasAttribute('haserror')).toBe(true)
    })
  })

  describe('Accessibility', () => {
    test('has no accessibility violations', async () => {
      const container = await createCombobox(
        'id="accessible-combobox" name="test" label="Accessible Combobox"',
      )

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const results = await axe(combobox)
      expect(results).toHaveNoViolations()
    })

    test('sets correct ARIA attributes on select-only combobox', async () => {
      const container = await createCombobox('id="test-aria" name="test" label="Test"')

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const comboboxInput = combobox.querySelector('.pkt-combobox__input')
      expect(comboboxInput?.getAttribute('role')).toBe('combobox')
      expect(comboboxInput?.getAttribute('aria-controls')).toBe('test-aria-listbox')
      expect(comboboxInput?.getAttribute('aria-haspopup')).toBe('listbox')
      expect(comboboxInput?.getAttribute('aria-expanded')).toBe('false')
      expect(comboboxInput?.getAttribute('aria-labelledby')).toBe('test-aria-combobox-label')
    })

    test('sets correct ARIA attributes on text input', async () => {
      const container = await createCombobox(
        'id="test-input" name="test" label="Test Label" allow-user-input',
      )

      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const textInput = combobox.querySelector('input[type="text"]')
      expect(textInput?.getAttribute('role')).toBe('combobox')
      expect(textInput?.getAttribute('aria-controls')).toBe('test-input-listbox')
      expect(textInput?.getAttribute('aria-label')).toBe('Test Label')
      expect(textInput?.getAttribute('aria-autocomplete')).toBe('list')
    })

    test('sets correct aria-activedescendant when value is selected', async () => {
      const testOptions: IPktComboboxOption[] = [{ value: 'option1', label: 'Option 1' }]

      const container = await createCombobox(
        'id="test" name="test" allow-user-input value="option1"',
      )
      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      combobox.options = testOptions
      await combobox.updateComplete

      const textInput = combobox.querySelector('input[type="text"]')
      expect(textInput?.getAttribute('aria-activedescendant')).toBe('test-listbox--1')
    })
  })

  describe('Event handling', () => {
    test('dispatches search event when search value changes', async () => {
      const container = await createCombobox('id="test" name="test" include-search')
      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const searchEventSpy = vi.fn()
      combobox.addEventListener('search', searchEventSpy)

      // Simulate search change
      combobox['_search'] = 'test search'
      await combobox.updateComplete

      expect(searchEventSpy).toHaveBeenCalledWith(
        expect.objectContaining({
          detail: 'test search',
        }),
      )
    })

    test('handles listbox events correctly', async () => {
      const container = await createCombobox('id="test" name="test"')
      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      const listbox = combobox.querySelector('pkt-listbox')

      // Test close-options event
      fireEvent(listbox!, new CustomEvent('close-options'))
      await combobox.updateComplete

      expect(combobox['_isOptionsOpen']).toBe(false)
    })
  })

  describe('Dynamic slot options', () => {
    test('picks up dynamically added <option> children', async () => {
      const container = await createCombobox(
        'id="dynamic" name="dynamic"',
        createOptions([
          { value: 'a', label: 'A' },
          { value: 'b', label: 'B' },
        ]),
      )
      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      expect(combobox['_options']).toHaveLength(2)

      // Add a new option element to the DOM
      const newOption = document.createElement('option')
      newOption.value = 'c'
      newOption.textContent = 'C'
      combobox.appendChild(newOption)

      // Wait for MutationObserver + Lit update
      await combobox.updateComplete
      await new Promise((r) => setTimeout(r, 0))
      await combobox.updateComplete

      expect(combobox['_options']).toHaveLength(3)
      expect(combobox['_options'].some((o: IPktComboboxOption) => o.value === 'c')).toBe(true)
    })

    test('picks up dynamically removed <option> children', async () => {
      const container = await createCombobox(
        'id="dynamic" name="dynamic"',
        createOptions([
          { value: 'a', label: 'A' },
          { value: 'b', label: 'B' },
          { value: 'c', label: 'C' },
        ]),
      )
      const combobox = container.querySelector('pkt-combobox') as PktCombobox
      await combobox.updateComplete

      expect(combobox['_options']).toHaveLength(3)

      // Remove the last option element
      const options = combobox.querySelectorAll('option')
      combobox.removeChild(options[options.length - 1])

      // Wait for MutationObserver + Lit update
      await combobox.updateComplete
      await new Promise((r) => setTimeout(r, 0))
      await combobox.updateComplete

      expect(combobox['_options']).toHaveLength(2)
      expect(combobox['_options'].some((o: IPktComboboxOption) => o.value === 'c')).toBe(false)
    })
  })
})
