// src/components/ui/Select.jsx
// Fully-styled custom select — replaces the native <select> so the option list
// can be themed to match the rest of the design system.
//
// Used internally by FormField (type="select"). Can also be used standalone.
//
// Props:
//   value       — controlled value string
//   onChange    — (e) => void — called with a synthetic { target: { value } }
//   children    — <option> elements (same API as native <select>)
//   placeholder — shown when value is empty (default: 'Select…')
//   disabled    — boolean
//   className   — extra classes on the trigger button
//   id          — forwarded for label association
//   name        — forwarded (unused visually, kept for form semantics)

import { useState, useRef, useEffect, Children, isValidElement } from 'react'
import { createPortal } from 'react-dom'

// Parse React <option> children into a flat [{value, label, disabled}] array
function parseOptions(children) {
  const opts = []
  Children.forEach(children, child => {
    if (!isValidElement(child)) return
    if (child.type === 'option') {
      opts.push({
        value:    String(child.props.value ?? ''),
        label:    child.props.children ?? child.props.value ?? '',
        disabled: !!child.props.disabled,
      })
    }
    // Ignore <optgroup> for now — could be added later
  })
  return opts
}

export default function Select({
  value,
  onChange,
  children,
  placeholder = 'Select…',
  disabled = false,
  className = '',
  id,
  name,
  ...props
}) {
  const [open, setOpen]       = useState(false)
  const [menuPos, setMenuPos] = useState({ top: 0, left: 0, width: 0 })
  const triggerRef            = useRef(null)
  const menuRef               = useRef(null)

  const options  = parseOptions(children)
  const selected = options.find(o => o.value === String(value ?? ''))

  // ── Close on outside click / scroll ────────────────────────────────────────
  useEffect(() => {
    if (!open) return
    function close(e) {
      if (triggerRef.current?.contains(e.target)) return
      if (menuRef.current?.contains(e.target)) return
      setOpen(false)
    }
    function closeOnScroll(e) {
      if (menuRef.current?.contains(e.target)) return
      if (triggerRef.current?.contains(e.target)) return
      setOpen(false)
    }
    document.addEventListener('mousedown', close)
    document.addEventListener('scroll', closeOnScroll, true)
    return () => {
      document.removeEventListener('mousedown', close)
      document.removeEventListener('scroll', closeOnScroll, true)
    }
  }, [open])

  // ── Keyboard navigation ────────────────────────────────────────────────────
  function handleKeyDown(e) {
    if (disabled) return
    const curr = options.findIndex(o => o.value === String(value ?? ''))
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault()
      if (!open) {
        openMenu()
      } else {
        setOpen(false)
      }
    } else if (e.key === 'Escape') {
      setOpen(false)
      triggerRef.current?.focus()
    } else if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
      e.preventDefault()
      const dir   = e.key === 'ArrowDown' ? 1 : -1
      let   next  = curr + dir
      // Skip disabled
      while (next >= 0 && next < options.length && options[next].disabled) {
        next += dir
      }
      if (next >= 0 && next < options.length) {
        onChange?.({ target: { value: options[next].value, name } })
      }
    }
  }

  function openMenu() {
    if (disabled) return
    if (triggerRef.current) {
      const r = triggerRef.current.getBoundingClientRect()
      setMenuPos({ top: r.bottom + 4, left: r.left, width: r.width })
    }
    setOpen(true)
  }

  function handleToggle() {
    if (open) {
      setOpen(false)
    } else {
      openMenu()
    }
  }

  function handleSelect(opt) {
    if (opt.disabled) return
    onChange?.({ target: { value: opt.value, name } })
    setOpen(false)
    triggerRef.current?.focus()
  }

  const menu = open && createPortal(
    <div
      ref={menuRef}
      className="select-menu"
      style={{ top: menuPos.top, left: menuPos.left, width: menuPos.width }}
      role="listbox"
      aria-label="Options"
    >
      {options.map(opt => (
        <div
          key={opt.value}
          role="option"
          aria-selected={opt.value === String(value ?? '')}
          aria-disabled={opt.disabled || undefined}
          className={[
            'select-option',
            opt.value === String(value ?? '') ? 'select-option-selected' : '',
            opt.disabled                      ? 'select-option-disabled' : '',
          ].filter(Boolean).join(' ')}
          onMouseDown={e => { e.preventDefault(); handleSelect(opt) }}
        >
          {opt.value === String(value ?? '') && (
            <svg className="select-option-check" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <path d="M20 6L9 17l-5-5" />
            </svg>
          )}
          <span>{opt.label}</span>
        </div>
      ))}
    </div>,
    document.body
  )

  return (
    <>
      <button
        ref={triggerRef}
        type="button"
        id={id}
        name={name}
        disabled={disabled}
        onClick={handleToggle}
        onKeyDown={handleKeyDown}
        className={[
          'input',
          'select-trigger',
          open ? 'select-trigger-open' : '',
          className,
        ].filter(Boolean).join(' ')}
        aria-haspopup="listbox"
        aria-expanded={open}
        {...props}
      >
        <span className={selected ? 'select-value' : 'select-placeholder'}>
          {selected ? selected.label : placeholder}
        </span>
        <span className="select-chevron" aria-hidden="true">
          <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
            <path d="M4 6l4 4 4-4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
          </svg>
        </span>
      </button>
      {menu}
    </>
  )
}
