import type { CSSProperties, ReactElement, ReactNode } from 'react'
import { useSortable } from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities'
import { Box, IconButton } from '@mui/material'
import { DragIndicator as DragIndicatorIcon } from '@mui/icons-material'
import { Tooltip } from '../../../components/tooltip/tooltip'
import { useLegendConfig } from '../../provider'
import { toSortableId, type SortableKind } from './sortable-ids'
import { styles } from './styles'

/** What `SortableEntity` hands to its render callback. */
export interface SortableEntityRenderProps {
  /** Attach to the entity's existing root element. */
  rootRef: (el: HTMLElement | null) => void
  /** Sort transform/transition for the root (inline, per-frame values). */
  rootStyle: CSSProperties
  /** The original is dimmed in place while its overlay clone is dragged. */
  dragging: boolean
  /** The drag handle — absolutely positioned, place anywhere in the header. */
  handle: ReactNode
}

export interface SortableEntityProps {
  kind: SortableKind
  id: string
  render: (sortable: SortableEntityRenderProps) => ReactElement
}

/**
 * Sortable shell for a legend group/row. Render-prop (instead of a wrapper
 * element) so the entity keeps its own root — sibling CSS like the `& + &`
 * dividers keeps working. Hosts `useSortable` and builds the drag handle
 * (keyboard-activatable, labelled `labels.reorder`).
 *
 * @experimental This API is new and may change in a future release.
 */
export function SortableEntity({ kind, id, render }: SortableEntityProps) {
  const { labels } = useLegendConfig()
  const {
    attributes,
    listeners,
    setNodeRef,
    setActivatorNodeRef,
    transform,
    transition,
    isDragging,
  } = useSortable({ id: toSortableId(kind, id) })

  const rootStyle: CSSProperties = {
    // Vertical list: lock x so items only shift along the axis.
    transform: CSS.Transform.toString(
      transform ? { ...transform, x: 0 } : null,
    ),
    transition,
  }

  const handle = (
    // Absolutely positioned (see styles.handleSlot) — no reserved flex slot,
    // so it never shifts the title/icon; the fade rules live on the
    // group/row root. Kind-scoped class so a group hover doesn't light up
    // its member rows' handles.
    <Box
      component='span'
      className={`PsLegend-dragHandle-${kind}`}
      sx={[
        styles.handleSlot,
        kind === 'group' ? styles.handleSlotGroup : styles.handleSlotLayer,
      ]}
    >
      <Tooltip title={labels.reorder}>
        <IconButton
          ref={setActivatorNodeRef}
          size='xsmall'
          aria-label={labels.reorder}
          {...attributes}
          {...listeners}
          sx={styles.handle}
        >
          <DragIndicatorIcon />
        </IconButton>
      </Tooltip>
    </Box>
  )

  return render({
    rootRef: setNodeRef,
    rootStyle,
    dragging: isDragging,
    handle,
  })
}
