import * as React from 'react'

import { CheckIcon } from '@radix-ui/react-icons'
import { DataGridCellWrapper } from '@components/ui/data-grid/data-grid-cell-wrapper'
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from '@components/ui/command/command'
import { Popover, PopoverContent, PopoverTrigger } from '@components/ui/popover/popover'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@components/ui/select/select'
import { CellVariantProps } from './cell-variant-types'

export function SelectCell<TData>({
  cell,
  table,
  rowIndex,
  columnId,
  isFocused,
  isEditing,
  isSelected,
}: Readonly<CellVariantProps<TData, string>>) {
  const initialValue = cell.getValue()
  const [value, setValue] = React.useState(initialValue)
  const [open, setOpen] = React.useState(false)
  const containerRef = React.useRef<HTMLDivElement>(null)
  const inputRef = React.useRef<HTMLInputElement>(null)
  const meta = table.options.meta
  const cellOpts = cell.column.columnDef.meta?.cell
  const options = cellOpts?.variant === 'select' ? cellOpts.options : []
  const hasSearch = (cellOpts?.variant === 'select' && cellOpts?.hasSearch) ?? false
  const sideOffset = -(inputRef.current?.clientHeight ?? 0)

  const onValueChange = React.useCallback(
    (newValue: string) => {
      setValue(newValue)
      meta?.onDataUpdate?.({ rowIndex, columnId, value: newValue })
      meta?.onCellEditingStop?.()
    },
    [meta, rowIndex, columnId],
  )

  const onOpenChange = React.useCallback(
    (isOpen: boolean) => {
      setOpen(isOpen)
      if (!isOpen) {
        meta?.onCellEditingStop?.()
      }
    },
    [meta],
  )

  const onOpenAutoFocus: NonNullable<React.ComponentProps<typeof PopoverContent>['onOpenAutoFocus']> =
    React.useCallback((event) => {
      event.preventDefault()
      inputRef.current?.focus()
    }, [])

  const onWrapperKeyDown = React.useCallback(
    (event: React.KeyboardEvent<HTMLDivElement>) => {
      if (isEditing) {
        if (event.key === 'Escape') {
          event.preventDefault()
          setValue(initialValue)
          setOpen(false)
          meta?.onCellEditingStop?.()
        } else if (event.key === 'Tab') {
          event.preventDefault()
          setOpen(false)
          meta?.onCellEditingStop?.({
            direction: event.shiftKey ? 'left' : 'right',
          })
        }
      }
    },
    [isEditing, initialValue, meta],
  )

  React.useEffect(() => {
    setValue(initialValue)
  }, [initialValue])

  React.useEffect(() => {
    if (isEditing && !open) {
      setOpen(true)
    }
    if (isFocused && !isEditing && !meta?.searchOpen && !meta?.isScrolling && containerRef.current) {
      containerRef.current.focus()
    }
  }, [isFocused, isEditing, open, meta?.searchOpen, meta?.isScrolling])

  const displayLabel = options.find((opt) => opt.value === value)?.label ?? value

  let editingContent: React.ReactNode

  if (hasSearch) {
    editingContent = (
      <Popover open={open} onOpenChange={onOpenChange}>
        <PopoverTrigger asChild>
          <div className="size-full items-start text-start border-none p-0 shadow-none focus-visible:ring-0 dark:bg-transparent [&_svg]:hidden line-clamp-1">
            {displayLabel}
          </div>
        </PopoverTrigger>
        <PopoverContent
          data-grid-cell-editor=""
          align="start"
          sideOffset={sideOffset}
          className="max-w-[500px] w-full rounded-none p-0"
          onOpenAutoFocus={onOpenAutoFocus}
        >
          <Command>
            <CommandList>
              <CommandInput ref={inputRef} placeholder="Search..." className="h-auto flex-1 p-0" />
              <CommandEmpty>No results found.</CommandEmpty>
              <CommandGroup>
                {options.map((option) => (
                  <CommandItem
                    key={option.value}
                    onSelect={() => {
                      onValueChange(option.value)
                    }}
                  >
                    <span>{option.label}</span>
                    {value === option.value ? <CheckIcon className="ml-auto h-4 w-4" /> : null}
                  </CommandItem>
                ))}
              </CommandGroup>
            </CommandList>
          </Command>
        </PopoverContent>
      </Popover>
    )
  } else {
    editingContent = (
      <Select value={value} onValueChange={onValueChange} open={open} onOpenChange={onOpenChange}>
        <SelectTrigger className="size-full items-start text-start border-none p-0 shadow-none focus-visible:ring-0 dark:bg-transparent [&_svg]:hidden">
          <SelectValue />
        </SelectTrigger>
        <SelectContent
          data-grid-cell-editor=""
          // compensate for the wrapper padding
          align="start"
          alignOffset={-8}
          sideOffset={-2}
          className="min-w-[calc(var(--radix-select-trigger-width)+16px)]"
        >
          {options.map((option) => (
            <SelectItem key={option.value} value={option.value} spacing="sm">
              {option.label}
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
    )
  }

  return (
    <DataGridCellWrapper
      ref={containerRef}
      cell={cell}
      table={table}
      rowIndex={rowIndex}
      columnId={columnId}
      isEditing={isEditing}
      isFocused={isFocused}
      isSelected={isSelected}
      onKeyDown={onWrapperKeyDown}
    >
      {isEditing ? editingContent : <span data-slot="grid-cell-content">{displayLabel}</span>}
    </DataGridCellWrapper>
  )
}
