import { useState, useRef, useCallback } from 'react'

type HandleType = 'move' | 'tl' | 'tr' | 'bl' | 'br'
interface CropBox { x: number; y: number; w: number; h: number }

interface Props {
  imageSrc: string
  aspectRatio: number   // width / height of the target display area
  onCrop: (dataUrl: string) => void
  onCancel: () => void
}

const MIN_SIZE = 80

function clamp(v: number, lo: number, hi: number) {
  return Math.max(lo, Math.min(hi, v))
}

export function BgImageCropper({ imageSrc, aspectRatio, onCrop, onCancel }: Props) {
  const containerRef = useRef<HTMLDivElement>(null)
  const imgRef = useRef<HTMLImageElement>(null)

  // Keep crop box in both a ref (for event handlers, avoids stale closure) and state (for rendering)
  const cropRef = useRef<CropBox | null>(null)
  const [cropBox, setCropBox] = useState<CropBox | null>(null)

  const drag = useRef<{
    type: HandleType
    startX: number
    startY: number
    startCrop: CropBox
  } | null>(null)

  const setBox = useCallback((b: CropBox) => {
    cropRef.current = b
    setCropBox(b)
  }, [])

  // Centre a crop box filling most of the displayed image at the target aspect ratio
  const initCrop = useCallback(() => {
    const c = containerRef.current
    const img = imgRef.current
    if (!c || !img) return

    const cW = c.clientWidth
    const cH = c.clientHeight
    const scale = Math.min(cW / img.naturalWidth, cH / img.naturalHeight)
    const dispW = img.naturalWidth * scale
    const dispH = img.naturalHeight * scale
    const imgX = (cW - dispW) / 2
    const imgY = (cH - dispH) / 2

    let w = dispW * 0.9
    let h = w / aspectRatio
    if (h > dispH * 0.9) { h = dispH * 0.9; w = h * aspectRatio }

    setBox({
      x: imgX + (dispW - w) / 2,
      y: imgY + (dispH - h) / 2,
      w,
      h,
    })
  }, [aspectRatio, setBox])

  const onPointerDown = useCallback((e: React.PointerEvent, type: HandleType) => {
    if (!cropRef.current) return
    e.preventDefault()
    e.stopPropagation()
    drag.current = {
      type,
      startX: e.clientX,
      startY: e.clientY,
      startCrop: { ...cropRef.current },
    }
    ;(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId)
  }, [])

  const onPointerMove = useCallback((e: React.PointerEvent) => {
    if (!drag.current || !containerRef.current) return
    const c = containerRef.current
    const cW = c.clientWidth
    const cH = c.clientHeight
    const dx = e.clientX - drag.current.startX
    const dy = e.clientY - drag.current.startY
    const sc = drag.current.startCrop
    const t = drag.current.type

    let x = sc.x, y = sc.y, w = sc.w, h = sc.h

    if (t === 'move') {
      x = clamp(sc.x + dx, 0, cW - sc.w)
      y = clamp(sc.y + dy, 0, cH - sc.h)
    } else {
      // Resize: width driven by dx, height derived from aspect ratio
      let newW: number
      if (t === 'br' || t === 'tr') newW = clamp(sc.w + dx, MIN_SIZE, cW)
      else                           newW = clamp(sc.w - dx, MIN_SIZE, cW)

      const newH = newW / aspectRatio

      if      (t === 'br') { x = sc.x;               y = sc.y }
      else if (t === 'bl') { x = sc.x + sc.w - newW; y = sc.y }
      else if (t === 'tr') { x = sc.x;               y = sc.y + sc.h - newH }
      else                 { x = sc.x + sc.w - newW; y = sc.y + sc.h - newH }

      x = clamp(x, 0, cW - newW)
      y = clamp(y, 0, cH - newH)
      w = newW
      h = newH
    }

    setBox({ x, y, w, h })
  }, [aspectRatio, setBox])

  const onPointerUp = useCallback(() => { drag.current = null }, [])

  const handleCrop = useCallback(() => {
    const img = imgRef.current
    const c = containerRef.current
    const cb = cropRef.current
    if (!img || !c || !cb) return

    const cW = c.clientWidth
    const cH = c.clientHeight
    const scale = Math.min(cW / img.naturalWidth, cH / img.naturalHeight)
    const dispW = img.naturalWidth * scale
    const dispH = img.naturalHeight * scale
    const offX = (cW - dispW) / 2
    const offY = (cH - dispH) / 2

    // Map crop box back to source image coordinates
    const srcX = (cb.x - offX) / scale
    const srcY = (cb.y - offY) / scale
    const srcW = cb.w / scale
    const srcH = cb.h / scale

    // Output resolution: screen size × device pixel ratio, capped at 1440px wide
    // Then scale down resolution until the result is under 3MB (keeping quality at 0.92)
    const MAX_BYTES = 1 * 1024 * 1024
    const dpr = Math.min(window.devicePixelRatio || 1, 2)
    let w = Math.min(Math.round(window.innerWidth * dpr), 1440)

    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')!
    let dataUrl: string

    do {
      const h = Math.round(w / aspectRatio)
      canvas.width = w
      canvas.height = h
      ctx.drawImage(img, srcX, srcY, srcW, srcH, 0, 0, w, h)
      dataUrl = canvas.toDataURL('image/jpeg', 0.92)
      // base64 → approx byte size
      const bytes = (dataUrl.length - dataUrl.indexOf(',') - 1) * 0.75
      if (bytes <= MAX_BYTES) break
      w = Math.round(w * 0.8)
    } while (w > 200)

    onCrop(dataUrl!)
  }, [aspectRatio, onCrop])

  return (
    <div className="cropper-overlay">
      <div className="cropper-header">
        <button type="button" className="cropper-cancel-btn" onClick={onCancel}>
          Cancel
        </button>
        <span className="cropper-title">Crop Background</span>
        <button
          type="button"
          className="cropper-apply-btn"
          onClick={handleCrop}
          disabled={!cropBox}
        >
          Apply
        </button>
      </div>

      <div
        ref={containerRef}
        className="cropper-container"
        onPointerMove={onPointerMove}
        onPointerUp={onPointerUp}
        onPointerLeave={onPointerUp}
      >
        <img
          ref={imgRef}
          src={imageSrc}
          className="cropper-image"
          onLoad={initCrop}
          alt=""
          draggable={false}
        />

        {cropBox && (
          <>
            {/* Darkened area outside crop box via box-shadow */}
            <div
              className="cropper-shade"
              style={{
                left: cropBox.x,
                top: cropBox.y,
                width: cropBox.w,
                height: cropBox.h,
              }}
            />

            {/* Moveable crop box */}
            <div
              className="cropper-box"
              style={{
                left: cropBox.x,
                top: cropBox.y,
                width: cropBox.w,
                height: cropBox.h,
              }}
              onPointerDown={(e) => onPointerDown(e, 'move')}
            >
              {/* Rule-of-thirds grid */}
              <div className="cropper-grid" />

              {/* Resize handles */}
              <div className="cropper-handle cropper-handle-tl" onPointerDown={(e) => onPointerDown(e, 'tl')} />
              <div className="cropper-handle cropper-handle-tr" onPointerDown={(e) => onPointerDown(e, 'tr')} />
              <div className="cropper-handle cropper-handle-bl" onPointerDown={(e) => onPointerDown(e, 'bl')} />
              <div className="cropper-handle cropper-handle-br" onPointerDown={(e) => onPointerDown(e, 'br')} />
            </div>
          </>
        )}
      </div>

      <p className="cropper-hint">Drag to move · Drag corners to resize</p>
    </div>
  )
}
