'use client'

import { useState, useRef, useEffect, useCallback } from 'react'
import { createPortal } from 'react-dom'
import { ChevronDown, Check } from 'lucide-react'
import { cn } from '@/lib/utils'

export interface SelectOption {
  value: string
  label: string
  /** 禁用项：展示但不可选（用于标注"暂未启用"等） */
  disabled?: boolean
}

interface CustomSelectProps {
  value: string
  onChange: (value: string) => void
  options: SelectOption[]
  placeholder?: string
  className?: string
  size?: 'sm' | 'md'
}

export function CustomSelect({
  value,
  onChange,
  options,
  placeholder = 'Select...',
  className,
  size = 'md',
}: CustomSelectProps) {
  const [open, setOpen] = useState(false)
  const triggerRef = useRef<HTMLButtonElement>(null)
  const dropdownRef = useRef<HTMLDivElement>(null)
  const [pos, setPos] = useState({ top: 0, left: 0, width: 0 })

  // Calculate dropdown position from trigger button
  const updatePosition = useCallback(() => {
    if (!triggerRef.current) return
    const rect = triggerRef.current.getBoundingClientRect()
    const dropdownHeight = 140 // approximate max height for 3 items
    const spaceBelow = window.innerHeight - rect.bottom
    // If not enough space below, position above the trigger
    const top = spaceBelow < dropdownHeight
      ? rect.top - dropdownHeight - 4
      : rect.bottom + 4
    setPos({ top, left: rect.left, width: rect.width })
  }, [])

  // Recalculate position when opening
  useEffect(() => {
    if (open) updatePosition()
  }, [open, updatePosition])

  // Close on outside click (check both trigger and dropdown)
  useEffect(() => {
    if (!open) return
    const handler = (e: MouseEvent) => {
      const target = e.target as Node
      if (
        triggerRef.current && !triggerRef.current.contains(target) &&
        dropdownRef.current && !dropdownRef.current.contains(target)
      ) {
        setOpen(false)
      }
    }
    document.addEventListener('mousedown', handler)
    return () => document.removeEventListener('mousedown', handler)
  }, [open])

  // Close on scroll or resize (position becomes stale)
  useEffect(() => {
    if (!open) return
    const handleScroll = (e: Event) => {
      // Don't close if scrolling inside the dropdown itself
      if (dropdownRef.current?.contains(e.target as Node)) return
      setOpen(false)
    }
    const handleResize = () => setOpen(false)
    window.addEventListener('scroll', handleScroll, true)
    window.addEventListener('resize', handleResize)
    return () => {
      window.removeEventListener('scroll', handleScroll, true)
      window.removeEventListener('resize', handleResize)
    }
  }, [open])

  const selected = options.find((o) => o.value === value)
  const h = size === 'sm' ? 'h-9' : 'h-10'

  return (
    <div className={cn('relative', className)}>
      <button
        ref={triggerRef}
        type="button"
        role="combobox"
        aria-haspopup="listbox"
        aria-expanded={open}
        onClick={() => setOpen(!open)}
        className={cn(
          'w-full min-w-0 flex items-center justify-between gap-2 px-4 rounded-panel bg-surface-2 border border-hairline text-[13px] outline-none transition-colors',
          'focus-visible:shadow-focus-ring',
          open ? 'border-brand-primary' : 'hover:border-hairline-strong',
          h,
        )}
      >
        <span
          className={cn(
            'min-w-0 flex-1 truncate text-left whitespace-nowrap',
            selected ? 'text-ink' : 'text-ink-tertiary',
          )}
          title={selected?.label || placeholder}
        >
          {selected?.label || placeholder}
        </span>
        <ChevronDown
          size={14}
          className={cn('text-ink-tertiary shrink-0 transition-transform', open && 'rotate-180')}
        />
      </button>

      {open && createPortal(
        <div
          ref={dropdownRef}
          role="listbox"
          className="fixed popover-styled py-1 max-h-[200px] overflow-y-auto animate-slide-down"
          style={{ top: pos.top, left: pos.left, width: pos.width, zIndex: 9999 }}
        >
          {options.map((opt) => (
            <button
              key={opt.value}
              type="button"
              role="option"
              aria-selected={opt.value === value}
              disabled={opt.disabled}
              onClick={() => {
                if (opt.disabled) return
                onChange(opt.value)
                setOpen(false)
              }}
              className={cn(
                'flex items-center justify-between gap-2 w-full px-4 py-2 text-[13px] transition-colors',
                opt.disabled
                  ? 'text-ink-tertiary/50 cursor-not-allowed'
                  : opt.value === value
                    ? 'text-ink bg-surface-3'
                    : 'text-ink-muted hover:bg-surface-2 hover:text-ink',
              )}
              title={opt.label}
            >
              <span className="min-w-0 flex-1 truncate text-left whitespace-nowrap">{opt.label}</span>
              {opt.value === value && <Check size={14} className="text-green shrink-0" />}
            </button>
          ))}
        </div>,
        document.body,
      )}
    </div>
  )
}
