'use client'

import type { Cell, Table } from '@tanstack/react-table'

import * as React from 'react'

import { cn } from '@lib/utils'

type DataGridCellWrapperProps<TData> = {
  cell: Cell<TData, unknown>
  table: Table<TData>
  rowIndex: number
  columnId: string
  isEditing: boolean
  isFocused: boolean
  isSelected: boolean
} & React.ComponentProps<'div'>

export function DataGridCellWrapper<TData>({
  cell,
  table,
  rowIndex,
  columnId,
  isEditing,
  isFocused,
  isSelected,
  className,
  onClick: onClickProp,
  onKeyDown: onKeyDownProp,
  ...props
}: DataGridCellWrapperProps<TData>) {
  const meta = table.options.meta

  const rowOriginal = (cell?.row?.original ?? {}) as any
  const colCellMeta = cell?.column?.columnDef?.meta as any
  const align: 'left' | 'right' | 'center' = colCellMeta?.align ?? 'left'

  // Normalize editable to a resolver function and memoize to avoid typeof checks per cell
  const editableResolver = React.useMemo(() => {
    const v = colCellMeta?.editable
    if (v === undefined) {
      return () => true
    }
    return typeof v === 'function' ? (v as (row: TData) => boolean) : () => Boolean(v)
  }, [colCellMeta?.editable])
  const isEditable = editableResolver(rowOriginal)

  // Normalize className to a resolver function and memoize to avoid typeof checks per cell
  const classNameResolver = React.useMemo(() => {
    const v = colCellMeta?.className
    return typeof v === 'function' ? (v as (row: any) => string | undefined) : () => v as string | undefined
  }, [colCellMeta?.className])
  const colCellClassName = classNameResolver(rowOriginal)

  const isSearchMatch = meta?.getIsSearchMatch?.(rowIndex, columnId) ?? false
  const isActiveSearchMatch = meta?.getIsActiveSearchMatch?.(rowIndex, columnId) ?? false

  const onClick = React.useCallback(
    (event: React.MouseEvent<HTMLDivElement>) => {
      if (!isEditing) {
        event.preventDefault()
        onClickProp?.(event)
        if (isFocused) {
          if (isEditable) {
            meta?.onCellEditingStart?.(rowIndex, columnId)
          }
        } else {
          meta?.onCellClick?.(rowIndex, columnId, event)
        }
      }
    },
    [meta, rowIndex, columnId, isEditing, isFocused, onClickProp, isEditable],
  )

  const onContextMenu = React.useCallback(
    (event: React.MouseEvent) => {
      if (!isEditing) {
        meta?.onCellContextMenu?.(rowIndex, columnId, event)
      }
    },
    [meta, rowIndex, columnId, isEditing],
  )

  const onMouseDown = React.useCallback(
    (event: React.MouseEvent) => {
      if (!isEditing) {
        meta?.onCellMouseDown?.(rowIndex, columnId, event)
      }
    },
    [meta, rowIndex, columnId, isEditing],
  )

  const onMouseEnter = React.useCallback(
    (event: React.MouseEvent) => {
      if (!isEditing) {
        meta?.onCellMouseEnter?.(rowIndex, columnId, event)
      }
    },
    [meta, rowIndex, columnId, isEditing],
  )

  const onMouseUp = React.useCallback(() => {
    if (!isEditing) {
      meta?.onCellMouseUp?.()
    }
  }, [meta, isEditing])

  const onDoubleClick = React.useCallback(
    (event: React.MouseEvent) => {
      if (!isEditing) {
        event.preventDefault()
        if (isEditable) {
          meta?.onCellDoubleClick?.(rowIndex, columnId)
        }
      }
    },
    [meta, rowIndex, columnId, isEditing, isEditable],
  )

  const onKeyDown = React.useCallback(
    (event: React.KeyboardEvent<HTMLDivElement>) => {
      onKeyDownProp?.(event)

      if (event.defaultPrevented) {
        return
      }

      if (
        event.key === 'ArrowUp' ||
        event.key === 'ArrowDown' ||
        event.key === 'ArrowLeft' ||
        event.key === 'ArrowRight' ||
        event.key === 'Home' ||
        event.key === 'End' ||
        event.key === 'PageUp' ||
        event.key === 'PageDown' ||
        event.key === 'Tab'
      ) {
        return
      }

      if (isFocused && !isEditing) {
        if (event.key === 'F2' || event.key === 'Enter') {
          event.preventDefault()
          event.stopPropagation()
          if (isEditable) {
            meta?.onCellEditingStart?.(rowIndex, columnId)
          }
          return
        }

        if (event.key === '') {
          event.preventDefault()
          event.stopPropagation()
          meta?.onCellEditingStart?.(rowIndex, columnId)
          return
        }

        if (event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
          event.preventDefault()
          event.stopPropagation()
          if (isEditable) {
            meta?.onCellEditingStart?.(rowIndex, columnId)
          }
        }
      }
    },
    [onKeyDownProp, isFocused, isEditing, meta, rowIndex, columnId, isEditable],
  )

  const rowHeight = meta?.rowHeight ?? 'short'

  return (
    <div
      role="button"
      data-slot="grid-cell-wrapper"
      data-editing={isEditing ? '' : undefined}
      data-focused={isFocused ? '' : undefined}
      data-selected={isSelected ? '' : undefined}
      tabIndex={isFocused && !isEditing ? 0 : -1}
      className={cn(
        'size-full px-2 py-1.5 text-sm outline-none -has-data-[slot=checkbox]:pt-2.5', // why has-data-[slot=checkbox] ?
        {
          'text-left': align === 'left',
          'text-right': align === 'right',
          'text-center': align === 'center',
        },
        {
          'ring-1 ring-neutral-950 ring-inset dark:ring-neutral-300': isFocused,
          'bg-yellow-100 dark:bg-yellow-900/30': isSearchMatch && !isActiveSearchMatch,
          'bg-orange-200 dark:bg-orange-900/50': isActiveSearchMatch,
          'bg-neutral-900/10 dark:bg-neutral-50/10': isSelected && !isEditing,
          'cursor-default': !isEditing,
          '**:data-[slot=grid-cell-content]:line-clamp-1': !isEditing && rowHeight === 'short',
          '**:data-[slot=grid-cell-content]:line-clamp-2': !isEditing && rowHeight === 'medium',
          '**:data-[slot=grid-cell-content]:line-clamp-3': !isEditing && rowHeight === 'tall',
          '**:data-[slot=grid-cell-content]:line-clamp-4': !isEditing && rowHeight === 'extra-tall',
        },
        colCellClassName,
        className,
      )}
      onClick={onClick}
      onContextMenu={onContextMenu}
      onDoubleClick={onDoubleClick}
      onMouseDown={onMouseDown}
      onMouseEnter={onMouseEnter}
      onMouseUp={onMouseUp}
      onKeyDown={onKeyDown}
      {...props}
    />
  )
}
