"use client"

import { useCallback, useEffect, useRef } from "react"
import {
  computeCropDisplayGeometry,
  resizeCropRegion,
  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: "docs-crop-handle--corner docs-crop-handle--nw cursor-nwse-resize",
  n: "docs-crop-handle--edge docs-crop-handle--n cursor-ns-resize",
  ne: "docs-crop-handle--corner docs-crop-handle--ne cursor-nesw-resize",
  e: "docs-crop-handle--edge docs-crop-handle--e cursor-ew-resize",
  se: "docs-crop-handle--corner docs-crop-handle--se cursor-nwse-resize",
  s: "docs-crop-handle--edge docs-crop-handle--s cursor-ns-resize",
  sw: "docs-crop-handle--corner docs-crop-handle--sw cursor-nesw-resize",
  w: "docs-crop-handle--edge docs-crop-handle--w cursor-ew-resize",
}

type CropRegion = Pick<DocsGraphicAttrs, "cropX" | "cropY" | "cropWidth" | "cropHeight">

function pct(value: number, total: number): string {
  return `${(value / Math.max(total, 1)) * 100}%`
}

export function DocsGraphicCropOverlay({
  attrs,
  cropEditBase,
  frameWidth,
  frameHeight,
  imageNaturalWidth,
  imageNaturalHeight,
  onChange,
  onDone,
}: {
  attrs: DocsGraphicAttrs
  cropEditBase?: Pick<DocsGraphicAttrs, "cropX" | "cropY" | "cropWidth" | "cropHeight"> | null
  frameWidth: number
  frameHeight: number
  imageNaturalWidth: number
  imageNaturalHeight: number
  onChange: (patch: Partial<DocsGraphicAttrs>) => void
  onDone: () => void
}) {
  const rootRef = useRef<HTMLDivElement>(null)
  const { windowRect, cropRect } = computeCropDisplayGeometry(
    attrs,
    frameWidth,
    frameHeight,
    imageNaturalWidth,
    imageNaturalHeight,
    cropEditBase
  )
  const dragRef = useRef<{
    handle: Handle
    startX: number
    startY: number
    origin: CropRegion
  } | null>(null)

  const readScale = useCallback(() => {
    const rootRect = rootRef.current?.getBoundingClientRect()
    return rootRect && windowRect.width > 0 ? rootRect.width / windowRect.width : 1
  }, [windowRect.width])

  const beginResize = 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 scale = readScale()
      const dxPx = (event.clientX - startX) / scale
      const dyPx = (event.clientY - startY) / scale
      const dxNorm = dxPx / Math.max(windowRect.width, 1)
      const dyNorm = dyPx / Math.max(windowRect.height, 1)
      onChange(resizeCropRegion(handle, origin, dxNorm, dyNorm))
    }
    const onUp = () => {
      dragRef.current = null
    }
    window.addEventListener("pointermove", onMove)
    window.addEventListener("pointerup", onUp)
    window.addEventListener("pointercancel", onUp)
    return () => {
      window.removeEventListener("pointermove", onMove)
      window.removeEventListener("pointerup", onUp)
      window.removeEventListener("pointercancel", onUp)
    }
  }, [onChange, readScale, windowRect.height, windowRect.width])

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

  const localCropLeft = cropRect.left - windowRect.left
  const localCropTop = cropRect.top - windowRect.top
  const cropWidth = pct(cropRect.width, windowRect.width)
  const cropHeight = pct(cropRect.height, windowRect.height)
  const cropLeft = pct(localCropLeft, windowRect.width)
  const cropTop = pct(localCropTop, windowRect.height)

  const shadeTop = localCropTop
  const shadeLeft = localCropLeft
  const shadeRight = windowRect.width - (localCropLeft + cropRect.width)
  const shadeBottom = windowRect.height - (localCropTop + cropRect.height)

  return (
    <div
      ref={rootRef}
      className="docs-graphic-crop pointer-events-none absolute z-30"
      aria-label="Recadrage"
      style={{
        left: windowRect.left,
        top: windowRect.top,
        width: windowRect.width,
        height: windowRect.height,
      }}
      onDoubleClick={(event) => {
        event.preventDefault()
        event.stopPropagation()
        onDone()
      }}
    >
      {shadeTop > 0 ? (
        <div
          className="pointer-events-none absolute left-0 top-0 bg-black/40"
          style={{ width: "100%", height: pct(shadeTop, windowRect.height) }}
        />
      ) : null}
      {shadeBottom > 0 ? (
        <div
          className="pointer-events-none absolute bottom-0 left-0 bg-black/40"
          style={{ width: "100%", height: pct(shadeBottom, windowRect.height) }}
        />
      ) : null}
      {shadeLeft > 0 ? (
        <div
          className="pointer-events-none absolute bg-black/40"
          style={{
            left: 0,
            top: cropTop,
            width: pct(shadeLeft, windowRect.width),
            height: cropHeight,
          }}
        />
      ) : null}
      {shadeRight > 0 ? (
        <div
          className="pointer-events-none absolute bg-black/40"
          style={{
            right: 0,
            top: cropTop,
            width: pct(shadeRight, windowRect.width),
            height: cropHeight,
          }}
        />
      ) : null}

      <div
        className={cn(
          "docs-crop-region pointer-events-none absolute",
          attrs.cropShape === "ellipse" && "rounded-full"
        )}
        style={{ left: cropLeft, top: cropTop, width: cropWidth, height: cropHeight }}
      >
        <div
          className="docs-crop-region__frame pointer-events-none absolute inset-0 border border-dashed border-white/95 shadow-[0_0_0_1px_rgba(0,0,0,0.45)]"
          aria-hidden
        />
        {HANDLES.map((handle) => (
          <span
            key={handle}
            role="presentation"
            className={cn("docs-crop-handle pointer-events-auto absolute z-40", HANDLE_CLASS[handle])}
            onPointerDown={(event) => beginResize(handle, event)}
          />
        ))}
      </div>
    </div>
  )
}
