"use client"

import type { ReactNode } from "react"
import { useCallback, useMemo, useRef, useState } from "react"
import { toast } from "sonner"
import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"
import { Sheet, SheetContent, SheetDescription, SheetTitle } from "@/components/ui/sheet"
import { DriveMoveDialog, type DriveFolderPickerMode } from "@/components/drive/drive-move-dialog"
import { useDriveMutations } from "@/lib/api/hooks/use-drive-queries"
import type { DriveFileInfo } from "@/lib/api/types"
import { displayFileName } from "@/lib/drive/display-file-name"
import { resolveRenameName } from "@/lib/drive/drive-default-name"
import { useLongPress } from "@/hooks/use-long-press"
import { useIsMobile } from "@/hooks/use-mobile"
import { mergeDriveCardRefs, useDriveCardRefRegistrar } from "@/components/drive/drive-card-ref-context"
import { useDriveDragSource } from "@/lib/hooks/use-drive-drag-source"
import { useDriveDropTarget } from "@/lib/hooks/use-drive-drop-target"
import {
  guardDriveMenuPointer,
  isCardOpenSuppressed,
  isFromDriveMenu,
} from "@/lib/drive/drive-menu-guard"
import { useDriveUIStore } from "@/lib/stores/drive-ui-store"
import { DriveNameDialog } from "@/components/drive/drive-name-dialog"
import { DriveFileMenuActions } from "@/components/drive/drive-file-menu-actions"
import { MAIL_MENU_SURFACE_CLASS } from "@/lib/mail-chrome-classes"
import { cn } from "@/lib/utils"

export const DRIVE_MENU_SURFACE_CLASS = cn(
  MAIL_MENU_SURFACE_CLASS,
  "z-50 min-w-[12rem] p-1"
)

export const DRIVE_CARD_HIGHLIGHT_CLASS = "bg-mail-active"

export const DRIVE_DROP_TARGET_CLASS =
  "ring-2 ring-[#1a73e8] ring-inset bg-[#e8f0fe] dark:bg-primary/20"

const MOBILE_TAP_SLOP_PX = 10

