/* The Upper Room — profile photo crop/zoom modal (2026-07-04).
 * CEO caught this live: two real uploaded avatars (his own close-up vs.
 * Nicole's farther-back shot) render inconsistently since Avatar's <img>
 * just center-crops whatever comes in (object-fit: cover, no reframing).
 * This gives everyone a simple drag-to-reposition + slider-to-zoom step
 * BEFORE upload, so every profile photo lands as a consistent, centered
 * square headshot regardless of the source photo's framing — same idea
 * as the standard Instagram/LinkedIn avatar-upload crop step.
 * Renders a fixed-size square JPEG via <canvas> and hands the caller a
 * Blob to upload — no backend change needed, the upload route already
 * just stores whatever file arrives.
 */
const { useState: useCropState, useRef: useCropRef, useEffect: useCropEffect } = React;

const CROP_OUTPUT_SIZE = 600; // square px, matches typical avatar display sizes with headroom

function PhotoCropModal({ file, onCancel, onDone }) {
  const [imgUrl, setImgUrl] = useCropState(null);
  const [imgSize, setImgSize] = useCropState({ w: 0, h: 0 });
  const [zoom, setZoom] = useCropState(1);
  const [offset, setOffset] = useCropState({ x: 0, y: 0 }); // pan, in displayed-box px
  const [dragging, setDragging] = useCropState(false);
  const [busy, setBusy] = useCropState(false);
  const dragStart = useCropRef(null);
  const boxRef = useCropRef(null);
  const BOX = 280; // on-screen preview box size, px (square)

  useCropEffect(() => {
    const url = URL.createObjectURL(file);
    const img = new Image();
    img.onload = () => { setImgSize({ w: img.naturalWidth, h: img.naturalHeight }); setImgUrl(url); };
    img.src = url;
    return () => URL.revokeObjectURL(url);
  }, [file]);

  // Minimum zoom = whatever scale makes the shorter side fill the box (no
  // letterboxing gaps ever allowed) — anything below this would show
  // empty space at the edges of the crop circle.
  const baseScale = imgSize.w && imgSize.h ? Math.max(BOX / imgSize.w, BOX / imgSize.h) : 1;
  const scale = baseScale * zoom;
  const dispW = imgSize.w * scale, dispH = imgSize.h * scale;
  const maxOffX = Math.max(0, (dispW - BOX) / 2), maxOffY = Math.max(0, (dispH - BOX) / 2);
  const clampedOffset = { x: Math.max(-maxOffX, Math.min(maxOffX, offset.x)), y: Math.max(-maxOffY, Math.min(maxOffY, offset.y)) };

  const onPointerDown = (e) => {
    const p = e.touches ? e.touches[0] : e;
    dragStart.current = { x: p.clientX - clampedOffset.x, y: p.clientY - clampedOffset.y };
    setDragging(true);
  };
  const onPointerMove = (e) => {
    if (!dragging || !dragStart.current) return;
    const p = e.touches ? e.touches[0] : e;
    setOffset({ x: p.clientX - dragStart.current.x, y: p.clientY - dragStart.current.y });
  };
  const onPointerUp = () => { setDragging(false); dragStart.current = null; };

  const confirm = () => {
    if (!imgUrl || busy) return;
    setBusy(true);
    const img = new Image();
    img.onload = () => {
      const canvas = document.createElement('canvas');
      canvas.width = CROP_OUTPUT_SIZE; canvas.height = CROP_OUTPUT_SIZE;
      const ctx = canvas.getContext('2d');
      // Map the on-screen BOXxBOX crop window to the output canvas 1:1 scaled.
      const outScale = CROP_OUTPUT_SIZE / BOX;
      const srcScale = scale; // displayed px per source px
      // Top-left of the visible BOXxBOX window, in SOURCE image pixels.
      const srcX = (dispW / 2 - BOX / 2 - clampedOffset.x) / srcScale;
      const srcY = (dispH / 2 - BOX / 2 - clampedOffset.y) / srcScale;
      const srcW = BOX / srcScale, srcH = BOX / srcScale;
      ctx.drawImage(img, srcX, srcY, srcW, srcH, 0, 0, CROP_OUTPUT_SIZE, CROP_OUTPUT_SIZE);
      canvas.toBlob((blob) => {
        setBusy(false);
        if (blob) onDone(blob);
      }, 'image/jpeg', 0.92);
    };
    img.src = imgUrl;
  };

  return (
    <div className="ur-modal-scrim" onClick={onCancel}>
      <div className="card ur-crop-modal" onClick={(e) => e.stopPropagation()}>
        <div className="ur-crop-head">
          <span>Adjust your photo</span>
          <button className="ur-modal-x" onClick={onCancel} aria-label="Cancel"><Icon name="x" size={18} /></button>
        </div>
        <p className="ur-crop-hint">Drag to reposition, use the slider to zoom — this is how the room will see you.</p>
        <div
          ref={boxRef}
          className="ur-crop-box"
          style={{ width: BOX, height: BOX, cursor: dragging ? 'grabbing' : 'grab' }}
          onMouseDown={onPointerDown} onMouseMove={onPointerMove} onMouseUp={onPointerUp} onMouseLeave={onPointerUp}
          onTouchStart={onPointerDown} onTouchMove={onPointerMove} onTouchEnd={onPointerUp}
        >
          {imgUrl && (
            <img
              src={imgUrl} alt="" draggable={false}
              style={{ width: dispW, height: dispH, transform: `translate(${clampedOffset.x}px, ${clampedOffset.y}px)`, position: 'absolute', left: (BOX - dispW) / 2, top: (BOX - dispH) / 2, userSelect: 'none', pointerEvents: 'none' }}
            />
          )}
          <div className="ur-crop-ring"></div>
        </div>
        <div className="ur-crop-zoom-row">
          <Icon name="zoom-out" size={16} />
          <input type="range" min="1" max="3" step="0.01" value={zoom} onChange={(e) => setZoom(Number(e.target.value))} />
          <Icon name="zoom-in" size={16} />
        </div>
        <div className="ur-crop-actions">
          <button className="ur-skip" onClick={onCancel} disabled={busy}>Cancel</button>
          <button className="ur-primary" onClick={confirm} disabled={busy || !imgUrl}>{busy ? 'Applying…' : 'Use this photo'}</button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { PhotoCropModal });
