import { type ComponentType, type ReactNode } from 'react'
import * as RxSelect from '@radix-ui/react-select'
import { motion, AnimatePresence } from 'framer-motion'
import { Check, ChevronDown } from '../../lib/icons'

export interface SelectOption<V extends string = string> {
  value: V
  label: ReactNode
  /** Optional left icon component (Tabler / lucide-shaped: { size, stroke }) */
  icon?: ComponentType<{ size?: number; stroke?: number; className?: string }>
  /** Subtle dim of the row, e.g. for non-content items like "All genres" */
  muted?: boolean
}

interface Props<V extends string = string> {
  value: V
  onChange: (v: V) => void
  options: SelectOption<V>[]
  placeholder?: string
  size?: 'sm' | 'md'
  /** Optional leading icon shown in the trigger */
  triggerIcon?: ReactNode
  /** Tighten the trigger to fit narrow columns */
  width?: string
  /** Aria label for the trigger */
  ariaLabel?: string
  /** Render the dropdown portal inside this container instead of body */
  portalContainer?: HTMLElement | null
  disabled?: boolean
}

export default function Select<V extends string = string>({
  value,
  onChange,
  options,
  placeholder,
  size = 'md',
  triggerIcon,
  width,
  ariaLabel,
  portalContainer,
  disabled,
}: Props<V>) {
  const trigSize =
    size === 'sm'
      ? 'h-7 px-2.5 text-[11.5px] gap-1.5'
      : 'h-9 px-3 text-[12.5px] gap-2'
  const chevSize = size === 'sm' ? 12 : 14

  const selected = options.find(o => o.value === value)
  const SelectedIcon = selected?.icon

  return (
    <RxSelect.Root value={value} onValueChange={(v) => onChange(v as V)} disabled={disabled}>
      <RxSelect.Trigger
        aria-label={ariaLabel}
        className={`group inline-flex items-center justify-between rounded-md bg-elevated/60 hover:bg-elevated border border-border hover:border-border-hover text-text-1 transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/40 focus-visible:border-accent/50 disabled:opacity-50 disabled:cursor-not-allowed ${trigSize} ${width ?? 'min-w-[8rem]'}`}
      >
        <span className="inline-flex items-center min-w-0 gap-1.5">
          {triggerIcon && (
            <span className="text-text-3 group-hover:text-text-1 transition-colors shrink-0">
              {triggerIcon}
            </span>
          )}
          {SelectedIcon && (
            <SelectedIcon size={size === 'sm' ? 12 : 14} stroke={1.75} className="text-text-3 shrink-0" />
          )}
          <RxSelect.Value placeholder={<span className="text-text-3">{placeholder}</span>}>
            <span className={`truncate font-medium ${selected?.muted ? 'text-text-3' : ''}`}>
              {selected?.label ?? placeholder}
            </span>
          </RxSelect.Value>
        </span>
        <RxSelect.Icon className="text-text-3 group-hover:text-text-1 ml-2 shrink-0 transition-colors data-[state=open]:rotate-180">
          <ChevronDown size={chevSize} stroke={2} />
        </RxSelect.Icon>
      </RxSelect.Trigger>

      <RxSelect.Portal container={portalContainer ?? undefined}>
        <RxSelect.Content
          position="popper"
          sideOffset={6}
          align="start"
          className="z-dropdown overflow-hidden rounded-lg border border-border-hover bg-glass-strong backdrop-blur-xl shadow-[0_24px_60px_-12px_rgba(0,0,0,0.7)] focus:outline-none origin-[var(--radix-select-content-transform-origin)]"
        >
          <AnimatePresence>
            <motion.div
              initial={{ opacity: 0, y: -4, scale: 0.97 }}
              animate={{ opacity: 1, y: 0, scale: 1 }}
              transition={{ duration: 0.16, ease: [0.16, 1, 0.3, 1] }}
            >
              <RxSelect.Viewport className="p-1.5 max-h-[min(420px,var(--radix-select-content-available-height))] min-w-[var(--radix-select-trigger-width)]">
                {options.map(opt => (
                  <Item key={opt.value} option={opt} size={size} />
                ))}
              </RxSelect.Viewport>
            </motion.div>
          </AnimatePresence>
        </RxSelect.Content>
      </RxSelect.Portal>
    </RxSelect.Root>
  )
}

function Item<V extends string = string>({
  option,
  size,
}: {
  option: SelectOption<V>
  size: 'sm' | 'md'
}) {
  const { value, label, icon: Icon, muted } = option
  const sizeCls =
    size === 'sm'
      ? 'h-8 px-2 text-[12px] gap-2'
      : 'h-9 px-2.5 text-[13px] gap-2.5'
  const iconSize = size === 'sm' ? 14 : 15
  return (
    <RxSelect.Item
      value={value}
      className={`group relative flex items-center rounded-md cursor-pointer outline-none select-none transition-colors duration-100 data-[highlighted]:bg-glass-light data-[state=checked]:text-accent ${sizeCls} ${muted ? 'text-text-3' : 'text-text-1'}`}
    >
      <RxSelect.ItemIndicator className="absolute right-2 text-accent">
        <Check size={iconSize - 2} stroke={2.5} />
      </RxSelect.ItemIndicator>

      {Icon && (
        <span className="text-text-3 group-data-[highlighted]:text-text-1 group-data-[state=checked]:text-accent transition-colors shrink-0">
          <Icon size={iconSize} stroke={1.75} />
        </span>
      )}
      <RxSelect.ItemText asChild>
        <span className="flex-1 min-w-0 truncate font-medium tracking-tight pr-6">{label}</span>
      </RxSelect.ItemText>
    </RxSelect.Item>
  )
}
