// Minimal in-browser circular cropper. Drag to pan, slider to zoom. On confirm,
// renders the visible square to a 256×256 PNG with a circular alpha mask and
// returns a data URI to the caller. No third-party deps.
(function () {
  const { useState, useRef, useEffect, useCallback } = React;
  const VIEW = 280;      // viewport pixels
  const OUTPUT = 256;    // exported size

  function AvatarCropper({ file, onCancel, onCommit }) {
    const [src, setSrc] = useState(null);
    const [img, setImg] = useState(null);
    const [scale, setScale] = useState(1);
    const [pos, setPos] = useState({ x: 0, y: 0 });   // top-left of image inside viewport
    const dragRef = useRef(null);

    useEffect(() => {
      const reader = new FileReader();
      reader.onload = () => setSrc(reader.result);
      reader.readAsDataURL(file);
    }, [file]);

    useEffect(() => {
      if (!src) return;
      const i = new Image();
      i.onload = () => {
        setImg(i);
        // initial fit: cover the viewport
        const s = Math.max(VIEW / i.width, VIEW / i.height);
        setScale(s);
        setPos({
          x: (VIEW - i.width * s) / 2,
          y: (VIEW - i.height * s) / 2,
        });
      };
      i.src = src;
    }, [src]);

    const onPointerDown = (e) => {
      dragRef.current = { sx: e.clientX, sy: e.clientY, ox: pos.x, oy: pos.y };
    };
    useEffect(() => {
      function move(e) {
        if (!dragRef.current) return;
        setPos({
          x: dragRef.current.ox + (e.clientX - dragRef.current.sx),
          y: dragRef.current.oy + (e.clientY - dragRef.current.sy),
        });
      }
      function up() { dragRef.current = null; }
      window.addEventListener("pointermove", move);
      window.addEventListener("pointerup", up);
      window.addEventListener("pointercancel", up);
      return () => {
        window.removeEventListener("pointermove", move);
        window.removeEventListener("pointerup", up);
        window.removeEventListener("pointercancel", up);
      };
    }, []);

    const onScale = (e) => {
      const next = Number(e.target.value);
      if (!img) { setScale(next); return; }
      // zoom about viewport center
      const cx = VIEW / 2, cy = VIEW / 2;
      const factor = next / scale;
      setPos({
        x: cx - (cx - pos.x) * factor,
        y: cy - (cy - pos.y) * factor,
      });
      setScale(next);
    };

    function exportPng() {
      if (!img) return;
      const canvas = document.createElement("canvas");
      canvas.width = OUTPUT; canvas.height = OUTPUT;
      const ctx = canvas.getContext("2d");
      // circular mask
      ctx.save();
      ctx.beginPath();
      ctx.arc(OUTPUT / 2, OUTPUT / 2, OUTPUT / 2, 0, Math.PI * 2);
      ctx.closePath();
      ctx.clip();
      // map viewport coords → canvas coords (scale OUTPUT/VIEW)
      const k = OUTPUT / VIEW;
      ctx.drawImage(img, pos.x * k, pos.y * k, img.width * scale * k, img.height * scale * k);
      ctx.restore();
      onCommit(canvas.toDataURL("image/png"));
    }

    const minScale = img ? Math.max(VIEW / img.width, VIEW / img.height) * 0.6 : 0.5;
    const maxScale = img ? Math.max(VIEW / img.width, VIEW / img.height) * 4 : 4;

    return React.createElement("div", { className: "cropper-overlay" },
      React.createElement("div", { className: "cropper-card card" },
        React.createElement("div", { className: "cap" },
          React.createElement("div", null,
            React.createElement("div", { className: "label" }, "shape your circle"),
            React.createElement("h3", { className: "title" }, "crop ",
              React.createElement("span", { className: "em" }, "your avatar"))
          ),
          React.createElement("button", { className: "btn ghost tiny", onClick: onCancel }, "cancel")
        ),
        React.createElement("div", { className: "cropper-stage", style: { width: VIEW, height: VIEW } },
          React.createElement("div", {
            className: "cropper-canvas",
            style: { width: VIEW, height: VIEW, touchAction: "none" },
            onPointerDown,
          },
            img ? React.createElement("img", {
              src, draggable: false, alt: "",
              style: {
                position: "absolute", left: pos.x + "px", top: pos.y + "px",
                width: (img.width * scale) + "px", height: (img.height * scale) + "px",
                userSelect: "none", pointerEvents: "none",
              },
            }) : null
          ),
          React.createElement("div", { className: "cropper-mask" })
        ),
        React.createElement("div", { style: { marginTop: 14 } },
          React.createElement("div", { className: "label", style: { marginBottom: 4 } }, "zoom"),
          React.createElement("input", {
            type: "range", min: minScale, max: maxScale, step: 0.01, value: scale,
            onChange: onScale,
            style: { width: "100%" },
          })
        ),
        React.createElement("div", { style: { display: "flex", gap: 10, justifyContent: "flex-end", marginTop: 14 } },
          React.createElement("button", { className: "btn ghost", onClick: onCancel }, "release"),
          React.createElement("button", { className: "btn warm", onClick: exportPng, disabled: !img }, "use this")
        )
      )
    );
  }

  window.AvatarCropper = AvatarCropper;
})();
