// GetContent — profielfoto-cropper. Modal die na het kiezen van een afbeelding
// verschijnt: verschuiven (slepen), in-/uitzoomen (slider, scroll of knijpen) en
// een ronde crop-preview. Wat binnen de cirkel valt wordt de ronde profielfoto.
// Werkt op desktop én mobiel (pointer events + touch-action: none).
function AvatarCropper({ file, onCancel, onCropped }) {
  const NS = window.GetContentDesignSystem_aa0f52;
  const { Button } = NS;

  // vierkant crop-venster; op smalle schermen kleiner zodat het past
  const vp = React.useMemo(() => Math.max(220, Math.min(320, (typeof window !== 'undefined' ? window.innerWidth : 360) - 72)), []);
  const OUT = 512; // uitvoer-resolutie (vierkant, wordt rond getoond)

  const [url, setUrl] = React.useState('');
  const [nat, setNat] = React.useState(null);      // { w, h } natuurlijke afmetingen
  const [base, setBase] = React.useState(1);        // minimale schaal (venster vullen)
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState('');
  const imgElRef = React.useRef(null);              // geladen HTMLImageElement (voor canvas)
  const natRef = React.useRef(null);                // natuurlijke afmetingen (voor handlers/save; geen stale state)
  const t = React.useRef({ scale: 1, tx: 0, ty: 0 });
  const [, force] = React.useReducer((x) => x + 1, 0);

  // interactie-state
  const pointers = React.useRef(new Map());
  const pinchPrev = React.useRef(0);

  // afbeelding laden
  React.useEffect(() => {
    if (!file) return;
    const u = URL.createObjectURL(file);
    setUrl(u);
    const im = new Image();
    im.onload = () => {
      imgElRef.current = im;
      const w = im.naturalWidth, h = im.naturalHeight;
      const b = Math.max(vp / w, vp / h);
      natRef.current = { w, h };
      setNat({ w, h }); setBase(b);
      t.current = { scale: b, tx: (vp - w * b) / 2, ty: (vp - h * b) / 2 };
      force();
    };
    im.onerror = () => setErr('Kon de afbeelding niet laden. Kies een andere.');
    im.src = u;
    return () => URL.revokeObjectURL(u);
  }, [file, vp]);

  // body-scroll blokkeren terwijl de modal open is
  React.useEffect(() => {
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => { document.body.style.overflow = prev; };
  }, []);

  const clampT = (tx, ty, scale) => {
    const n = natRef.current;
    if (!n) return { tx, ty };
    const w = n.w * scale, h = n.h * scale;
    return {
      tx: Math.min(0, Math.max(vp - w, tx)),
      ty: Math.min(0, Math.max(vp - h, ty)),
    };
  };

  const zoomAt = (ns, px, py) => {
    if (!natRef.current) return;
    const cur = t.current, cs = cur.scale;
    const ix = (px - cur.tx) / cs, iy = (py - cur.ty) / cs;
    const c = clampT(px - ix * ns, py - iy * ns, ns);
    t.current = { scale: ns, tx: c.tx, ty: c.ty };
    force();
  };

  const clampScale = (s) => Math.max(base, Math.min(base * 4, s));

  // ---- pointer / touch ----
  const onPointerDown = (e) => {
    e.currentTarget.setPointerCapture && e.currentTarget.setPointerCapture(e.pointerId);
    pointers.current.set(e.pointerId, { x: e.clientX, y: e.clientY });
    if (pointers.current.size === 2) {
      const [a, b] = [...pointers.current.values()];
      pinchPrev.current = Math.hypot(a.x - b.x, a.y - b.y);
    }
  };
  const onPointerMove = (e) => {
    const p = pointers.current.get(e.pointerId);
    if (!p) return;
    const prevX = p.x, prevY = p.y;
    p.x = e.clientX; p.y = e.clientY;
    if (pointers.current.size >= 2) {
      const [a, b] = [...pointers.current.values()];
      const d = Math.hypot(a.x - b.x, a.y - b.y);
      if (pinchPrev.current > 0) {
        const ns = clampScale(t.current.scale * (d / pinchPrev.current));
        const rect = e.currentTarget.getBoundingClientRect();
        zoomAt(ns, (a.x + b.x) / 2 - rect.left, (a.y + b.y) / 2 - rect.top);
      }
      pinchPrev.current = d;
    } else {
      const c = clampT(t.current.tx + (e.clientX - prevX), t.current.ty + (e.clientY - prevY), t.current.scale);
      t.current = Object.assign({}, t.current, c);
      force();
    }
  };
  const onPointerUp = (e) => {
    pointers.current.delete(e.pointerId);
    if (pointers.current.size < 2) pinchPrev.current = 0;
  };
  const onWheel = (e) => {
    e.preventDefault();
    const rect = e.currentTarget.getBoundingClientRect();
    const ns = clampScale(t.current.scale * (e.deltaY < 0 ? 1.08 : 0.92));
    zoomAt(ns, e.clientX - rect.left, e.clientY - rect.top);
  };

  const save = () => {
    if (!natRef.current || !imgElRef.current) return;
    setBusy(true);
    try {
      const cur = t.current;
      const srcSize = vp / cur.scale;         // zichtbaar deel in natuurlijke px
      const srcX = -cur.tx / cur.scale;
      const srcY = -cur.ty / cur.scale;
      const canvas = document.createElement('canvas');
      canvas.width = OUT; canvas.height = OUT;
      const ctx = canvas.getContext('2d');
      ctx.imageSmoothingQuality = 'high';
      ctx.drawImage(imgElRef.current, srcX, srcY, srcSize, srcSize, 0, 0, OUT, OUT);
      canvas.toBlob((blob) => {
        setBusy(false);
        if (!blob) { setErr('Bijsnijden is niet gelukt. Probeer het opnieuw.'); return; }
        onCropped(blob);
      }, 'image/jpeg', 0.9);
    } catch (e2) {
      setBusy(false);
      setErr('Bijsnijden is niet gelukt. Probeer het opnieuw.');
    }
  };

  const ready = !!(nat && url);

  return (
    <div role="dialog" aria-modal="true" aria-label="Profielfoto bijsnijden"
      style={{ position: 'fixed', inset: 0, zIndex: 120, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 16, background: 'rgba(18,24,38,0.55)' }}
      onMouseDown={(e) => { if (e.target === e.currentTarget) onCancel(); }}>
      <div style={{ background: 'var(--surface-card)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-lg)', padding: 'clamp(18px, 3vw, 26px)', width: '100%', maxWidth: 400, display: 'flex', flexDirection: 'column', gap: 16 }}>
        <div>
          <h3 style={{ fontSize: 18, fontWeight: 'var(--fw-semibold)', color: 'var(--text-strong)', margin: 0 }}>Profielfoto bijsnijden</h3>
          <p style={{ fontSize: 13.5, color: 'var(--text-muted)', margin: '4px 0 0' }}>Versleep om te verplaatsen, zoom met de balk of scroll.</p>
        </div>

        <div style={{ display: 'flex', justifyContent: 'center' }}>
          <div
            onPointerDown={onPointerDown} onPointerMove={onPointerMove} onPointerUp={onPointerUp} onPointerCancel={onPointerUp} onWheel={onWheel}
            style={{ position: 'relative', width: vp, height: vp, overflow: 'hidden', borderRadius: 12, background: '#0d111b', touchAction: 'none', cursor: 'grab', userSelect: 'none' }}>
            {ready && (
              <img src={url} alt="" draggable={false}
                style={{ position: 'absolute', left: 0, top: 0, width: nat.w * t.current.scale, height: nat.h * t.current.scale, maxWidth: 'none', maxHeight: 'none', transform: `translate(${t.current.tx}px, ${t.current.ty}px)`, willChange: 'transform', pointerEvents: 'none' }} />
            )}
            {/* ronde crop-indicator: dimt alles buiten de cirkel */}
            <div aria-hidden style={{ position: 'absolute', inset: 0, borderRadius: '50%', boxShadow: '0 0 0 9999px rgba(13,17,27,0.55)', border: '2px solid rgba(245,243,239,0.9)', pointerEvents: 'none' }} />
          </div>
        </div>

        {/* zoom-slider (fijn op mobiel) */}
        {ready && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <i data-lucide="image" style={{ width: 16, height: 16, color: 'var(--text-muted)' }}></i>
            <input type="range" min={base} max={base * 4} step={base / 100} value={t.current.scale}
              onChange={(e) => zoomAt(clampScale(parseFloat(e.target.value)), vp / 2, vp / 2)}
              aria-label="Zoomen"
              style={{ flex: 1, accentColor: 'var(--accent)' }} />
            <i data-lucide="image" style={{ width: 22, height: 22, color: 'var(--text-muted)' }}></i>
          </div>
        )}

        {err && <p style={{ margin: 0, fontSize: 13.5, fontWeight: 'var(--fw-semibold)', color: 'var(--gc-danger)' }}>{err}</p>}

        <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end' }}>
          <Button variant="ghost" onClick={onCancel} disabled={busy}>Annuleren</Button>
          <Button variant="primary" onClick={save} disabled={busy || !ready} iconRight={<i data-lucide="check"></i>}>{busy ? 'Bezig…' : 'Opslaan'}</Button>
        </div>
      </div>
    </div>
  );
}
window.AvatarCropper = AvatarCropper;
