'use client'

import * as React from 'react'
import {
  DragDropContext,
  Droppable,
  Draggable,
  type DropResult,
} from '@hello-pangea/dnd'
import { cn } from '../../lib/utils'

export interface KanbanColumnConfig {
  id: string
  label: string
  color?: string
}

/** A resolved card move derived from a drag, in board terms (not DnD terms). */
export interface KanbanMove {
  cardId: string
  fromColumnId: string
  toColumnId: string
  toIndex: number
}

/**
 * Pure resolver: turn a @hello-pangea/dnd DropResult into a KanbanMove, or null
 * when the drag is a no-op (dropped outside any column, or back onto the same slot).
 * Exported so consumers and tests can reason about a move without a DOM.
 */
export function resolveKanbanMove(result: DropResult): KanbanMove | null {
  const { draggableId, source, destination } = result
  if (!destination) return null
  if (
    source.droppableId === destination.droppableId &&
    source.index === destination.index
  ) {
    return null
  }
  return {
    cardId: draggableId,
    fromColumnId: source.droppableId,
    toColumnId: destination.droppableId,
    toIndex: destination.index,
  }
}

export interface KanbanBoardProps<T> {
  columns: KanbanColumnConfig[]
  items: Record<string, T[]>
  renderCard: (item: T) => React.ReactNode
  renderColumnHeader?: (column: KanbanColumnConfig, items: T[]) => React.ReactNode
  renderColumnFooter?: (column: KanbanColumnConfig) => React.ReactNode
  emptyColumnMessage?: string
  columnWidth?: number
  columnRef?: (columnId: string) => React.Ref<HTMLDivElement> | undefined
  isColumnOver?: (columnId: string) => boolean
  className?: string
  /**
   * DnD (opt-in). Provide BOTH `getCardId` and `onCardMove` to make cards draggable
   * between columns via @hello-pangea/dnd — all drag mechanics live here in
   * @startsimpli/ui; consumers stay dnd-agnostic and just persist the move in
   * `onCardMove`. Omit either and the board renders exactly as before (no DnD;
   * `columnRef`/`isColumnOver` honored for a parent's own manual wiring).
   */
  getCardId?: (item: T) => string
  onCardMove?: (move: KanbanMove) => void
}

export function KanbanBoard<T>({
  columns,
  items,
  renderCard,
  renderColumnHeader,
  renderColumnFooter,
  emptyColumnMessage = 'No items',
  columnWidth = 320,
  columnRef,
  isColumnOver,
  className,
  getCardId,
  onCardMove,
}: KanbanBoardProps<T>) {
  const dndEnabled = !!(getCardId && onCardMove)

  const handleDragEnd = React.useCallback(
    (result: DropResult) => {
      const move = resolveKanbanMove(result)
      if (move) onCardMove?.(move)
    },
    [onCardMove],
  )

  const columnHeader = (column: KanbanColumnConfig, columnItems: T[]) =>
    renderColumnHeader ? (
      renderColumnHeader(column, columnItems)
    ) : (
      <div className="flex items-center justify-between px-3 py-2 border-b">
        <div className="flex items-center gap-2">
          {column.color && (
            <span
              className="w-2.5 h-2.5 rounded-full shrink-0"
              style={{ backgroundColor: column.color }}
              aria-hidden="true"
            />
          )}
          <h3 className="text-sm font-semibold text-foreground truncate">
            {column.label}
          </h3>
        </div>
        <span className="inline-flex items-center justify-center rounded-full bg-muted px-2 py-0.5 text-xs font-medium text-muted-foreground">
          {columnItems.length}
        </span>
      </div>
    )

  const emptyState = (
    <p className="text-xs text-muted-foreground text-center py-8">
      {emptyColumnMessage}
    </p>
  )

  const renderColumn = (column: KanbanColumnConfig) => {
    const columnItems = items[column.id] ?? []
    const footer = renderColumnFooter && (
      <div className="border-t px-3 py-2">{renderColumnFooter(column)}</div>
    )

    if (dndEnabled) {
      return (
        <div
          key={column.id}
          style={{ minWidth: columnWidth, maxWidth: columnWidth }}
          className="flex flex-col rounded-lg border bg-muted/50 transition-colors"
        >
          {columnHeader(column, columnItems)}
          <Droppable droppableId={column.id}>
            {(provided, snapshot) => (
              <div
                ref={provided.innerRef}
                {...provided.droppableProps}
                className={cn(
                  'flex-1 overflow-y-auto p-2 space-y-2 transition-colors',
                  snapshot.isDraggingOver && 'bg-primary/5',
                )}
              >
                {columnItems.length === 0 && !snapshot.isDraggingOver
                  ? emptyState
                  : columnItems.map((item, index) => {
                      const id = getCardId!(item)
                      return (
                        <Draggable key={id} draggableId={id} index={index}>
                          {(dp, ds) => (
                            <div
                              ref={dp.innerRef}
                              {...dp.draggableProps}
                              {...dp.dragHandleProps}
                              // @hello-pangea/dnd's DraggableStyle isn't assignable to
                              // the radix-augmented CSSProperties; the spread already
                              // sets it, this re-asserts the type for consumer tsc.
                              style={dp.draggableProps.style as React.CSSProperties}
                              className={cn(ds.isDragging && 'opacity-80')}
                            >
                              {renderCard(item)}
                            </div>
                          )}
                        </Draggable>
                      )
                    })}
                {provided.placeholder}
              </div>
            )}
          </Droppable>
          {footer}
        </div>
      )
    }

    // Non-DnD (backward compatible): honor columnRef/isColumnOver for a parent's own
    // manual drag wiring, render cards keyed by index as before.
    const ref = columnRef?.(column.id)
    const isOver = isColumnOver?.(column.id) ?? false
    return (
      <div
        key={column.id}
        ref={ref}
        style={{ minWidth: columnWidth, maxWidth: columnWidth }}
        className={cn(
          'flex flex-col rounded-lg border bg-muted/50 transition-colors',
          isOver && 'border-primary ring-2 ring-primary/20',
        )}
      >
        {columnHeader(column, columnItems)}
        <div className="flex-1 overflow-y-auto p-2 space-y-2">
          {columnItems.length === 0
            ? emptyState
            : columnItems.map((item, index) => (
                <React.Fragment key={index}>{renderCard(item)}</React.Fragment>
              ))}
        </div>
        {footer}
      </div>
    )
  }

  const board = (
    <div className={cn('flex gap-4 overflow-x-auto pb-4', className)}>
      {columns.map(renderColumn)}
    </div>
  )

  if (dndEnabled) {
    return <DragDropContext onDragEnd={handleDragEnd}>{board}</DragDropContext>
  }
  return board
}
