import * as React from 'react'

import { DataGridCellWrapper } from '@components/ui/data-grid/data-grid-cell-wrapper'
import { useDebouncedCallback } from '@components/ui/data-grid/hooks/use-debounced-callback'
import { Popover, PopoverAnchor, PopoverContent } from '@components/ui/popover/popover'
import { Textarea } from '@components/ui/textarea/textarea'
import { CellVariantProps } from './cell-variant-types'

export function LongTextCell<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 textareaRef = React.useRef<HTMLTextAreaElement>(null)
  const containerRef = React.useRef<HTMLDivElement>(null)
  const meta = table.options.meta
  const sideOffset = -(containerRef.current?.clientHeight ?? 0)

  const prevInitialValueRef = React.useRef(initialValue)
  if (initialValue !== prevInitialValueRef.current) {
    prevInitialValueRef.current = initialValue
    setValue(initialValue ?? '')
  }

  // Debounced auto-save (300ms delay)
  const debouncedSave = useDebouncedCallback((newValue: string) => {
    meta?.onDataUpdate?.({ rowIndex, columnId, value: newValue })
  }, 300)

  const onSave = React.useCallback(() => {
    // Immediately save any pending changes and close the popover
    if (value !== initialValue) {
      meta?.onDataUpdate?.({ rowIndex, columnId, value })
    }
    setOpen(false)
    meta?.onCellEditingStop?.()
  }, [meta, value, initialValue, rowIndex, columnId])

  const onCancel = React.useCallback(() => {
    // Restore the original value
    setValue(initialValue ?? '')
    meta?.onDataUpdate?.({ rowIndex, columnId, value: initialValue })
    setOpen(false)
    meta?.onCellEditingStop?.()
  }, [meta, initialValue, rowIndex, columnId])

  const onChange = React.useCallback(
    (event: React.ChangeEvent<HTMLTextAreaElement>) => {
      const newValue = event.target.value
      setValue(newValue)
      // Debounced auto-save
      debouncedSave(newValue)
    },
    [debouncedSave],
  )

  const onOpenChange = React.useCallback(
    (isOpen: boolean) => {
      setOpen(isOpen)
      if (!isOpen) {
        // Immediately save any pending changes when closing
        if (value !== initialValue) {
          meta?.onDataUpdate?.({ rowIndex, columnId, value })
        }
        meta?.onCellEditingStop?.()
      }
    },
    [meta, value, initialValue, rowIndex, columnId],
  )

  const onOpenAutoFocus: NonNullable<React.ComponentProps<typeof PopoverContent>['onOpenAutoFocus']> =
    React.useCallback((event) => {
      event.preventDefault()
      if (textareaRef.current) {
        textareaRef.current.focus()
        const length = textareaRef.current.value.length
        textareaRef.current.setSelectionRange(length, length)
      }
    }, [])

  const onWrapperKeyDown = React.useCallback(
    (event: React.KeyboardEvent<HTMLDivElement>) => {
      if (isEditing && !open) {
        if (event.key === 'Escape') {
          event.preventDefault()
          meta?.onCellEditingStop?.()
        } else if (event.key === 'Tab') {
          event.preventDefault()
          // Save any pending changes
          if (value !== initialValue) {
            meta?.onDataUpdate?.({ rowIndex, columnId, value })
          }
          meta?.onCellEditingStop?.({
            direction: event.shiftKey ? 'left' : 'right',
          })
        }
      }
    },
    [isEditing, open, meta, value, initialValue, rowIndex, columnId],
  )

  const onTextareaKeyDown = React.useCallback(
    (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
      if (event.key === 'Escape') {
        event.preventDefault()
        onCancel()
      } else if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {
        event.preventDefault()
        onSave()
      }
      // Stop propagation to prevent grid navigation
      event.stopPropagation()
    },
    [onCancel, onSave],
  )

  const onTextareaBlur = React.useCallback(() => {
    // Immediately save any pending changes on blur
    if (value !== initialValue) {
      meta?.onDataUpdate?.({ rowIndex, columnId, value })
    }
    setOpen(false)
    meta?.onCellEditingStop?.()
  }, [meta, value, initialValue, rowIndex, columnId])

  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])

  return (
    <Popover open={open} onOpenChange={onOpenChange}>
      <PopoverAnchor asChild>
        <DataGridCellWrapper
          ref={containerRef}
          cell={cell}
          table={table}
          rowIndex={rowIndex}
          columnId={columnId}
          isEditing={isEditing}
          isFocused={isFocused}
          isSelected={isSelected}
          onKeyDown={onWrapperKeyDown}
        >
          <span data-slot="grid-cell-content">{value}</span>
        </DataGridCellWrapper>
      </PopoverAnchor>
      <PopoverContent
        data-grid-cell-editor=""
        align="start"
        side="bottom"
        sideOffset={sideOffset}
        className="w-[400px] rounded-none p-0"
        onOpenAutoFocus={onOpenAutoFocus}
      >
        <Textarea
          ref={textareaRef}
          value={value}
          onChange={onChange}
          onKeyDown={onTextareaKeyDown}
          onBlur={onTextareaBlur}
          className="min-h-[150px] resize-none rounded-none border-0 shadow-none focus-visible:ring-0"
          placeholder="Enter text..."
        />
      </PopoverContent>
    </Popover>
  )
}