export function DriveFileContextMenu({
  file,
  allItems,
  isTrash,
  allowShare = true,
  writable = true,
  hideFavorite = false,
  disableDnd = false,
  mutations: mutationsProp,
  onDownloadRequest,
  onOpen,
  children,
  className,
  variant = "default",
  registerRef,
  onItemClick,
  onContextMenuActiveChange,
}: {
  file: DriveFileInfo
  allItems: DriveFileInfo[]
  isTrash?: boolean
  allowShare?: boolean
  writable?: boolean
  hideFavorite?: boolean
  disableDnd?: boolean
  mutations?: ReturnType<typeof useDriveMutations>
  onDownloadRequest?: () => void
  onOpen: () => void
  children: ReactNode
  className?: string
  variant?: "default" | "grid"
  registerRef?: (el: HTMLDivElement | null) => void
  onItemClick?: (file: DriveFileInfo, e: React.MouseEvent) => void
  /** Visual highlight while right-click menu is open (grid cards). */
  onContextMenuActiveChange?: (active: boolean) => void
}) {
  const isMobile = useIsMobile()
  const isGrid = variant === "grid"
  const registerCardRef = useDriveCardRefRegistrar()
  const dndEnabled = !isMobile && !isTrash && !disableDnd
  const isFolder = file.type === "directory"
  const { dragProps } = useDriveDragSource({ file, allItems, disabled: !dndEnabled })
  const { dropProps, canDrop, isOver } = useDriveDropTarget({
    folderPath: file.path,
    disabled: !dndEnabled || !isFolder,
  })
  const [sheetOpen, setSheetOpen] = useState(false)
  const [renameOpen, setRenameOpen] = useState(false)
  const [contextMenuOpen, setContextMenuOpen] = useState(false)
  const [folderPickerMode, setFolderPickerMode] = useState<DriveFolderPickerMode | null>(null)
  const selectedPaths = useDriveUIStore((s) => s.selectedPaths)
  const selectionMode = useDriveUIStore((s) => s.selectionMode)
  const toggleSelect = useDriveUIStore((s) => s.toggleSelect)
  const enterSelectionMode = useDriveUIStore((s) => s.enterSelectionMode)
  const setSharePath = useDriveUIStore((s) => s.setSharePath)
  const mutationsDefault = useDriveMutations()
  const mutations = mutationsProp ?? mutationsDefault

  const openRenameDialog = useCallback(() => {
    guardDriveMenuPointer()
    window.setTimeout(() => setRenameOpen(true), 0)
  }, [])

  /** Context menu / long-press sheet: always the file under cursor, never bulk selection. */
  const targets = useMemo(() => [file], [file])

  const openSheet = useCallback(() => setSheetOpen(true), [])

  const longPress = useLongPress(openSheet, { disabled: !isMobile })
  const touchStartRef = useRef<{ x: number; y: number } | null>(null)
  const touchMovedRef = useRef(false)

  const handleMobilePointerDown = useCallback(
    (e: React.PointerEvent) => {
      touchStartRef.current = { x: e.clientX, y: e.clientY }
      touchMovedRef.current = false
      longPress.onPointerDown(e)
    },
    [longPress]
  )

  const handleMobilePointerMove = useCallback((e: React.PointerEvent) => {
    const start = touchStartRef.current
    if (!start) return
    const dx = e.clientX - start.x
    const dy = e.clientY - start.y
    if (dx * dx + dy * dy > MOBILE_TAP_SLOP_PX * MOBILE_TAP_SLOP_PX) {
      touchMovedRef.current = true
    }
  }, [])

  const handleMobilePointerEnd = useCallback(() => {
    touchStartRef.current = null
    longPress.onPointerUp()
  }, [longPress])

  const handleMobileClickCapture = useCallback(
    (e: React.MouseEvent) => {
      longPress.onClickCapture(e)
      if (touchMovedRef.current) {
        e.preventDefault()
        e.stopPropagation()
        touchMovedRef.current = false
      }
    },
    [longPress]
  )

  const handleRename = async (input: string) => {
    const target = targets[0]
    if (!target) return
    const newName = resolveRenameName(target, input)
    if (displayFileName(target.name) === newName) {
      return
    }
    try {
      await mutations.rename.mutateAsync({ path: target.path, new_name: newName })
      toast.success("Renommé")
    } catch {
      toast.error("Impossible de renommer")
      throw new Error("rename failed")
    }
  }

  const shouldIgnoreCardAction = (target: EventTarget | null) =>
    isFromDriveMenu(target) || isCardOpenSuppressed()

  const handleMobileTap = (e: React.MouseEvent) => {
    if (shouldIgnoreCardAction(e.target)) {
      e.preventDefault()
      e.stopPropagation()
      return
    }
    e.preventDefault()
    e.stopPropagation()
    if (selectionMode) {
      toggleSelect(file.path, !selectedPaths.has(file.path))
      return
    }
    onOpen()
  }

  const touchProps = isMobile
    ? {
        onContextMenu: (e: React.MouseEvent) => {
          e.preventDefault()
          e.stopPropagation()
          openSheet()
        },
        onPointerDown: handleMobilePointerDown,
        onPointerMove: handleMobilePointerMove,
        onPointerUp: handleMobilePointerEnd,
        onPointerLeave: handleMobilePointerEnd,
        onPointerCancel: handleMobilePointerEnd,
        onClickCapture: handleMobileClickCapture,
      }
    : {}

  const handlePointerDownSelect = (e: React.PointerEvent) => {
    if (e.pointerType === "mouse" && (e.ctrlKey || e.metaKey)) {
      e.preventDefault()
      toggleSelect(file.path, !selectedPaths.has(file.path))
    }
    if (isMobile) {
      handleMobilePointerDown(e)
    }
  }

  const handleClickSelect = (e: React.MouseEvent) => {
    if (shouldIgnoreCardAction(e.target)) {
      e.preventDefault()
      e.stopPropagation()
      return
    }
    if (e.ctrlKey || e.metaKey) {
      e.preventDefault()
      e.stopPropagation()
      toggleSelect(file.path, !selectedPaths.has(file.path))
    }
  }

  const handleGridClick = (e: React.MouseEvent) => {
    if (shouldIgnoreCardAction(e.target)) {
      e.preventDefault()
      e.stopPropagation()
      return
    }
    onItemClick?.(file, e)
  }

  const handleOpenDoubleClick = (e: React.MouseEvent) => {
    if (shouldIgnoreCardAction(e.target)) {
      e.preventDefault()
      e.stopPropagation()
      return
    }
    e.preventDefault()
    e.stopPropagation()
    onOpen()
  }

  const handleContextMenuOpenChange = useCallback(
    (open: boolean) => {
      if (open) {
        setContextMenuOpen(true)
        onContextMenuActiveChange?.(true)
        return
      }
      setContextMenuOpen(false)
      onContextMenuActiveChange?.(false)
      guardDriveMenuPointer()
    },
    [onContextMenuActiveChange]
  )

  const closeContextMenu = useCallback(() => {
    handleContextMenuOpenChange(false)
  }, [handleContextMenuOpenChange])

  const mergedRegisterRef = mergeDriveCardRefs(file.path, registerRef, registerCardRef)

  const isSelected = selectedPaths.has(file.path)

  const trigger = (
    <div
      ref={mergedRegisterRef}
      data-drive-card
      data-path={file.path}
      className={cn(
        className,
        !isGrid && isMobile && longPress.ackClassName,
        isFolder && isOver && canDrop && DRIVE_DROP_TARGET_CLASS,
        isSelected && DRIVE_CARD_HIGHLIGHT_CLASS
      )}
      onClick={
        isMobile
          ? handleMobileTap
          : onItemClick
            ? handleGridClick
            : handleClickSelect
      }
      onDoubleClick={isMobile ? undefined : onItemClick ? handleOpenDoubleClick : undefined}
      {...dragProps}
      {...dropProps}
      {...(!isGrid && isMobile
        ? {
            ...touchProps,
            onPointerDown: handlePointerDownSelect,
          }
        : isMobile
          ? touchProps
          : {})}
    >
      {children}
    </div>
  )

  const renameTarget = targets.length === 1 ? targets[0] : null

  const openFolderPicker = (mode: DriveFolderPickerMode) => {
    setSheetOpen(false)
    window.setTimeout(() => setFolderPickerMode(mode), 0)
  }

  const menuActionsProps = {
    targets,
    isTrash,
    allowShare,
    writable,
    hideFavorite,
    onOpen,
    setSharePath,
    mutations,
    onRenameRequest: openRenameDialog,
    onMoveRequest: isTrash || disableDnd ? undefined : () => openFolderPicker("move"),
    onCopyRequest: isTrash || disableDnd ? undefined : () => openFolderPicker("copy"),
    onDownloadRequest,
    onEnterSelectionMode: isTrash
      ? undefined
      : () => {
          enterSelectionMode(file.path)
        },
  }

  const menus = (
    <>
      <DriveNameDialog
        open={renameOpen}
        onOpenChange={setRenameOpen}
        title="Renommer"
        defaultValue={renameTarget ? displayFileName(renameTarget.name) : ""}
        confirmLabel="Renommer"
        onConfirm={handleRename}
      />
      <DriveMoveDialog
        open={folderPickerMode !== null}
        onOpenChange={(open) => {
          if (!open) setFolderPickerMode(null)
        }}
        mode={folderPickerMode ?? "move"}
        sources={targets}
      />
      <Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
        <SheetContent
          side="bottom"
          hideClose
          className="gap-0 overflow-hidden rounded-t-2xl border-border px-0 pb-[max(1rem,env(safe-area-inset-bottom))] pt-2"
        >
          <SheetTitle className="sr-only">
            {targets.length > 1
              ? `${targets.length} éléments`
              : displayFileName(file.name)}
          </SheetTitle>
          <SheetDescription className="sr-only">
            {targets.length > 1
              ? `Actions pour ${targets.length} éléments sélectionnés.`
              : `Actions pour ${displayFileName(file.name)}.`}
          </SheetDescription>
          <p className="truncate px-4 pb-2 text-sm font-medium text-muted-foreground">
            {targets.length > 1
              ? `${targets.length} éléments sélectionnés`
              : displayFileName(file.name)}
          </p>
          <div className="flex flex-col border-t border-border">
            <DriveFileMenuActions
              variant="sheet"
              {...menuActionsProps}
              onClose={() => setSheetOpen(false)}
              onRenameRequest={() => {
                setSheetOpen(false)
                openRenameDialog()
              }}
            />
          </div>
        </SheetContent>
      </Sheet>
    </>
  )

  if (isMobile) {
    return (
      <>
        {trigger}
        {menus}
      </>
    )
  }

  const contextMenu = (
    <ContextMenu open={contextMenuOpen} onOpenChange={handleContextMenuOpenChange}>
      <ContextMenuTrigger asChild>{trigger}</ContextMenuTrigger>
      <ContextMenuContent
        data-drive-menu-surface
        className={cn(DRIVE_MENU_SURFACE_CLASS, "w-52")}
        onCloseAutoFocus={(e) => e.preventDefault()}
      >
        <DriveFileMenuActions
          variant="context"
          {...menuActionsProps}
          onClose={closeContextMenu}
        />
      </ContextMenuContent>
    </ContextMenu>
  )

  return (
    <>
      {contextMenu}
      {menus}
    </>
  )
}
