"use client"

import { useCallback, useEffect, useMemo, useState, type ReactNode } from "react"
import { useRouter } from "next/navigation"
import type { Editor } from "@tiptap/react"
import { toast } from "sonner"
import { DocsDetailsDialog } from "@/components/drive/richtext/docs-details-dialog"
import { DocsOpenDialog } from "@/components/drive/richtext/docs-open-dialog"
import { DocsPageSetupDialog } from "@/components/drive/richtext/docs-page-setup-dialog"
import type { DocsFileMenuActions } from "@/components/drive/richtext/docs-file-menu"
import { DriveMoveDialog } from "@/components/drive/drive-move-dialog"
import { DriveNameDialog } from "@/components/drive/drive-name-dialog"
import { apiClient } from "@/lib/api/client"
import { useDriveList, useDriveMutations } from "@/lib/api/hooks/use-drive-queries"
import type { DriveFileInfo } from "@/lib/api/types"
import { displayFileName } from "@/lib/drive/display-file-name"
import { nextUntitledName } from "@/lib/drive/drive-default-name"
import { buildMoveDestination, parentFolderPath } from "@/lib/drive/drive-move-items"
import { buildDriveDocsEditHref } from "@/lib/drive/drive-url"
import type { DocsExportSnapshot } from "@/lib/drive/docs-export-snapshot"
import {
  exportDocsContent,
  type DocsDownloadFormat,
} from "@/lib/drive/docs-file-menu-export"
import { printDocsDocument } from "@/lib/drive/docs-print"
import { openRichTextDocument } from "@/lib/drive/open-rich-text-document"
import type { PageFormatId } from "@/lib/drive/page-formats"
import type { DocPageSetup } from "@/lib/drive/doc-page-setup"
import { useDocsKeyboardShortcutsStore } from "@/lib/stores/docs-keyboard-shortcuts-store"

function buildCopyFileName(originalName: string, siblingNames: string[]): string {
  const name = displayFileName(originalName)
  const dot = name.lastIndexOf(".")
  const base = dot > 0 ? name.slice(0, dot) : name
  const ext = dot > 0 ? name.slice(dot) : ""
  const siblings = siblingNames.map(displayFileName)

  let candidate = `Copie de ${base}${ext}`
  if (!siblings.includes(candidate)) return candidate

  let n = 2
  while (siblings.includes(`Copie de ${base} (${n})${ext}`)) {
    n += 1
  }
  return `Copie de ${base} (${n})${ext}`
}

