"use client"

import type React from "react"
import { useRef } from "react"
import { useDrag, useDrop } from "react-dnd"
import type { ComponentItem } from "@/contexts/composer-context"
import { cn } from "@/lib/utils"
import { X, GripVertical } from "lucide-react"
import { Button } from "@/components/ui/button"

interface DraggableComponentProps {
  component: ComponentItem
  index: number
  moveComponent: (dragIndex: number, hoverIndex: number) => void
  removeComponent: (id: string) => void
  children: React.ReactNode
}

interface DragItem {
  index: number
  id: string
  type: string
}

export function DraggableComponent({
  component,
  index,
  moveComponent,
  removeComponent,
  children,
}: DraggableComponentProps) {
  const ref = useRef<HTMLDivElement>(null)

  // Set up drag
  const [{ isDragging }, drag, preview] = useDrag({
    type: "COMPONENT",
    item: { index, id: component.id, type: "COMPONENT" } as DragItem,
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
  })

  // Set up drop
  const [{ handlerId }, drop] = useDrop({
    accept: "COMPONENT",
    collect(monitor) {
      return {
        handlerId: monitor.getHandlerId(),
      }
    },
    hover(item: DragItem, monitor) {
      if (!ref.current) {
        return
      }
      const dragIndex = item.index
      const hoverIndex = index

      // Don't replace items with themselves
      if (dragIndex === hoverIndex) {
        return
      }

      // Determine rectangle on screen
      const hoverBoundingRect = ref.current?.getBoundingClientRect()

      // Get vertical middle
      const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2

      // Determine mouse position
      const clientOffset = monitor.getClientOffset()

      // Get pixels to the top
      const hoverClientY = clientOffset!.y - hoverBoundingRect.top

      // Only perform the move when the mouse has crossed half of the items height
      // When dragging downwards, only move when the cursor is below 50%
      // When dragging upwards, only move when the cursor is above 50%
      if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
        return
      }
      if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
        return
      }

      // Time to actually perform the action
      moveComponent(dragIndex, hoverIndex)

      // Note: we're mutating the monitor item here!
      // Generally it's better to avoid mutations,
      // but it's good here for the sake of performance
      // to avoid expensive index searches.
      item.index = hoverIndex
    },
  })

  // Initialize drag and drop refs
  drag(drop(ref))

  return (
    <div
      ref={preview}
      className={cn(
        "relative border border-border rounded-lg mb-4 transition-opacity",
        isDragging ? "opacity-50" : "opacity-100",
      )}
      data-handler-id={handlerId}
    >
      {/* Component handle for dragging */}
      <div ref={ref} className="absolute left-2 top-2 cursor-move p-1 rounded-md hover:bg-accent z-10">
        <GripVertical className="h-5 w-5 text-muted-foreground" />
      </div>

      {/* Remove button */}
      <Button
        variant="ghost"
        size="icon"
        className="absolute right-2 top-2 h-7 w-7 rounded-full hover:bg-destructive/10 hover:text-destructive z-10"
        onClick={() => removeComponent(component.id)}
      >
        <X className="h-4 w-4" />
      </Button>

      {/* Component content */}
      <div className="pt-10 px-4 pb-4">{children}</div>
    </div>
  )
}
