"use client"

import { useCallback, useRef, useState } from "react"
import { toast } from "sonner"
import { useDriveMutations } from "@/lib/api/hooks/use-drive-queries"
import { getDriveDragData } from "@/lib/drive/drive-dnd"
import {
  isMoveDestinationBlocked,
  isMoveToSameFolder,
  moveDriveItemsToFolder,
} from "@/lib/drive/drive-move-items"
import { useDriveUIStore } from "@/lib/stores/drive-ui-store"

const HOVER_EXPAND_MS = 700

export function useDriveDropTarget({
  folderPath,
  disabled,
  hasChildFolders,
  onExpandRequest,
}: {
  folderPath: string
  disabled?: boolean
  hasChildFolders?: boolean
  onExpandRequest?: () => void
}) {
  const [isOver, setIsOver] = useState(false)
  const [canDrop, setCanDrop] = useState(false)
  const enterCountRef = useRef(0)
  const expandTimerRef = useRef<number | null>(null)
  const mutations = useDriveMutations()
  const clearSelection = useDriveUIStore((s) => s.clearSelection)
  const draggingItems = useDriveUIStore((s) => s.draggingItems)
  const setDraggingItems = useDriveUIStore((s) => s.setDraggingItems)

  const clearExpandTimer = useCallback(() => {
    if (expandTimerRef.current !== null) {
      window.clearTimeout(expandTimerRef.current)
      expandTimerRef.current = null
    }
  }, [])

  const resolveSources = useCallback(
    (event: React.DragEvent) => {
      return getDriveDragData(event.dataTransfer) ?? draggingItems
    },
    [draggingItems]
  )

  const evaluateDrop = useCallback(
    (sources: ReturnType<typeof resolveSources>) => {
      if (disabled || !sources || sources.length === 0) return false
      if (isMoveDestinationBlocked(sources, folderPath)) return false
      if (isMoveToSameFolder(sources, folderPath)) return false
      return true
    },
    [disabled, folderPath]
  )

  const onDragOver = useCallback(
    (event: React.DragEvent) => {
      if (disabled) return
      const sources = draggingItems
      const allowed = evaluateDrop(sources)
      if (!allowed) return
      event.preventDefault()
      event.dataTransfer.dropEffect = "move"
      setCanDrop(true)

      if (hasChildFolders && onExpandRequest && expandTimerRef.current === null) {
        expandTimerRef.current = window.setTimeout(() => {
          expandTimerRef.current = null
          onExpandRequest()
        }, HOVER_EXPAND_MS)
      }
    },
    [disabled, draggingItems, evaluateDrop, hasChildFolders, onExpandRequest]
  )

  const onDragEnter = useCallback(
    (event: React.DragEvent) => {
      if (disabled) return
      enterCountRef.current += 1
      if (enterCountRef.current === 1) {
        setIsOver(true)
        setCanDrop(evaluateDrop(draggingItems))
      }
    },
    [disabled, draggingItems, evaluateDrop]
  )

  const onDragLeave = useCallback(() => {
    enterCountRef.current = Math.max(0, enterCountRef.current - 1)
    if (enterCountRef.current === 0) {
      setIsOver(false)
      setCanDrop(false)
      clearExpandTimer()
    }
  }, [clearExpandTimer])

  const onDrop = useCallback(
    (event: React.DragEvent) => {
      event.preventDefault()
      event.stopPropagation()
      enterCountRef.current = 0
      setIsOver(false)
      setCanDrop(false)
      clearExpandTimer()

      if (disabled) return
      const sources = resolveSources(event)
      if (!sources) return
      if (isMoveDestinationBlocked(sources, folderPath)) {
        toast.error("Impossible de déplacer un dossier dans lui-même")
        return
      }
      if (isMoveToSameFolder(sources, folderPath)) return

      void (async () => {
        try {
          await moveDriveItemsToFolder(sources, folderPath, (body) =>
            mutations.move.mutateAsync(body)
          )
          toast.success(sources.length > 1 ? "Éléments déplacés" : "Élément déplacé")
          clearSelection()
        } catch {
          toast.error("Impossible de déplacer")
        } finally {
          setDraggingItems(null)
        }
      })()
    },
    [
      clearExpandTimer,
      clearSelection,
      disabled,
      folderPath,
      mutations.move,
      resolveSources,
      setDraggingItems,
    ]
  )

  return {
    isOver,
    canDrop,
    dropProps: disabled
      ? ({} as const)
      : ({
          onDragOver,
          onDragEnter,
          onDragLeave,
          onDrop,
        } as const),
  }
}