export function useDocsFileMenu({
  file,
  editor,
  pageSetup,
  fallbackFormatId,
  getExportSnapshot,
  onPageSetupApply,
  onShareClick,
  onRenameRequest,
  onFileMoved,
  onPurgeSidecarAndReimport,
  disabled,
}: {
  file?: DriveFileInfo
  editor: Editor | null
  pageSetup: DocPageSetup | null
  fallbackFormatId: PageFormatId
  getExportSnapshot: () => DocsExportSnapshot | null
  onPageSetupApply: (setup: DocPageSetup) => void
  onShareClick?: () => void
  onRenameRequest?: () => void
  onFileMoved?: (newPath: string) => void
  onPurgeSidecarAndReimport?: () => void
  disabled?: boolean
}) {
  const router = useRouter()
  const mutations = useDriveMutations()
  const parentPath = file ? parentFolderPath(file.path) : "/"
  const siblingList = useDriveList(parentPath, 1, "", false)
  const siblingNames = useMemo(
    () => (siblingList.data?.files ?? []).map((item) => item.name),
    [siblingList.data?.files]
  )

  const [openDialogOpen, setOpenDialogOpen] = useState(false)
  const [moveDialogOpen, setMoveDialogOpen] = useState(false)
  const [newDocDialogOpen, setNewDocDialogOpen] = useState(false)
  const [pageSetupOpen, setPageSetupOpen] = useState(false)
  const [detailsOpen, setDetailsOpen] = useState(false)
  const [newDocDefaultName, setNewDocDefaultName] = useState("")

  const navigateToFile = useCallback(
    async (path: string) => {
      const info = await apiClient.get<DriveFileInfo>(
        `/drive/files/info${path.startsWith("/") ? path : `/${path}`}`
      )
      if (!info.file_id) {
        throw new Error("Identifiant du document introuvable")
      }
      router.push(buildDriveDocsEditHref(info.file_id))
    },
    [router]
  )

  const createDocument = useCallback(
    async (rawName: string) => {
      const name = rawName.trim().replace(/\//g, "")
      if (!name) return
      const fileName = name.endsWith(".docx") ? name : `${name}.docx`
      try {
        const { path } = await mutations.createFile.mutateAsync({
          parent_path: parentPath,
          name: fileName,
          kind: "document",
        })
        toast.success("Document créé")
        await navigateToFile(path)
      } catch {
        toast.error("Impossible de créer le document")
        throw new Error("create failed")
      }
    },
    [mutations.createFile, navigateToFile, parentPath]
  )

  const makeCopy = useCallback(async () => {
    if (!file) return
    const copyName = buildCopyFileName(file.name, siblingNames)
    const destination = buildMoveDestination(parentPath, copyName)
    try {
      await mutations.copy.mutateAsync({ source: file.path, destination })
      toast.success("Copie créée")
      await navigateToFile(destination)
    } catch {
      toast.error("Impossible de créer la copie")
    }
  }, [file, mutations.copy, navigateToFile, parentPath, siblingNames])

  const moveToTrash = useCallback(async () => {
    if (!file) return
    try {
      await mutations.deleteFile.mutateAsync(file.path)
      toast.success("Document déplacé dans la corbeille")
      router.push("/drive")
    } catch {
      toast.error("Impossible de déplacer dans la corbeille")
    }
  }, [file, mutations.deleteFile, router])

  const downloadFormat = useCallback(
    async (format: DocsDownloadFormat) => {
      if (!file) return

      if (format === "html-zip" || format === "odt" || format === "rtf" || format === "epub") {
        toast.info("Export bientôt disponible pour ce format")
        return
      }

      const snapshot = getExportSnapshot()
      const loadingToast =
        format === "pdf" ? toast.loading("Génération du PDF…") : undefined

      try {
        const result = await exportDocsContent(format, snapshot, editor, file.name)
        if (result === "unsupported") {
          toast.error("Export indisponible")
        } else if (format === "pdf") {
          toast.success("PDF téléchargé")
        }
      } catch {
        toast.error("Échec de l'export")
      } finally {
        if (loadingToast != null) toast.dismiss(loadingToast)
      }
    },
    [editor, file, getExportSnapshot]
  )

  const handlePrint = useCallback(async () => {
    const snapshot = getExportSnapshot()
    if (!snapshot) {
      toast.error("Impossible d'imprimer le document")
      return
    }
    try {
      await printDocsDocument(snapshot)
    } catch (error) {
      console.error("[docs] print failed", error)
      toast.error("Impossible d'imprimer le document")
    }
  }, [getExportSnapshot])

  const soon = useCallback((label: string) => {
    toast.info(`${label} — bientôt disponible`)
  }, [])

  const menuDisabled = disabled || !file

  const actions = useMemo<DocsFileMenuActions>(
    () => ({
      onNewDocument: () => {
        setNewDocDefaultName(nextUntitledName(siblingNames, "Document", ".docx"))
        setNewDocDialogOpen(true)
      },
      onNewFromTemplate: () => soon("Galerie de modèles"),
      onOpen: () => setOpenDialogOpen(true),
      onMakeCopy: () => void makeCopy(),
      onShareWithUsers: () => onShareClick?.(),
      onPublishToWeb: () => onShareClick?.(),
      onEmailFile: () => soon("Envoi par e-mail"),
      onEmailCollaborators: () => soon("Envoi aux collaborateurs"),
      onEmailDraft: () => soon("Brouillon d'e-mail"),
      onDownload: (format) => void downloadFormat(format),
      onRename: () => onRenameRequest?.(),
      onMove: () => setMoveDialogOpen(true),
      onAddShortcut: () => soon("Raccourci Drive"),
      onMoveToTrash: () => void moveToTrash(),
      onNameCurrentVersion: () => soon("Nommer la version actuelle"),
      onShowVersionHistory: () => soon("Historique des versions"),
      onToggleOffline: () => soon("Disponible hors connexion"),
      onDetails: () => setDetailsOpen(true),
      onSecurityLimits: () => soon("Limites de sécurité"),
      onPageSetup: () => setPageSetupOpen(true),
      onPrint: () => void handlePrint(),
      ...(onPurgeSidecarAndReimport
        ? { onPurgeSidecarAndReimport: () => void onPurgeSidecarAndReimport() }
        : {}),
    }),
    [
      downloadFormat,
      handlePrint,
      makeCopy,
      moveToTrash,
      onPurgeSidecarAndReimport,
      onRenameRequest,
      onShareClick,
      siblingNames,
      soon,
    ]
  )

  useEffect(() => {
    if (menuDisabled) return

    const onKeyDown = (event: KeyboardEvent) => {
      const id = useDocsKeyboardShortcutsStore.getState().matchEvent(
        event,
        (definition) => definition.scope === "document" && definition.handler === "custom"
      )
      if (id === "file.open") {
        event.preventDefault()
        setOpenDialogOpen(true)
        return
      }
      if (id === "file.print") {
        event.preventDefault()
        void handlePrint()
      }
    }

    window.addEventListener("keydown", onKeyDown)
    return () => window.removeEventListener("keydown", onKeyDown)
  }, [handlePrint, menuDisabled])

  const dialogs: ReactNode = file ? (
    <>
      <DocsOpenDialog
        open={openDialogOpen}
        onOpenChange={setOpenDialogOpen}
        onOpenFile={(target) =>
          openRichTextDocument(target, {
            push: (href) => router.push(href),
          })
        }
      />
      <DriveMoveDialog
        open={moveDialogOpen}
        onOpenChange={setMoveDialogOpen}
        sources={[file]}
        mode="move"
        onMoved={(destinationFolder) => {
          if (!destinationFolder) return
          onFileMoved?.(buildMoveDestination(destinationFolder, file.name))
        }}
      />
      <DriveNameDialog
        open={newDocDialogOpen}
        onOpenChange={setNewDocDialogOpen}
        title="Nouveau document"
        description="Nom du document à créer dans le dossier actuel."
        defaultValue={newDocDefaultName}
        confirmLabel="Créer"
        onConfirm={createDocument}
      />
      <DocsPageSetupDialog
        open={pageSetupOpen}
        onOpenChange={setPageSetupOpen}
        pageSetup={pageSetup}
        fallbackFormatId={fallbackFormatId}
        onApply={onPageSetupApply}
      />
      <DocsDetailsDialog open={detailsOpen} onOpenChange={setDetailsOpen} file={file} />
    </>
  ) : null

  return {
    actions,
    dialogs,
    disabled: menuDisabled,
  }
}
