/* global React */
const { useRef, useState, useEffect, useCallback } = React;

const STAGE = 240;     // on-screen crop square (px)
const OUT = 560;       // exported square resolution (px)

function PhotoCropper({ value, onChange }) {
  const [img, setImg] = useState(null);     // HTMLImageElement
  const [zoom, setZoom] = useState(1);       // 1..3 multiplier over cover-fit
  const [offset, setOffset] = useState({ x: 0, y: 0 });
  const [dragging, setDragging] = useState(false);
  const [over, setOver] = useState(false);
  const canvasRef = useRef(null);
  const dragRef = useRef(null);
  const fileRef = useRef(null);

  const baseScale = img ? Math.max(STAGE / img.width, STAGE / img.height) : 1;
  const scale = baseScale * zoom;

  const clamp = useCallback((off, sc) => {
    if (!img) return off;
    const w = img.width * sc, h = img.height * sc;
    const maxX = Math.max(0, (w - STAGE) / 2);
    const maxY = Math.max(0, (h - STAGE) / 2);
    return {
      x: Math.max(-maxX, Math.min(maxX, off.x)),
      y: Math.max(-maxY, Math.min(maxY, off.y)),
    };
  }, [img]);

  // draw to stage canvas
  useEffect(() => {
    const cv = canvasRef.current;
    if (!cv) return;
    const ctx = cv.getContext("2d");
    ctx.clearRect(0, 0, STAGE, STAGE);
    if (!img) return;
    const w = img.width * scale, h = img.height * scale;
    ctx.drawImage(img, STAGE / 2 - w / 2 + offset.x, STAGE / 2 - h / 2 + offset.y, w, h);
  }, [img, scale, offset]);

  function loadFile(file) {
    if (!file || !file.type.startsWith("image/")) return;
    const reader = new FileReader();
    reader.onload = (e) => {
      const im = new Image();
      im.onload = () => { setImg(im); setZoom(1); setOffset({ x: 0, y: 0 }); };
      im.src = e.target.result;
    };
    reader.readAsDataURL(file);
  }

  // pointer drag
  function onDown(e) {
    if (!img) return;
    setDragging(true);
    const p = e.touches ? e.touches[0] : e;
    dragRef.current = { sx: p.clientX, sy: p.clientY, ox: offset.x, oy: offset.y };
  }
  function onMove(e) {
    if (!dragging || !dragRef.current) return;
    const p = e.touches ? e.touches[0] : e;
    const nx = dragRef.current.ox + (p.clientX - dragRef.current.sx);
    const ny = dragRef.current.oy + (p.clientY - dragRef.current.sy);
    setOffset(clamp({ x: nx, y: ny }, scale));
  }
  function onUp() { setDragging(false); dragRef.current = null; }

  useEffect(() => {
    if (!dragging) return;
    const mv = (e) => onMove(e);
    const up = () => onUp();
    window.addEventListener("mousemove", mv);
    window.addEventListener("mouseup", up);
    window.addEventListener("touchmove", mv, { passive: false });
    window.addEventListener("touchend", up);
    return () => {
      window.removeEventListener("mousemove", mv);
      window.removeEventListener("mouseup", up);
      window.removeEventListener("touchmove", mv);
      window.removeEventListener("touchend", up);
    };
  }, [dragging, scale]);

  function changeZoom(z) {
    setZoom(z);
    setOffset((o) => clamp(o, baseScale * z));
  }

  function applyCrop() {
    if (!img) return;
    const cv = document.createElement("canvas");
    cv.width = OUT; cv.height = OUT;
    const ctx = cv.getContext("2d");
    ctx.fillStyle = "#fff"; ctx.fillRect(0, 0, OUT, OUT);
    const k = OUT / STAGE;
    const w = img.width * scale * k, h = img.height * scale * k;
    ctx.drawImage(img, OUT / 2 - w / 2 + offset.x * k, OUT / 2 - h / 2 + offset.y * k, w, h);
    onChange(cv.toDataURL("image/jpeg", 0.9));
  }

  function reset() { setImg(null); onChange(null); if (fileRef.current) fileRef.current.value = ""; }

  // editing existing value with no working image -> show preview + replace
  if (value && !img) {
    return (
      <div className="photo-block">
        <div className="photo-preview-sq" style={{ width: 130, height: 130 }}>
          <img src={value} alt="candidate" />
        </div>
        <div className="crop-controls">
          <div className="field-hint" style={{ marginTop: 0 }}>Photo saved &amp; cropped to a square.</div>
          <div className="crop-actions">
            <button type="button" className="mini-btn" onClick={() => fileRef.current.click()}>Replace photo</button>
            <button type="button" className="mini-btn" onClick={reset}>Remove</button>
          </div>
          <input ref={fileRef} type="file" accept="image/*" hidden
            onChange={(e) => loadFile(e.target.files[0])} />
        </div>
      </div>
    );
  }

  return (
    <div className="photo-block">
      {!img ? (
        <div
          className={"drop-zone" + (over ? " drag" : "")}
          onClick={() => fileRef.current.click()}
          onDragOver={(e) => { e.preventDefault(); setOver(true); }}
          onDragLeave={() => setOver(false)}
          onDrop={(e) => { e.preventDefault(); setOver(false); loadFile(e.dataTransfer.files[0]); }}
        >
          <div>
            <div className="dz-ico" aria-hidden="true">⬆</div>
            <div className="dz-t">Click or drop a photo</div>
            <div className="dz-s">JPG / PNG · square crop</div>
          </div>
        </div>
      ) : (
        <div
          className={"crop-stage" + (dragging ? " dragging" : "")}
          onMouseDown={onDown}
          onTouchStart={onDown}
        >
          <canvas ref={canvasRef} width={STAGE} height={STAGE} />
          <div className="crop-grid" />
        </div>
      )}

      <div className="crop-controls">
        {img ? (
          <>
            <div className="zoom-lab"><span>Zoom</span><span>{zoom.toFixed(1)}×</span></div>
            <input type="range" min="1" max="3" step="0.01" value={zoom}
              onChange={(e) => changeZoom(parseFloat(e.target.value))} />
            <div className="field-hint" style={{ marginTop: 8 }}>Drag the photo to reposition. The square area is what appears on the CV.</div>
            <div className="crop-actions">
              <button type="button" className="btn btn-primary" style={{ padding: "9px 18px", fontSize: 13 }} onClick={applyCrop}>Use this photo</button>
              <button type="button" className="mini-btn" onClick={() => fileRef.current.click()}>Choose another</button>
            </div>
          </>
        ) : (
          <div className="field-hint" style={{ marginTop: 0 }}>
            Upload a clear, front-facing headshot. You'll be able to zoom and drag to frame it into a square.
          </div>
        )}
        <input ref={fileRef} type="file" accept="image/*" hidden
          onChange={(e) => loadFile(e.target.files[0])} />
      </div>
    </div>
  );
}

window.PhotoCropper = PhotoCropper;
