import * as React from 'react'

import { cn } from './utils'

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

export interface KanbanAssignee {
  id: string
  name: string
  kind?: string
  avatarUrl?: string
}

export interface KanbanCardData {
  id: string
  title: string
  description?: string
  labels?: { text: string; color: string }[]
  assignee?: string
  priority?: 'low' | 'medium' | 'high' | 'critical'
  dueDate?: string | Date
  assignees?: KanbanAssignee[]
  issueKey?: string
  issueType?: string
  storyPoints?: number
  completionPercentage?: number
  subtaskCount?: number
  subtaskCompleted?: number
}

export interface KanbanColumnData {
  id: string
  title: string
  cards: KanbanCardData[]
  limit?: number
  color?: string
  collapsible?: boolean
  collapsed?: boolean
  emptyMessage?: string
  addButton?: boolean
}

export interface KanbanBoardProps extends React.ComponentProps<'div'> {
  columns: KanbanColumnData[]
  draggable?: boolean
  onCardMove?: (cardId: string, fromColumn: string, toColumn: string, index: number) => void
  onCardClick?: (card: KanbanCardData) => void
  onAddCard?: (columnId: string) => void
  descriptionMaxLength?: number
  maxLabels?: number
}

// ---------------------------------------------------------------------------
// KanbanCard
// ---------------------------------------------------------------------------

interface KanbanCardProps {
  card: KanbanCardData
  columnId: string
  isDraggable: boolean
  descriptionMaxLength: number
  maxLabels: number
  onClick?: ((card: KanbanCardData) => void) | undefined
  onDragStart: (cardId: string, columnId: string) => void
}

const PRIORITY_STYLES: Record<string, string> = {
  critical: 'border-l-accent-rose border-l-2',
  high: 'border-l-accent-amber border-l-2',
  medium: 'border-l-accent-cyan border-l-2',
  low: 'border-l-accent-violet border-l-2',
}

function KanbanCard({
  card,
  columnId,
  isDraggable,
  descriptionMaxLength,
  maxLabels,
  onClick,
  onDragStart,
}: KanbanCardProps) {
  const handleDragStart = (e: React.DragEvent) => {
    e.dataTransfer.effectAllowed = 'move'
    e.dataTransfer.setData('text/plain', card.id)
    onDragStart(card.id, columnId)
  }

  const truncatedDesc =
    card.description && card.description.length > descriptionMaxLength
      ? card.description.slice(0, descriptionMaxLength) + '...'
      : card.description

  const percentage = React.useMemo(() => {
    if (card.completionPercentage !== undefined) return card.completionPercentage
    if (card.subtaskCount && card.subtaskCount > 0)
      return ((card.subtaskCompleted ?? 0) / card.subtaskCount) * 100
    return null
  }, [card.completionPercentage, card.subtaskCount, card.subtaskCompleted])

  return (
    <div
      className={cn(
        'bg-glass border-border-glass rounded-lg border p-3 backdrop-blur-[20px] transition-all',
        'hover:border-border-glass/80 cursor-pointer hover:shadow-sm',
        card.priority && PRIORITY_STYLES[card.priority]
      )}
      draggable={isDraggable}
      onDragStart={isDraggable ? handleDragStart : undefined}
      onClick={() => onClick?.(card)}
      role="listitem"
      tabIndex={0}
    >
      {/* Issue info row */}
      {(card.issueKey || card.issueType || card.storyPoints !== undefined) && (
        <div className="text-foreground-secondary mb-1.5 flex items-center gap-2 text-xs">
          {card.issueKey && <span className="font-medium">{card.issueKey}</span>}
          {card.issueType && <span>{card.issueType}</span>}
          {card.storyPoints !== undefined && (
            <span className="bg-surface-secondary rounded-full px-1.5 py-0.5 text-[10px]">
              {card.storyPoints}
            </span>
          )}
        </div>
      )}

      {/* Title */}
      <div className="text-foreground text-sm font-medium">{card.title}</div>

      {/* Description */}
      {truncatedDesc && (
        <div className="text-foreground-secondary mt-1 text-xs">{truncatedDesc}</div>
      )}

      {/* Progress */}
      {percentage !== null && (
        <div className="bg-surface-secondary mt-2 h-1 rounded-full">
          <div
            className="bg-accent-cyan h-full rounded-full transition-all"
            style={{ width: `${Math.round(percentage)}%` }}
          />
        </div>
      )}

      {/* Due date */}
      {card.dueDate && (
        <div className="text-foreground-secondary mt-1.5 text-xs">
          {card.dueDate instanceof Date ? card.dueDate.toLocaleDateString() : card.dueDate}
        </div>
      )}

      {/* Assignees */}
      {card.assignees && card.assignees.length > 0 && (
        <div className="mt-2 flex -space-x-1">
          {card.assignees.slice(0, 3).map(a => (
            <div
              key={a.id}
              title={a.name}
              className="bg-surface-secondary text-foreground-secondary flex size-6 items-center justify-center rounded-full border border-white/10 text-[10px] font-medium"
              style={
                a.avatarUrl
                  ? { backgroundImage: `url(${a.avatarUrl})`, backgroundSize: 'cover' }
                  : undefined
              }
            >
              {!a.avatarUrl && a.name.charAt(0).toUpperCase()}
            </div>
          ))}
          {card.assignees.length > 3 && (
            <span className="text-foreground-secondary ml-1 text-xs">
              +{card.assignees.length - 3}
            </span>
          )}
        </div>
      )}

      {/* Labels */}
      {card.labels && card.labels.length > 0 && (
        <div className="mt-2 flex flex-wrap gap-1">
          {card.labels.slice(0, maxLabels).map((label, idx) => (
            <span
              key={idx}
              className="rounded-full px-2 py-0.5 text-[10px] font-medium text-white"
              style={{ backgroundColor: label.color }}
            >
              {label.text}
            </span>
          ))}
          {card.labels.length > maxLabels && (
            <span className="text-foreground-secondary text-[10px]">
              +{card.labels.length - maxLabels}
            </span>
          )}
        </div>
      )}

      {/* Legacy assignee */}
      {!card.assignees?.length && card.assignee && (
        <div className="text-foreground-secondary mt-2 text-xs">{card.assignee}</div>
      )}
    </div>
  )
}

