import { useEffect } from 'react'

import { Checkbox } from '../checkbox'
import { KeyboardKeys, useStyleConfig, vui } from '../core'
import { List, ListItem } from '../list'
import { usePopoverContext } from '../popover'
import { cs, ellipsisOverflow, KeyboardEvent, MouseEvent, useCallbackRef } from '../utils'
import { useSelectContext } from './context'
import { SelectOptionProps } from './select.types'

/**
 * Displays a select option as a list item. By default, closes popover when option is selected.
 * In multi-select mode, displays a checkbox and doesn't close popover.
 * 'onChange' is triggered with a modified click event, which adds 'value' and 'name' properties.
 */
export const SelectOption = vui<'li', SelectOptionProps>((props, ref) => {
  const { children, closeOnScroll, className, disabled, title, onClick: onClickProp, value: valueProp, ...rest } = props
  const { instance } = usePopoverContext() ?? {}
  const { isMultiple, name, onChange, value } = useSelectContext() ?? {}
  const styles = useStyleConfig('Select', useSelectContext())

  const isSelected = Array.isArray(value) && valueProp ? value.includes(valueProp) : value === valueProp

  const hide = () => instance?.hide()

  const onClick = useCallbackRef((e: MouseEvent<HTMLLIElement> | KeyboardEvent<HTMLLIElement>) => {
    const nativeEvent = e.nativeEvent || e
    const clonedEvent = new (nativeEvent.constructor as any)(nativeEvent.type, nativeEvent)

    Object.defineProperty(clonedEvent, 'target', {
      writable: true,
      value: { value: valueProp, name },
    })

    onClickProp?.(e as MouseEvent<HTMLLIElement>)
    onChange?.(clonedEvent)
    !isMultiple && hide()
  })

  const onKeyDown = useCallbackRef((e: KeyboardEvent<HTMLLIElement>) => e.key === KeyboardKeys.Enter && onClick(e))

  const onScroll = (e: Event) => !(e.target as HTMLElement)?.className?.includes('vui-allowScroll') && hide()

  // Hiding the popover on scroll
  useEffect(() => {
    if (closeOnScroll) document.addEventListener('scroll', onScroll, true)

    return () => {
      if (closeOnScroll) document.removeEventListener('scroll', onScroll, true)
    }
  }, [closeOnScroll])

  return (
    <ListItem
      activeBg="skyBlue.active"
      className={cs('vui-selectOption', className)}
      disabled={disabled}
      hoverBg="skyBlue.hover"
      isInteractive
      isSelected={isSelected}
      onClick={onClick}
      onKeyDown={onKeyDown}
      ref={ref}
      selectedBg="skyBlue.selected"
      tabIndex={0}
      title={title}
      value={valueProp}
      {...styles.option}
      {...rest}
      {...ellipsisOverflow}
    >
      {children ??
        (isMultiple && (
          <>
            <Checkbox checked={isSelected} disabled={disabled} mr={1} {...styles.option} />
            <List.Text>{props.text}</List.Text>
          </>
        ))}
    </ListItem>
  )
})

SelectOption.displayName = 'SelectOption'

export default SelectOption
