import { useEffect, useRef, useState } from 'react'
import styles from './Select.module.css'

export interface SelectOption<T extends string | number = string> {
  value: T
  label: string
}

interface Props<T extends string | number> {
  value: T
  options: SelectOption<T>[]
  onChange: (value: T) => void
  label?: string
  placeholder?: string
  id?: string
  disabled?: boolean
}

export function Select<T extends string | number>({
  value,
  options,
  onChange,
  label,
  placeholder = 'Выберите',
  id,
  disabled,
}: Props<T>) {
  const [open, setOpen] = useState(false)
  const ref = useRef<HTMLDivElement>(null)

  const selected = options.find((o) => o.value === value)

  useEffect(() => {
    if (!open) return
    const handlePointer = (e: MouseEvent) => {
      if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false)
    }
    const handleKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') setOpen(false)
    }
    document.addEventListener('mousedown', handlePointer)
    document.addEventListener('keydown', handleKey)
    return () => {
      document.removeEventListener('mousedown', handlePointer)
      document.removeEventListener('keydown', handleKey)
    }
  }, [open])

  return (
    <div className={styles.field} ref={ref}>
      {label && (
        <label className={styles.label} htmlFor={id}>
          {label}
        </label>
      )}
      <button
        type="button"
        id={id}
        className={`${styles.trigger} ${open ? styles.triggerOpen : ''}`}
        onClick={() => !disabled && setOpen((v) => !v)}
        disabled={disabled}
        aria-haspopup="listbox"
        aria-expanded={open}
      >
        <span className={selected ? styles.value : styles.placeholder}>
          {selected ? selected.label : placeholder}
        </span>
        <span className={`${styles.arrow} ${open ? styles.arrowOpen : ''}`} aria-hidden>
          ▾
        </span>
      </button>
      {open && (
        <ul className={styles.dropdown} role="listbox">
          {options.map((o) => (
            <li
              key={String(o.value)}
              role="option"
              aria-selected={o.value === value}
              className={`${styles.option} ${o.value === value ? styles.optionSelected : ''}`}
              onClick={() => {
                onChange(o.value)
                setOpen(false)
              }}
            >
              {o.label}
            </li>
          ))}
        </ul>
      )}
    </div>
  )
}