// ---------------------------------------------------------------------------
// KanbanColumn
// ---------------------------------------------------------------------------

interface KanbanColumnProps {
  column: KanbanColumnData
  isDraggable: boolean
  descriptionMaxLength: number
  maxLabels: number
  onCardClick?: ((card: KanbanCardData) => void) | undefined
  onAddCard?: ((columnId: string) => void) | undefined
  onDragStart: (cardId: string, columnId: string) => void
  onDrop: (columnId: string, index: number) => void
}

function KanbanColumn({
  column,
  isDraggable,
  descriptionMaxLength,
  maxLabels,
  onCardClick,
  onAddCard,
  onDragStart,
  onDrop,
}: KanbanColumnProps) {
  const [isCollapsed, setIsCollapsed] = React.useState(column.collapsed ?? false)
  const [isDragOver, setIsDragOver] = React.useState(false)
  const isAtLimit = column.limit !== undefined && column.cards.length >= column.limit

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault()
    e.dataTransfer.dropEffect = 'move'
    setIsDragOver(true)
  }

  const handleDragLeave = (e: React.DragEvent) => {
    const related = e.relatedTarget
    if (related instanceof Node && e.currentTarget.contains(related)) return
    setIsDragOver(false)
  }

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault()
    setIsDragOver(false)
    const listEl = e.currentTarget as HTMLElement
    const cards = listEl.querySelectorAll('[role="listitem"]')
    let index = cards.length
    for (let i = 0; i < cards.length; i++) {
      const rect = cards[i]?.getBoundingClientRect()
      if (rect && e.clientY < rect.top + rect.height / 2) {
        index = i
        break
      }
    }
    onDrop(column.id, index)
  }

  return (
    <div
      className={cn(
        'bg-surface-secondary/50 flex min-w-[280px] shrink-0 flex-col rounded-lg',
        isAtLimit && 'border-accent-amber/30 border'
      )}
    >
      {/* Header */}
      <div
        className="flex items-center gap-2 px-3 py-2.5"
        style={
          column.color
            ? { borderTop: `3px solid ${column.color}`, borderRadius: '8px 8px 0 0' }
            : undefined
        }
      >
        <span className="text-foreground text-sm font-semibold">{column.title}</span>
        <span className={cn('text-foreground-secondary text-xs', isAtLimit && 'text-accent-amber')}>
          {column.cards.length}
          {column.limit !== undefined && ` / ${column.limit}`}
        </span>
        <div className="ml-auto flex items-center gap-1">
          {column.collapsible && (
            <button
              onClick={() => setIsCollapsed(!isCollapsed)}
              className="text-foreground-secondary hover:text-foreground text-xs"
            >
              {isCollapsed ? '+' : '-'}
            </button>
          )}
          {column.addButton && (
            <button
              onClick={() => onAddCard?.(column.id)}
              className="text-foreground-secondary hover:text-foreground text-xs"
            >
              +
            </button>
          )}
        </div>
      </div>

      {/* Cards */}
      {!isCollapsed && (
        <div
          className={cn(
            'flex flex-1 flex-col gap-2 px-2 pb-2',
            isDragOver && 'bg-accent-cyan/5 rounded-b-lg'
          )}
          onDragOver={isDraggable ? handleDragOver : undefined}
          onDragLeave={isDraggable ? handleDragLeave : undefined}
          onDrop={isDraggable ? handleDrop : undefined}
        >
          {column.cards.length === 0 && column.emptyMessage && (
            <div className="text-foreground-secondary py-4 text-center text-xs">
              {column.emptyMessage}
            </div>
          )}
          {column.cards.map(card => (
            <KanbanCard
              key={card.id}
              card={card}
              columnId={column.id}
              isDraggable={isDraggable}
              descriptionMaxLength={descriptionMaxLength}
              maxLabels={maxLabels}
              onClick={onCardClick}
              onDragStart={onDragStart}
            />
          ))}
        </div>
      )}
    </div>
  )
}

