"use client"

import { memo, useCallback, useEffect, useRef, useState } from "react"
import { createPortal } from "react-dom"
import type { Editor } from "@tiptap/react"
import { Icon } from "@iconify/react"
import {
  ArrowDown,
  ArrowUp,
  Check,
  ChevronDown,
  Crop,
  MoreHorizontal,
  Settings2,
  Shapes,
} from "lucide-react"
import { Button } from "@/components/ui/button"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { DOCS_GRAPHIC_WRAP_MARGIN_PRESETS_MM } from "@/lib/drive/docs-graphic-layout"
import { usesPageLayer } from "@/lib/drive/docs-graphic-position"
import {
  DOCS_GRAPHIC_WRAP_LABELS,
  parseGraphicAttrs,
  type DocsGraphicFloatSide,
  type DocsGraphicPositionMode,
  type DocsGraphicWrap,
} from "@/lib/drive/docs-graphic-types"
import {
  DOCS_GRAPHIC_ADVANCED_WRAP_ACTIONS,
  DOCS_GRAPHIC_FLOATING_WRAP_ACTIONS,
  DOCS_GRAPHIC_FLOAT_SIDE_ICONS,
  DOCS_GRAPHIC_FLOAT_SIDE_LABELS,
  DOCS_GRAPHIC_LAYER_WRAP_ACTIONS,
  DOCS_GRAPHIC_POSITION_MODE_SHORT_LABELS,
  DOCS_GRAPHIC_WRAP_ICONS,
} from "@/lib/drive/docs-graphic-ui"
import { openDocsGraphicDrawEditor } from "@/lib/drive/docs-graphic-draw-bridge"
import { readGraphicToolbarActive } from "@/components/drive/richtext/docs-graphic-toolbar-menu"
import { openDocsGraphicOptionsSidebar } from "@/components/drive/richtext/docs-graphic-options-sidebar"
import {
  applyDocsGraphicCrop,
  DOCS_GRAPHIC_CROP_CHANGED_EVENT,
  readDocsGraphicCropActive,
  startDocsGraphicCrop,
} from "@/lib/drive/docs-graphic-crop-bridge"
import { cn } from "@/lib/utils"

function readSelectedGraphic(editor: Editor) {
  const name = editor.isActive("docsInlineGraphic")
    ? "docsInlineGraphic"
    : editor.isActive("docsGraphic")
      ? "docsGraphic"
      : null
  if (!name) return null
  return {
    name,
    attrs: parseGraphicAttrs(editor.getAttributes(name) as Record<string, unknown>),
  }
}

function ToolbarDivider() {
  return <span className="mx-0.5 h-6 w-px shrink-0 bg-border" aria-hidden />
}

function keepEditorSelectionOnMenuClose(event: Event) {
  event.preventDefault()
}

function IconToolbarButton({
  label,
  active,
  onClick,
  children,
}: {
  label: string
  active?: boolean
  onClick: () => void
  children: React.ReactNode
}) {
  return (
    <Button
      type="button"
      variant="ghost"
      size="icon"
      className={cn(
        "size-8 shrink-0 rounded-full text-popover-foreground hover:bg-accent hover:text-accent-foreground",
        active && "bg-accent text-primary hover:bg-accent hover:text-primary"
      )}
      aria-label={label}
      title={label}
      onClick={onClick}
    >
      {children}
    </Button>
  )
}

