"use client"

import { useCallback, useMemo, useRef, useState } from "react"
import type { DocPageLayout, DocPageSetup } from "@/lib/drive/doc-page-setup"
import { pxToMm } from "@/lib/drive/doc-page-setup"
import {
  clampPageMarginPx,
  mergeMarginPreview,
  type DocsPageMarginsPx,
  type DocsRulerMarginSide,
} from "@/lib/drive/docs-ruler-margin-math"
import { formatMarginDistanceLabel } from "@/lib/drive/docs-ruler-units"
import type { DocsRulerDragTooltipState } from "@/components/drive/richtext/docs-ruler-markers"

function applyMarginDragPx(
  side: DocsRulerMarginSide,
  rawValuePx: number,
  base: DocsPageMarginsPx,
  preview: Partial<DocsPageMarginsPx> | null,
  pageWidth: number,
  pageHeight: number
): { nextPreview: Partial<DocsPageMarginsPx>; clamped: number } {
  const current = mergeMarginPreview(base, preview)
  let nextValue = rawValuePx
  if (side === "right") {
    nextValue = pageWidth - rawValuePx
  } else if (side === "bottom") {
    nextValue = pageHeight - rawValuePx
  }
  const clamped = clampPageMarginPx(
    side,
    nextValue,
    current,
    pageWidth,
    pageHeight
  )
  return {
    nextPreview: { ...(preview ?? {}), [side]: clamped },
    clamped,
  }
}

export function useDocsRulerMarginDrag({
  pageLayout,
  editable,
  onPageSetupChange,
}: {
  pageLayout: DocPageLayout
  editable: boolean
  onPageSetupChange?: (
    patch: Partial<DocPageSetup>,
    options?: { immediate?: boolean }
  ) => void
}) {
  const [previewPx, setPreviewPx] = useState<Partial<DocsPageMarginsPx> | null>(null)
  const [dragTooltip, setDragTooltip] = useState<DocsRulerDragTooltipState>(null)
  const dragBaseRef = useRef<DocsPageMarginsPx>(pageLayout.marginsPx)
  /** Sync preview during drag — window pointer events don't flush React state in time. */
  const previewRef = useRef<Partial<DocsPageMarginsPx> | null>(null)
  const pageLayoutRef = useRef(pageLayout)
  pageLayoutRef.current = pageLayout

  const marginsPx = useMemo(
    () => mergeMarginPreview(pageLayout.marginsPx, previewPx),
    [pageLayout.marginsPx, previewPx]
  )

  const pageLayoutWithMargins = useMemo(
    (): DocPageLayout => ({
      ...pageLayout,
      marginsPx,
    }),
    [pageLayout, marginsPx]
  )

  const beginMarginDrag = useCallback(
    (_side: DocsRulerMarginSide) => {
      if (!editable) return
      const layout = pageLayoutRef.current
      dragBaseRef.current = mergeMarginPreview(layout.marginsPx, previewRef.current)
      previewRef.current = null
    },
    [editable]
  )

  const moveMarginDrag = useCallback(
    (side: DocsRulerMarginSide, rawValuePx: number, clientX: number, clientY: number) => {
      if (!editable) return

      const layout = pageLayoutRef.current
      const { nextPreview, clamped } = applyMarginDragPx(
        side,
        rawValuePx,
        dragBaseRef.current,
        previewRef.current,
        layout.widthPx,
        layout.heightPx
      )

      previewRef.current = nextPreview
      setPreviewPx(nextPreview)
      setDragTooltip({
        label: formatMarginDistanceLabel(clamped, layout.format.id),
        x: clientX,
        y: clientY,
      })
    },
    [editable]
  )

  const endMarginDrag = useCallback(() => {
    setDragTooltip(null)

    const preview = previewRef.current
    previewRef.current = null

    if (!editable || !preview) {
      setPreviewPx(null)
      return
    }

    const layout = pageLayoutRef.current
    const merged = mergeMarginPreview(layout.marginsPx, preview)
    setPreviewPx(null)

    onPageSetupChange?.(
      {
        marginsMm: {
          top: pxToMm(merged.top),
          right: pxToMm(merged.right),
          bottom: pxToMm(merged.bottom),
          left: pxToMm(merged.left),
        },
      },
      { immediate: true }
    )
  }, [editable, onPageSetupChange])

  const cancelMarginDrag = useCallback(() => {
    previewRef.current = null
    setPreviewPx(null)
    setDragTooltip(null)
  }, [])

  return {
    marginsPx,
    pageLayoutWithMargins,
    marginDragActive: previewPx != null,
    dragTooltip,
    beginMarginDrag,
    moveMarginDrag,
    endMarginDrag,
    cancelMarginDrag,
  }
}