// ---------------------------------------------------------------------------
// KanbanBoard
// ---------------------------------------------------------------------------

function KanbanBoard({
  columns,
  draggable = true,
  onCardMove,
  onCardClick,
  onAddCard,
  descriptionMaxLength = 100,
  maxLabels = 3,
  className,
  ...props
}: KanbanBoardProps) {
  const [cols, setCols] = React.useState(columns)
  const dragStateRef = React.useRef<{ cardId: string; fromColumnId: string } | null>(null)

  // Sync with external columns prop
  React.useEffect(() => {
    setCols(columns)
  }, [columns])

  const handleDragStart = React.useCallback((cardId: string, fromColumnId: string) => {
    dragStateRef.current = { cardId, fromColumnId }
  }, [])

  const handleDrop = React.useCallback(
    (toColumnId: string, index: number) => {
      const drag = dragStateRef.current
      if (!drag) return
      dragStateRef.current = null

      const { cardId, fromColumnId } = drag

      setCols(prev => {
        const next = prev.map(col => ({ ...col, cards: [...col.cards] }))
        const sourceCol = next.find(c => c.id === fromColumnId)
        const targetCol = next.find(c => c.id === toColumnId)
        if (!sourceCol || !targetCol) return prev

        const cardIdx = sourceCol.cards.findIndex(c => c.id === cardId)
        if (cardIdx < 0) return prev

        const [card] = sourceCol.cards.splice(cardIdx, 1)
        if (!card) return prev

        const clampedIdx = Math.min(index, targetCol.cards.length)
        targetCol.cards.splice(clampedIdx, 0, card)

        return next
      })

      onCardMove?.(cardId, fromColumnId, toColumnId, index)
    },
    [onCardMove]
  )

  return (
    <div
      data-slot="kanban-board"
      className={cn('flex gap-4 overflow-x-auto p-2', className)}
      {...props}
    >
      {cols.map(column => (
        <KanbanColumn
          key={column.id}
          column={column}
          isDraggable={draggable}
          descriptionMaxLength={descriptionMaxLength}
          maxLabels={maxLabels}
          onCardClick={onCardClick}
          onAddCard={onAddCard}
          onDragStart={handleDragStart}
          onDrop={handleDrop}
        />
      ))}
    </div>
  )
}
KanbanBoard.displayName = 'KanbanBoard'

export { KanbanBoard, KanbanColumn, KanbanCard }
