/* global React, Icon */
(function(){
const { useState, useEffect, useRef, useCallback, useMemo } = React;

/* =============================================================
   ImageCropper.jsx — reusable image editor overlay
   --------------------------------------------------------------
   Crop (pan + zoom), rotate 90°, flip, square/circle shape,
   aspect-ratio presets, and light color edits (brightness /
   contrast / saturation). Everything is processed in-browser on
   a <canvas> — the result comes back as a data-URL.

   <ImageCropper
     open src title
     shape="rect"|"circle"        initial shape
     allowShapeToggle={false}
     aspectOptions={[{id,label,ar,icon}]}  // omit → fixed `aspect`
     aspect={1}                    // used when no aspectOptions
     enableFilters={true}
     exportSize={1280}             // longest output edge (px)
     onCancel() onApply(dataUrl, meta) />
   ============================================================= */

const fa = (n) => String(n).replace(/\d/g, d => "۰۱۲۳۴۵۶۷۸۹"[d]);
const clamp = (v, a, b) => Math.max(a, Math.min(b, v));

const DEFAULT_ASPECTS = [
  { id: "1",   label: "۱:۱",  ar: 1,     icon: "square" },
  { id: "45",  label: "۴:۵",  ar: 4/5,   icon: "portrait" },
  { id: "169", label: "۱۶:۹", ar: 16/9,  icon: "rect" },
];

window.ImageCropper = function ImageCropper({
  open, src, title = "ویرایش تصویر",
  shape: shape0 = "rect", allowShapeToggle = false,
  aspectOptions, aspect: aspectFixed = 1,
  enableFilters = true, exportSize = 1280,
  applyLabel = "اعمال",
  onCancel, onApply,
}) {
  const stageRef = useRef(null);
  const imgRef = useRef(null);              // decoded HTMLImageElement for export
  const dragRef = useRef(null);

  const [box, setBox] = useState(300);      // square stage side (px)
  const [nat, setNat] = useState(null);     // { w, h } natural image size
  const [shape, setShape] = useState(shape0);
  const [aspId, setAspId] = useState(null);
  const [zoom, setZoom] = useState(1);
  const [rot, setRot] = useState(0);        // degrees, multiples of 90
  const [flipH, setFlipH] = useState(false);
  const [pan, setPan] = useState({ x: 0, y: 0 });
  const [bright, setBright] = useState(100);
  const [contrast, setContrast] = useState(100);
  const [sat, setSat] = useState(100);
  const [tab, setTab] = useState("crop");   // crop | color
  const [busy, setBusy] = useState(false);

  const asps = aspectOptions && aspectOptions.length ? aspectOptions : null;

  // resolve the active aspect ratio
  const aspect = useMemo(() => {
    if (shape === "circle") return 1;
    if (asps) {
      const a = asps.find(a => a.id === aspId) || asps[0];
      return a.ar;
    }
    return aspectFixed;
  }, [shape, asps, aspId, aspectFixed]);

  // measure the stage so the frame is crisp on any screen
  useEffect(() => {
    if (!open) return;
    const measure = () => {
      const el = stageRef.current;
      if (!el) return;
      const w = el.clientWidth || 300;
      setBox(Math.max(220, Math.min(w, 360)));
    };
    measure();
    const ro = ("ResizeObserver" in window) ? new ResizeObserver(measure) : null;
    if (ro && stageRef.current) ro.observe(stageRef.current);
    window.addEventListener("resize", measure);
    return () => { ro && ro.disconnect(); window.removeEventListener("resize", measure); };
  }, [open]);

  // (re)load the source whenever it changes
  useEffect(() => {
    if (!open || !src) return;
    setNat(null);
    const im = new Image();
    im.crossOrigin = "anonymous";
    im.onload = () => {
      imgRef.current = im;
      setNat({ w: im.naturalWidth || im.width, h: im.naturalHeight || im.height });
    };
    im.src = src;
    // reset transforms for a fresh image
    setShape(shape0); setAspId(asps ? asps[0].id : null);
    setZoom(1); setRot(0); setFlipH(false); setPan({ x: 0, y: 0 });
    setBright(100); setContrast(100); setSat(100); setTab("crop");
  // eslint-disable-next-line
  }, [open, src]);

  // frame size derived from the stage box + aspect
  const base = box * 0.92;
  let fw, fh;
  if (aspect >= 1) { fw = base; fh = base / aspect; }
  else { fh = base; fw = base * aspect; }

  // cover scale: the image fully covers the frame at zoom = 1
  const cover = nat ? Math.max(fw / nat.w, fh / nat.h) : 1;
  const dispW = nat ? nat.w * cover : fw;
  const dispH = nat ? nat.h * cover : fh;

  const filterStr = `brightness(${bright}%) contrast(${contrast}%) saturate(${sat}%)`;

  // ---- pointer drag to pan ------------------------------------------
  const onDown = (e) => {
    if (!nat) return;
    e.currentTarget.setPointerCapture?.(e.pointerId);
    dragRef.current = { x: e.clientX, y: e.clientY, px: pan.x, py: pan.y };
  };
  const onMove = (e) => {
    const d = dragRef.current; if (!d) return;
    setPan({ x: d.px + (e.clientX - d.x), y: d.py + (e.clientY - d.y) });
  };
  const onUp = () => { dragRef.current = null; };
  const onWheel = (e) => {
    if (!nat) return;
    setZoom(z => clamp(z * (e.deltaY < 0 ? 1.07 : 0.93), 1, 6));
  };

  const reset = () => { setZoom(1); setRot(0); setFlipH(false); setPan({ x: 0, y: 0 }); };

  // ---- export -------------------------------------------------------
  const apply = useCallback(() => {
    const im = imgRef.current;
    if (!im || !nat) return;
    setBusy(true);
    try {
      const longest = exportSize;
      let ow, oh;
      if (aspect >= 1) { ow = longest; oh = Math.round(longest / aspect); }
      else { oh = longest; ow = Math.round(longest * aspect); }
      const cv = document.createElement("canvas");
      cv.width = ow; cv.height = oh;
      const ctx = cv.getContext("2d");
      ctx.imageSmoothingQuality = "high";
      const k = ow / fw;               // px(screen) → px(output)
      const circ = shape === "circle";
      if (circ) {
        ctx.save();
        ctx.beginPath();
        ctx.arc(ow / 2, oh / 2, Math.min(ow, oh) / 2, 0, Math.PI * 2);
        ctx.closePath(); ctx.clip();
      }
      ctx.translate(ow / 2, oh / 2);
      ctx.translate(pan.x * k, pan.y * k);
      ctx.rotate(rot * Math.PI / 180);
      ctx.scale(zoom * (flipH ? -1 : 1), zoom);
      ctx.filter = filterStr;
      const dw = dispW * k, dh = dispH * k;
      ctx.drawImage(im, -dw / 2, -dh / 2, dw, dh);
      if (circ) ctx.restore();
      const url = circ ? cv.toDataURL("image/png") : cv.toDataURL("image/jpeg", 0.92);
      onApply?.(url, { shape, aspect, w: ow, h: oh });
    } finally {
      setBusy(false);
    }
  }, [nat, aspect, fw, dispW, dispH, pan, rot, zoom, flipH, filterStr, shape, exportSize, onApply]);

  if (!open) return null;

  const dirty = zoom !== 1 || rot !== 0 || flipH || pan.x !== 0 || pan.y !== 0;
  const colorDirty = bright !== 100 || contrast !== 100 || sat !== 100;

  return (
    <div className="kd-cropper" onClick={onCancel}>
      <div className="kd-cropper__panel kd-glass" onClick={e => e.stopPropagation()}>
        <div className="kd-cropper__head">
          <button className="kd-cropper__x" onClick={onCancel} aria-label="بستن"><Icon name="close" size={18} stroke={2} /></button>
          <h3 className="kd-cropper__title"><Icon name="crop" size={17} stroke={1.8} /> {title}</h3>
          <button className="kd-cropper__apply" onClick={apply} disabled={busy || !nat}>
            <Icon name="check" size={15} stroke={2.6} /> {applyLabel}
          </button>
        </div>

        {/* ---- stage ---- */}
        <div className="kd-cropper__stagewrap">
          <div className="kd-cropper__stage" ref={stageRef}
            style={{ height: box }}
            onPointerDown={onDown} onPointerMove={onMove} onPointerUp={onUp}
            onPointerCancel={onUp} onWheel={onWheel}>
            {!nat && <div className="kd-cropper__loading"><span className="kd-cropper__spin" /></div>}
            {nat && (
              <React.Fragment>
                <img className="kd-cropper__img" src={src} alt="" draggable={false}
                  style={{
                    width: dispW, height: dispH,
                    left: (box - dispW) / 2, top: (box - dispH) / 2,
                    transform: `translate(${pan.x}px, ${pan.y}px) rotate(${rot}deg) scale(${zoom * (flipH ? -1 : 1)}, ${zoom})`,
                    filter: filterStr,
                  }} />
                <div className="kd-cropper__mask" style={{
                  width: fw, height: fh,
                  borderRadius: shape === "circle" ? "50%" : "14px",
                }}>
                  <span className="kd-cropper__grid" />
                </div>
              </React.Fragment>
            )}
          </div>
          <p className="kd-cropper__hint">
            <Icon name="image" size={11} stroke={2} /> بکش تا جابه‌جا شه · چرخ یا اسلایدر برای بزرگ‌نمایی
          </p>
        </div>

        {/* ---- shape + aspect ---- */}
        <div className="kd-cropper__shapes">
          {allowShapeToggle && (
            <div className="kd-cropper__seg">
              <button className={shape === "rect" ? "is-on" : ""} onClick={() => setShape("rect")}><Icon name="square" size={15} stroke={1.9} /> مربع</button>
              <button className={shape === "circle" ? "is-on" : ""} onClick={() => setShape("circle")}><Icon name="circleshape" size={15} stroke={1.9} /> دایره</button>
            </div>
          )}
          {asps && shape !== "circle" && (
            <div className="kd-cropper__aspects">
              {asps.map(a => (
                <button key={a.id} className={`kd-cropper__asp ${(aspId || asps[0].id) === a.id ? "is-on" : ""}`}
                  onClick={() => { setAspId(a.id); setPan({ x: 0, y: 0 }); }}>
                  <Icon name={a.icon || "rect"} size={15} stroke={1.9} /> {a.label}
                </button>
              ))}
            </div>
          )}
        </div>

        {/* ---- tabs ---- */}
        {enableFilters && (
          <div className="kd-cropper__tabs">
            <button className={tab === "crop" ? "is-on" : ""} onClick={() => setTab("crop")}>
              <Icon name="crop" size={15} stroke={1.9} /> تنظیم
              {dirty && <span className="kd-cropper__dot" />}
            </button>
            <button className={tab === "color" ? "is-on" : ""} onClick={() => setTab("color")}>
              <Icon name="sliders" size={15} stroke={1.9} /> رنگ
              {colorDirty && <span className="kd-cropper__dot" />}
            </button>
          </div>
        )}

        {/* ---- controls ---- */}
        {tab === "crop" && (
          <div className="kd-cropper__ctrls">
            <div className="kd-cropper__zoom">
              <Icon name="image" size={14} stroke={2} />
              <input type="range" min="1" max="6" step="0.01" value={zoom}
                onChange={e => setZoom(parseFloat(e.target.value))} aria-label="بزرگ‌نمایی" />
              <span className="kd-cropper__zval">{fa(Math.round(zoom * 100))}٪</span>
            </div>
            <div className="kd-cropper__btns">
              <button onClick={() => setRot(r => (r + 90) % 360)}><Icon name="rotate" size={17} stroke={1.9} /> چرخش</button>
              <button className={flipH ? "is-on" : ""} onClick={() => setFlipH(f => !f)}><Icon name="flip" size={17} stroke={1.9} /> آینه</button>
              <button onClick={reset} disabled={!dirty}><Icon name="rotate" size={17} stroke={1.9} style={{ transform: "scaleX(-1)" }} /> ریست</button>
            </div>
          </div>
        )}

        {tab === "color" && enableFilters && (
          <div className="kd-cropper__ctrls">
            <label className="kd-cropper__slider">
              <span><Icon name="brightness" size={14} stroke={1.9} /> روشنایی</span>
              <input type="range" min="50" max="150" value={bright} onChange={e => setBright(+e.target.value)} />
              <em>{fa(bright)}</em>
            </label>
            <label className="kd-cropper__slider">
              <span><Icon name="contrast" size={14} stroke={1.9} /> کنتراست</span>
              <input type="range" min="50" max="150" value={contrast} onChange={e => setContrast(+e.target.value)} />
              <em>{fa(contrast)}</em>
            </label>
            <label className="kd-cropper__slider">
              <span><Icon name="droplet" size={14} stroke={1.9} /> اشباع</span>
              <input type="range" min="0" max="200" value={sat} onChange={e => setSat(+e.target.value)} />
              <em>{fa(sat)}</em>
            </label>
            <button className="kd-cropper__resetcolor" onClick={() => { setBright(100); setContrast(100); setSat(100); }} disabled={!colorDirty}>
              بازنشانی رنگ
            </button>
          </div>
        )}
      </div>
    </div>
  );
};
})();
