"use client"

import { useCallback, useEffect, useRef } from "react"
import type { DocsGraphicAttrs } from "@/lib/drive/docs-graphic-types"
import { cn } from "@/lib/utils"

const HANDLES = ["nw", "n", "ne", "e", "se", "s", "sw", "w"] as const
type Handle = (typeof HANDLES)[number]

const HANDLE_CLASS: Record<Handle, string> = {
  nw: "left-0 top-0 cursor-nwse-resize",
  n: "left-1/2 top-0 -translate-x-1/2 cursor-ns-resize",
  ne: "right-0 top-0 cursor-nesw-resize",
  e: "right-0 top-1/2 -translate-y-1/2 cursor-ew-resize",
  se: "right-0 bottom-0 cursor-nwse-resize",
  s: "left-1/2 bottom-0 -translate-x-1/2 cursor-ns-resize",
  sw: "left-0 bottom-0 cursor-nesw-resize",
  w: "left-0 top-1/2 -translate-y-1/2 cursor-ew-resize",
}

function clamp01(v: number): number {
  return Math.min(1, Math.max(0, v))
}

function resizeCrop(
  handle: Handle,
  crop: Pick<DocsGraphicAttrs, "cropX" | "cropY" | "cropWidth" | "cropHeight">,
  dxNorm: number,
  dyNorm: number
): Pick<DocsGraphicAttrs, "cropX" | "cropY" | "cropWidth" | "cropHeight"> {
  let { cropX, cropY, cropWidth, cropHeight } = crop
  if (handle.includes("e")) cropWidth = clamp01(cropWidth + dxNorm)
  if (handle.includes("w")) {
    cropWidth = clamp01(cropWidth - dxNorm)
    cropX = clamp01(cropX + dxNorm)
  }
  if (handle.includes("s")) cropHeight = clamp01(cropHeight + dyNorm)
  if (handle.includes("n")) {
    cropHeight = clamp01(cropHeight - dyNorm)
    cropY = clamp01(cropY + dyNorm)
  }
  cropWidth = Math.max(0.05, cropWidth)
  cropHeight = Math.max(0.05, cropHeight)
  return { cropX, cropY, cropWidth, cropHeight }
}

export function DocsGraphicCropOverlay({
  attrs,
  frameWidth,
  frameHeight,
  onChange,
  onDone,
}: {
  attrs: DocsGraphicAttrs
  frameWidth: number
  frameHeight: number
  onChange: (patch: Partial<DocsGraphicAttrs>) => void
  onDone: () => void
}) {
  const dragRef = useRef<{
    handle: Handle
    startX: number
    startY: number
    origin: Pick<DocsGraphicAttrs, "cropX" | "cropY" | "cropWidth" | "cropHeight">
  } | null>(null)

  const onHandleDown = useCallback(
    (handle: Handle, event: React.PointerEvent) => {
      event.preventDefault()
      event.stopPropagation()
      ;(event.currentTarget as HTMLElement).setPointerCapture(event.pointerId)
      dragRef.current = {
        handle,
        startX: event.clientX,
        startY: event.clientY,
        origin: {
          cropX: attrs.cropX,
          cropY: attrs.cropY,
          cropWidth: attrs.cropWidth,
          cropHeight: attrs.cropHeight,
        },
      }
    },
    [attrs.cropHeight, attrs.cropWidth, attrs.cropX, attrs.cropY]
  )

  useEffect(() => {
    const onMove = (event: PointerEvent) => {
      if (!dragRef.current) return
      const { handle, startX, startY, origin } = dragRef.current
      const dxNorm = (event.clientX - startX) / Math.max(frameWidth, 1)
      const dyNorm = (event.clientY - startY) / Math.max(frameHeight, 1)
      onChange(resizeCrop(handle, origin, dxNorm, dyNorm))
    }
    const onUp = () => {
      dragRef.current = null
    }
    window.addEventListener("pointermove", onMove)
    window.addEventListener("pointerup", onUp)
    return () => {
      window.removeEventListener("pointermove", onMove)
      window.removeEventListener("pointerup", onUp)
    }
  }, [frameHeight, frameWidth, onChange])

  useEffect(() => {
    const onKey = (event: KeyboardEvent) => {
      if (event.key === "Escape") onDone()
    }
    window.addEventListener("keydown", onKey)
    return () => window.removeEventListener("keydown", onKey)
  }, [onDone])

  const left = `${attrs.cropX * 100}%`
  const top = `${attrs.cropY * 100}%`
  const width = `${attrs.cropWidth * 100}%`
  const height = `${attrs.cropHeight * 100}%`

  return (
    <div className="docs-graphic-crop absolute inset-0 z-30" aria-label="Recadrage">
      <div className="absolute inset-0 bg-black/40" />
      <div
        className={cn(
          "absolute border-2 border-white shadow-[0_0_0_1px_#1a73e8]",
          attrs.cropShape === "ellipse" && "rounded-full"
        )}
        style={{ left, top, width, height }}
      >
        {HANDLES.map((handle) => (
          <span
            key={handle}
            role="presentation"
            className={cn(
              "absolute z-40 size-2.5 rounded-full border border-white bg-[#1a73e8] shadow",
              HANDLE_CLASS[handle]
            )}
            onPointerDown={(event) => onHandleDown(handle, event)}
          />
        ))}
      </div>
    </div>
  )
}
