import React from 'react'
import {
  DndContext,
  DragOverlay,
  closestCenter,
  KeyboardSensor,
  PointerSensor,
  useSensor,
  useSensors,
  DragStartEvent,
  DragEndEvent,
} from '@dnd-kit/core'
import {
  SortableContext,
  sortableKeyboardCoordinates,
  verticalListSortingStrategy,
} from '@dnd-kit/sortable'
import { MenuItemComponent } from './MenuItemComponent'
import { MenuItem } from '@/@types/menu'

interface SortableMenuTreeProps {
  items: MenuItem[]
  onItemsChange: (items: MenuItem[]) => void
  isDesignMode: boolean
}

export const SortableMenuTree: React.FC<SortableMenuTreeProps> = ({
  items,
  onItemsChange,
  isDesignMode,
}) => {
  const [activeItem, setActiveItem] = React.useState<MenuItem | null>(null)

  const sensors = useSensors(
    useSensor(PointerSensor, {
      activationConstraint: {
        distance: 8,
      },
    }),
    useSensor(KeyboardSensor, {
      coordinateGetter: sortableKeyboardCoordinates,
    }),
  )

  // Flatten the tree structure to get all items with their paths
  const flattenItems = (
    items: MenuItem[],
    parentPath: string[] = [],
  ): Array<{ item: MenuItem; path: number[] }> => {
    const result: Array<{ item: MenuItem; path: number[] }> = []

    items.forEach((item, index) => {
      const currentPath = [...parentPath, index]
      result.push({ item, path: currentPath })

      if (item.children && item.children.length > 0) {
        result.push(...flattenItems(item.children, currentPath))
      }
    })

    return result
  }

  // Find item by ID in the tree
  const findItemById = (items: MenuItem[], id: string): MenuItem | null => {
    for (const item of items) {
      if (item.id === id) {
        return item
      }
      if (item.children) {
        const found = findItemById(item.children, id)
        if (found) return found
      }
    }
    return null
  }

  // Remove item from tree by ID
  const removeItemFromTree = (items: MenuItem[], id: string): MenuItem[] => {
    return items.reduce((acc: MenuItem[], item) => {
      if (item.id === id) {
        return acc // Skip this item (remove it)
      }

      const newItem = { ...item }
      if (newItem.children && newItem.children.length > 0) {
        newItem.children = removeItemFromTree(newItem.children, id)
      }

      acc.push(newItem)
      return acc
    }, [])
  }

  // Insert item at specific position
  const insertItemAtPath = (
    items: MenuItem[],
    item: MenuItem,
    targetPath: number[],
  ): MenuItem[] => {
    if (targetPath.length === 1) {
      const newItems = [...items]
      newItems.splice(targetPath[0], 0, item)
      return newItems
    }

    const [firstIndex, ...restPath] = targetPath
    const newItems = [...items]

    if (newItems[firstIndex]) {
      newItems[firstIndex] = {
        ...newItems[firstIndex],
        children: insertItemAtPath(newItems[firstIndex].children || [], item, restPath),
      }
    }

    return newItems
  }

  // Get the path where an item should be inserted based on over item
  const getInsertionPath = (
    items: MenuItem[],
    activeId: string,
    overId: string,
  ): number[] | null => {
    const flatItems = flattenItems(items)
    const activeIndex = flatItems.findIndex(({ item }) => item.id === activeId)
    const overIndex = flatItems.findIndex(({ item }) => item.id === overId)

    if (overIndex === -1) return null

    const overItem = flatItems[overIndex]
    const insertPath = [...overItem.path]

    // Aktif item, listedeki over item'den sonra geliyorsa, yukarı taşınıyordur → over item'ın yerine ekle
    // Aktif item, listedeki over item'den önceyse, aşağı taşınıyordur → bir SONRASINA ekle ki yeniden aynı yere düşmesin
    if (activeIndex < overIndex) {
      insertPath[insertPath.length - 1] += 1
    }

    return insertPath
  }

  const updateOrderNumbers = (items: MenuItem[]): MenuItem[] => {
    return items.map((item, index) => ({
      ...item,
      order: index + 1,
      children: item.children ? updateOrderNumbers(item.children) : [],
    }))
  }

  const handleDragStart = (event: DragStartEvent) => {
    const { active } = event
    const activeItem = findItemById(items, active.id as string)
    setActiveItem(activeItem)
  }

  const handleDragEnd = (event: DragEndEvent) => {
    const { active, over } = event
    setActiveItem(null)

    if (!over || active.id === over.id || !isDesignMode) {
      return
    }

    const activeId = active.id as string
    const overId = over.id as string

    const activeItem = findItemById(items, activeId)
    if (!activeItem) return

    // ⛳️ Kullanılması gereken liste: `items`
    const insertionPath = getInsertionPath(items, activeId, overId)
    if (!insertionPath) return

    // Şimdi aktif elemanı çıkar
    let newItems = removeItemFromTree(items, activeId)

    // ve hedef konuma ekle
    newItems = insertItemAtPath(newItems, activeItem, insertionPath)

    // Sıra numaralarını güncelle
    const finalItems = updateOrderNumbers(newItems)
    onItemsChange(finalItems)
  }

  const renderMenuItem = (item: MenuItem, depth: number = 0): React.ReactNode => {
    return (
      <MenuItemComponent
        key={item.id || `temp-${Math.random().toString(36).substr(2, 9)}`}
        item={item}
        isDesignMode={isDesignMode}
        depth={depth}
      >
        {item.children && item.children.length > 0 && (
          <div className="ml-4">
            {item.children.map((child) => renderMenuItem(child, depth + 1))}
          </div>
        )}
      </MenuItemComponent>
    )
  }

  const allItems = flattenItems(items)

  return (
    <DndContext
      sensors={sensors}
      collisionDetection={closestCenter}
      onDragStart={handleDragStart}
      onDragEnd={handleDragEnd}
    >
      <SortableContext
        items={allItems.map(({ item }) => item.id)}
        strategy={verticalListSortingStrategy}
      >
        <div className="space-y-1">{items.map((item) => renderMenuItem(item))}</div>
      </SortableContext>

      <DragOverlay>
        {activeItem ? (
          <MenuItemComponent
            item={activeItem}
            isDesignMode={isDesignMode}
            depth={0}
            isDragOverlay={true}
          />
        ) : null}
      </DragOverlay>
    </DndContext>
  )
}