function DocsGraphicFloatingToolbarInner({
  editor,
  canvasRef,
  disabled,
}: {
  editor: Editor | null
  canvasRef: React.RefObject<HTMLElement | null>
  disabled?: boolean
}) {
  const [rect, setRect] = useState<DOMRect | null>(null)
  const [cropActive, setCropActive] = useState(false)
  const [, setTick] = useState(0)
  const replaceInputRef = useRef<HTMLInputElement>(null)

  const refresh = useCallback(() => {
    setTick((t) => t + 1)
    if (!editor || !readGraphicToolbarActive(editor)) {
      setRect(null)
      return
    }
    const selected = document.querySelector(
      ".docs-graphic--selected, .ProseMirror-selectednode .docs-graphic"
    ) as HTMLElement | null
    if (!selected) {
      setRect(null)
      return
    }
    setRect(selected.getBoundingClientRect())
    setCropActive(readDocsGraphicCropActive())
  }, [editor])

  useEffect(() => {
    if (!editor) return
    refresh()
    editor.on("selectionUpdate", refresh)
    editor.on("transaction", refresh)
    const canvas = canvasRef.current
    canvas?.addEventListener("scroll", refresh, { passive: true })
    window.addEventListener("resize", refresh)
    window.addEventListener(DOCS_GRAPHIC_CROP_CHANGED_EVENT, refresh)
    return () => {
      editor.off("selectionUpdate", refresh)
      editor.off("transaction", refresh)
      canvas?.removeEventListener("scroll", refresh)
      window.removeEventListener("resize", refresh)
      window.removeEventListener(DOCS_GRAPHIC_CROP_CHANGED_EVENT, refresh)
    }
  }, [canvasRef, editor, refresh])

  if (!editor || disabled || !readGraphicToolbarActive(editor) || !rect) return null

  const graphic = readSelectedGraphic(editor)
  if (!graphic) return null

  const { attrs } = graphic
  const isImage = attrs.graphicType === "image"
  const isGradient = attrs.graphicType === "gradient"
  const isDraw = attrs.graphicType === "draw" || attrs.graphicType === "shape"
  const moveWithText = attrs.positionMode === "move-with-text"
  const showInFlowWrap = moveWithText
  const showPageLayerActions = usesPageLayer(attrs)
  const showAlign = moveWithText

  const run = (fn: () => void) => fn()

  const applyWrap = (wrap: DocsGraphicWrap) => {
    run(() => editor.chain().setDocsGraphicWrap(wrap).run())
  }
  const applyPositionMode = (positionMode: DocsGraphicPositionMode) => {
    run(() => editor.chain().setDocsGraphicPositionMode(positionMode).run())
  }
  const applyMargin = (wrapMarginMm: number) => {
    run(() => editor.chain().setDocsGraphicWrapMargin(wrapMarginMm).run())
  }
  const applyFloatSide = (floatSide: DocsGraphicFloatSide) => {
    run(() => editor.chain().setDocsGraphicFloatSide(floatSide).run())
  }

  const downloadImage = () => {
    if (!attrs.src) return
    const link = document.createElement("a")
    link.href = attrs.src
    link.download = "image"
    link.click()
  }

  const toolbar = (
    <div
      className="docs-graphic-floating-toolbar pointer-events-auto fixed z-200 -translate-x-1/2"
      style={{ left: rect.left + rect.width / 2, top: rect.bottom + 8 }}
      role="toolbar"
      aria-label="Options graphique"
    >
      <div className="flex items-center gap-0.5 rounded-full border border-border bg-popover px-1 py-0.5 text-popover-foreground shadow-md">
        {isImage || isDraw ? (
          <Button
            type="button"
            variant={isImage && cropActive ? "default" : "ghost"}
            size="sm"
            className={cn(
              "h-8 shrink-0 gap-1.5 rounded-full px-2.5 text-xs",
              isImage && cropActive
                ? "bg-primary text-primary-foreground hover:bg-primary/90 hover:text-primary-foreground"
                : "hover:bg-accent hover:text-accent-foreground"
            )}
            onClick={() => {
              if (isImage) {
                if (cropActive) applyDocsGraphicCrop()
                else startDocsGraphicCrop()
              } else {
                openDocsGraphicDrawEditor(editor)
              }
            }}
          >
            {isImage ? (
              cropActive ? (
                <Check className="size-3.5" />
              ) : (
                <Crop className="size-3.5" />
              )
            ) : (
              <Shapes className="size-3.5" />
            )}
            {isImage ? (cropActive ? "Appliquer" : "Ajuster") : "Modifier le dessin"}
          </Button>
        ) : null}

        {showAlign ? (
          <>
            <ToolbarDivider />
            <DropdownMenu>
              <DropdownMenuTrigger asChild>
                <Button
                  type="button"
                  variant="ghost"
                  size="sm"
                  className="h-8 shrink-0 gap-1 rounded-full px-2 text-xs hover:bg-accent hover:text-accent-foreground"
                >
                  <Icon
                    icon={DOCS_GRAPHIC_FLOAT_SIDE_ICONS[attrs.floatSide]}
                    className="size-[18px]"
                  />
                  <ChevronDown className="size-3 opacity-60" />
                </Button>
              </DropdownMenuTrigger>
              <DropdownMenuContent
                align="start"
                className="min-w-40"
                onCloseAutoFocus={keepEditorSelectionOnMenuClose}
              >
                {(Object.keys(DOCS_GRAPHIC_FLOAT_SIDE_LABELS) as DocsGraphicFloatSide[]).map(
                  (side) => (
                    <DropdownMenuItem key={side} onClick={() => applyFloatSide(side)}>
                      <Icon icon={DOCS_GRAPHIC_FLOAT_SIDE_ICONS[side]} className="mr-2 size-4" />
                      {DOCS_GRAPHIC_FLOAT_SIDE_LABELS[side]}
                      {attrs.floatSide === side ? " ✓" : ""}
                    </DropdownMenuItem>
                  )
                )}
              </DropdownMenuContent>
            </DropdownMenu>
          </>
        ) : null}

        {showInFlowWrap ? (
          <>
            <ToolbarDivider />
            <DropdownMenu>
              <DropdownMenuTrigger asChild>
                <Button
                  type="button"
                  variant="ghost"
                  size="sm"
                  className="h-8 max-w-[140px] shrink-0 gap-1 truncate rounded-full px-2 text-xs hover:bg-accent hover:text-accent-foreground"
                >
                  <Icon icon="material-symbols:wrap-text" className="size-[18px] shrink-0" />
                  <span className="truncate">
                    {DOCS_GRAPHIC_WRAP_LABELS[attrs.wrap] ?? "Habillage"}
                  </span>
                  <ChevronDown className="size-3 shrink-0 opacity-60" />
                </Button>
              </DropdownMenuTrigger>
              <DropdownMenuContent
                align="start"
                className="min-w-48"
                onCloseAutoFocus={keepEditorSelectionOnMenuClose}
              >
                {DOCS_GRAPHIC_FLOATING_WRAP_ACTIONS.map(({ wrap, label }) => (
                  <DropdownMenuItem key={wrap} onClick={() => applyWrap(wrap)}>
                    <Icon icon={DOCS_GRAPHIC_WRAP_ICONS[wrap]} className="mr-2 size-4" />
                    {label}
                    {attrs.wrap === wrap ? " ✓" : ""}
                  </DropdownMenuItem>
                ))}
                <DropdownMenuSeparator />
                {DOCS_GRAPHIC_ADVANCED_WRAP_ACTIONS.map(({ wrap, label }) => (
                  <DropdownMenuItem key={wrap} onClick={() => applyWrap(wrap)}>
                    <Icon icon={DOCS_GRAPHIC_WRAP_ICONS[wrap]} className="mr-2 size-4" />
                    {label}
                    {attrs.wrap === wrap ? " ✓" : ""}
                  </DropdownMenuItem>
                ))}
              </DropdownMenuContent>
            </DropdownMenu>
          </>
        ) : null}

        {showPageLayerActions ? (
          <>
            <ToolbarDivider />
            {DOCS_GRAPHIC_LAYER_WRAP_ACTIONS.map(({ wrap, label }) => (
              <IconToolbarButton
                key={wrap}
                label={label}
                active={attrs.wrap === wrap}
                onClick={() => applyWrap(wrap)}
              >
                <Icon icon={DOCS_GRAPHIC_WRAP_ICONS[wrap]} className="size-[18px]" />
              </IconToolbarButton>
            ))}
          </>
        ) : null}

        <ToolbarDivider />

        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <Button
              type="button"
              variant="ghost"
              size="sm"
              className="h-8 shrink-0 gap-1 rounded-full px-2 text-xs hover:bg-accent hover:text-accent-foreground"
            >
              {attrs.wrapMarginMm}mm
              <ChevronDown className="size-3 opacity-60" />
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent
            align="center"
            className="min-w-40"
            onCloseAutoFocus={keepEditorSelectionOnMenuClose}
          >
            {DOCS_GRAPHIC_WRAP_MARGIN_PRESETS_MM.map((mm) => (
              <DropdownMenuItem key={mm} onClick={() => applyMargin(mm)}>
                Marge de {mm}mm{attrs.wrapMarginMm === mm ? " ✓" : ""}
              </DropdownMenuItem>
            ))}
          </DropdownMenuContent>
        </DropdownMenu>

        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <Button
              type="button"
              variant="ghost"
              size="sm"
              className="h-8 shrink-0 gap-1 rounded-full px-2 text-xs hover:bg-accent hover:text-accent-foreground"
            >
              <Icon icon="material-symbols:pin" className="size-[18px]" />
              {DOCS_GRAPHIC_POSITION_MODE_SHORT_LABELS[attrs.positionMode]}
              <ChevronDown className="size-3 opacity-60" />
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent
            align="start"
            className="min-w-48"
            onCloseAutoFocus={keepEditorSelectionOnMenuClose}
          >
            {(["move-with-text", "fixed-on-page"] as DocsGraphicPositionMode[]).map((mode) => (
              <DropdownMenuItem key={mode} onClick={() => applyPositionMode(mode)}>
                {DOCS_GRAPHIC_POSITION_MODE_SHORT_LABELS[mode]}
                {attrs.positionMode === mode ? " ✓" : ""}
              </DropdownMenuItem>
            ))}
          </DropdownMenuContent>
        </DropdownMenu>

        {showPageLayerActions ? (
          <>
            <IconToolbarButton
              label="Avancer"
              onClick={() => run(() => editor.chain().bringDocsGraphicForward().run())}
            >
              <ArrowUp className="size-4" />
            </IconToolbarButton>
            <IconToolbarButton
              label="Reculer"
              onClick={() => run(() => editor.chain().sendDocsGraphicBackward().run())}
            >
              <ArrowDown className="size-4" />
            </IconToolbarButton>
            <ToolbarDivider />
          </>
        ) : null}

        <Button
          type="button"
          variant="ghost"
          size="sm"
          className="h-8 shrink-0 gap-1.5 rounded-full px-2.5 text-xs hover:bg-accent hover:text-accent-foreground"
          onClick={() =>
            openDocsGraphicOptionsSidebar(
              isImage ? undefined : isGradient ? "gradient" : undefined
            )
          }
        >
          <Settings2 className="size-3.5" />
          {isImage
            ? "Options de l'image"
            : isGradient
              ? "Options du dégradé"
              : "Options"}
        </Button>

        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <Button
              type="button"
              variant="ghost"
              size="icon"
              className="size-8 shrink-0 rounded-full hover:bg-accent hover:text-accent-foreground"
              aria-label="Plus d'options"
            >
              <MoreHorizontal className="size-4" />
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent
            align="end"
            className="min-w-48"
            onCloseAutoFocus={keepEditorSelectionOnMenuClose}
          >
            {isImage ? (
              <>
                <DropdownMenuItem
                  onClick={() => {
                    const alt = window.prompt("Texte alternatif", attrs.alt)
                    if (alt != null) run(() => editor.chain().updateDocsGraphic({ alt }).run())
                  }}
                >
                  Texte alternatif…
                </DropdownMenuItem>
                <DropdownMenuSeparator />
                <DropdownMenuItem onClick={() => replaceInputRef.current?.click()}>
                  Remplacer l&apos;image…
                </DropdownMenuItem>
                <DropdownMenuItem onClick={downloadImage} disabled={!attrs.src}>
                  Télécharger l&apos;image
                </DropdownMenuItem>
              </>
            ) : null}
            <DropdownMenuSeparator />
            <DropdownMenuItem
              variant="destructive"
              onClick={() => run(() => editor.chain().focus().deleteSelection().run())}
            >
              Supprimer
            </DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>
        <input
          ref={replaceInputRef}
          type="file"
          accept="image/*"
          className="hidden"
          onChange={(event) => {
            const file = event.target.files?.[0]
            if (!file) return
            const reader = new FileReader()
            reader.onload = () => {
              run(() =>
                editor.chain().focus().updateDocsGraphic({ src: reader.result as string }).run()
              )
            }
            reader.readAsDataURL(file)
            event.target.value = ""
          }}
        />
      </div>
    </div>
  )

  return createPortal(toolbar, document.body)
}

export const DocsGraphicFloatingToolbar = memo(DocsGraphicFloatingToolbarInner)
