// Screenshot BG Remover — turn screenshots of "transparent preview"
// screens (Strava's Share Activity, Figma exports, etc.) into real
// transparent PNGs.
//
// Workflow:
//   1. User drops a screenshot
//   2. Click on the checkerboard / solid background to "pick" it
//   3. Tolerance slider widens the match radius
//   4. Optional crop sliders trim status bar + paywall regions
//   5. Live preview against our own checkerboard pattern
//   6. Export as PNG with alpha
//
// One-click "Auto: Strava screenshot" runs everything in one go.

window.TOOL_HANDLERS['screenshot-bg-remove'] = function ScreenshotBgRemoveTool() {
  const sourceCanvasRef = React.useRef(null);
  const previewCanvasRef = React.useRef(null);

  const [filename, setFilename] = React.useState('');
  const [origImage, setOrigImage] = React.useState(null); // ImageData of source
  const [origUrl, setOrigUrl] = React.useState('');
  const [removeColors, setRemoveColors] = React.useState([]); // [{r,g,b}]
  const [tolerance, setTolerance] = React.useState(45);
  const [crop, setCrop] = React.useState({ top: 0, right: 0, bottom: 0, left: 0 });
  const [mode, setMode] = React.useState('pick'); // 'pick' | 'crop'
  const [drag, setDrag] = React.useState(null);   // { x1, y1, x2, y2 } in image px during drag

  // ----- File load -----
  const onFile = (file) => {
    if (!file) return;
    const url = URL.createObjectURL(file);
    const img = new Image();
    img.onload = () => {
      const c = document.createElement('canvas');
      c.width = img.naturalWidth; c.height = img.naturalHeight;
      const ctx = c.getContext('2d');
      ctx.drawImage(img, 0, 0);
      const id = ctx.getImageData(0, 0, c.width, c.height);
      setOrigImage(id);
      setOrigUrl(url);
      setFilename(file.name);
      setRemoveColors([]);
      setCrop({ top: 0, right: 0, bottom: 0, left: 0 });
    };
    img.src = url;
  };

  // ----- Render source canvas (display only) -----
  React.useEffect(() => {
    if (!origImage || !sourceCanvasRef.current) return;
    const c = sourceCanvasRef.current;
    c.width = origImage.width; c.height = origImage.height;
    c.getContext('2d').putImageData(origImage, 0, 0);
  }, [origImage]);

  // ----- Render preview canvas (cropped + transparent) -----
  React.useEffect(() => {
    if (!origImage || !previewCanvasRef.current) return;
    const w = origImage.width, h = origImage.height;
    const cropX = Math.max(0, Math.min(w - 1, crop.left));
    const cropY = Math.max(0, Math.min(h - 1, crop.top));
    const cropW = Math.max(1, w - crop.left - crop.right);
    const cropH = Math.max(1, h - crop.top - crop.bottom);

    const c = previewCanvasRef.current;
    c.width = cropW; c.height = cropH;
    const ctx = c.getContext('2d');
    const newId = ctx.createImageData(cropW, cropH);
    const src = origImage.data;
    const dst = newId.data;
    const tolSq = tolerance * tolerance;

    for (let dy = 0; dy < cropH; dy++) {
      const srcRow = ((cropY + dy) * w + cropX) * 4;
      const dstRow = dy * cropW * 4;
      for (let dx = 0; dx < cropW; dx++) {
        const sI = srcRow + dx * 4;
        const dI = dstRow + dx * 4;
        const r = src[sI], g = src[sI + 1], b = src[sI + 2];
        let a = src[sI + 3];
        for (let k = 0; k < removeColors.length; k++) {
          const cc = removeColors[k];
          const dr = r - cc.r, dg = g - cc.g, db = b - cc.b;
          if (dr * dr + dg * dg + db * db <= tolSq) { a = 0; break; }
        }
        dst[dI] = r; dst[dI + 1] = g; dst[dI + 2] = b; dst[dI + 3] = a;
      }
    }
    ctx.putImageData(newId, 0, 0);
  }, [origImage, removeColors, tolerance, crop]);

  // ----- Convert mouse event → image-space (x, y) -----
  const eventToImage = (e) => {
    const c = sourceCanvasRef.current;
    if (!c) return null;
    const rect = c.getBoundingClientRect();
    const clientX = e.touches ? e.touches[0].clientX : e.clientX;
    const clientY = e.touches ? e.touches[0].clientY : e.clientY;
    const sx = Math.floor((clientX - rect.left) / rect.width * c.width);
    const sy = Math.floor((clientY - rect.top) / rect.height * c.height);
    return { sx, sy };
  };

  // ----- Pick a color by clicking on the source (pick mode only) -----
  const onSourceClick = (e) => {
    if (!origImage || mode !== 'pick') return;
    const pt = eventToImage(e); if (!pt) return;
    const { sx, sy } = pt;
    if (sx < 0 || sy < 0 || sx >= origImage.width || sy >= origImage.height) return;
    const i = (sy * origImage.width + sx) * 4;
    const newColor = {
      r: origImage.data[i],
      g: origImage.data[i + 1],
      b: origImage.data[i + 2],
    };
    const exists = removeColors.some((cc) => {
      const dr = cc.r - newColor.r, dg = cc.g - newColor.g, db = cc.b - newColor.b;
      return dr * dr + dg * dg + db * db < 100;
    });
    if (!exists) setRemoveColors([...removeColors, newColor]);
  };

  // ----- Drag to crop (crop mode only) -----
  const onSourceMouseDown = (e) => {
    if (!origImage || mode !== 'crop') return;
    e.preventDefault();
    const pt = eventToImage(e); if (!pt) return;
    setDrag({ x1: pt.sx, y1: pt.sy, x2: pt.sx, y2: pt.sy });
  };
  React.useEffect(() => {
    if (!drag) return;
    const onMove = (e) => {
      const pt = eventToImage(e); if (!pt) return;
      setDrag((d) => d ? { ...d, x2: pt.sx, y2: pt.sy } : d);
    };
    const onUp = () => {
      setDrag((d) => {
        if (!d || !origImage) return null;
        const x1 = Math.max(0, Math.min(d.x1, d.x2));
        const y1 = Math.max(0, Math.min(d.y1, d.y2));
        const x2 = Math.min(origImage.width,  Math.max(d.x1, d.x2));
        const y2 = Math.min(origImage.height, Math.max(d.y1, d.y2));
        if (x2 - x1 > 8 && y2 - y1 > 8) {
          setCrop({ left: x1, top: y1, right: origImage.width - x2, bottom: origImage.height - y2 });
        }
        return null;
      });
    };
    document.addEventListener('mousemove', onMove);
    document.addEventListener('mouseup', onUp);
    document.addEventListener('touchmove', onMove, { passive: false });
    document.addEventListener('touchend', onUp);
    return () => {
      document.removeEventListener('mousemove', onMove);
      document.removeEventListener('mouseup', onUp);
      document.removeEventListener('touchmove', onMove);
      document.removeEventListener('touchend', onUp);
    };
  }, [drag, origImage]);

  // ----- Auto-detect dominant colours within current crop -----
  // We bucket on the high 4 bits per channel (16×16×16 = 4096 buckets), then
  // return every bucket that holds at least `minPct` of the samples up to
  // `maxN`. Strava's checkerboard usually surfaces 2 dominant greys plus 2-4
  // anti-aliasing/JPEG-noise variants — we want to grab them all.
  const detectDominant = (cropOverride, maxN = 6, minPct = 0.02) => {
    const c = cropOverride || crop;
    const w = origImage.width, h = origImage.height;
    const cropX = Math.max(0, c.left);
    const cropY = Math.max(0, c.top);
    const cropW = w - c.left - c.right;
    const cropH = h - c.top - c.bottom;
    const buckets = new Map();
    const step = Math.max(2, Math.floor(Math.min(cropW, cropH) / 200));
    const data = origImage.data;
    let total = 0;
    for (let y = cropY + step; y < cropY + cropH - step; y += step) {
      for (let x = cropX + step; x < cropX + cropW - step; x += step) {
        const i = (y * w + x) * 4;
        const r = data[i] & 0xF0;
        const g = data[i + 1] & 0xF0;
        const b = data[i + 2] & 0xF0;
        const key = (r << 16) | (g << 8) | b;
        buckets.set(key, (buckets.get(key) || 0) + 1);
        total++;
      }
    }
    const minCount = Math.max(2, Math.floor(total * minPct));
    return [...buckets.entries()]
      .sort((a, b) => b[1] - a[1])
      .filter(([, count]) => count >= minCount)
      .slice(0, maxN)
      .map(([k]) => ({ r: (k >> 16) & 0xFF, g: (k >> 8) & 0xFF, b: k & 0xFF }));
  };

  const autoDetect = () => {
    if (!origImage) return;
    setRemoveColors(detectDominant());
  };

  // One-click Strava: crop status bar + paywall, then auto-detect.
  const autoStrava = () => {
    if (!origImage) return;
    const h = origImage.height;
    const newCrop = {
      top: Math.round(h * 0.08),
      bottom: Math.round(h * 0.27),
      left: 0,
      right: 0,
    };
    setCrop(newCrop);
    setRemoveColors(detectDominant(newCrop, 6, 0.02));
  };

  const removeColorAt = (idx) => setRemoveColors((prev) => prev.filter((_, i) => i !== idx));

  const reset = () => {
    setRemoveColors([]);
    setCrop({ top: 0, right: 0, bottom: 0, left: 0 });
  };

  const download = () => {
    if (!previewCanvasRef.current) return;
    previewCanvasRef.current.toBlob((blob) => {
      if (blob) window.downloadBlob(blob, (filename.replace(/\.([^.]+)$/, '') || 'screenshot') + '-transparent.png');
    }, 'image/png');
    window.mmTrackComplete?.('screenshot-bg-remove', { success: true });
  };

  // ----- UI -----
  if (!origImage) {
    return (
      <div className="mini-tool sport-tool">
        <window.MMSports.SportsToolHeader title="Screenshot BG Remover"
          sub="Drop a Strava share-screen screenshot — get a real transparent PNG."
          icon="erase" accent="#fc4c02" />
        <window.Dropzone onFile={onFile}
                         title="Drop a screenshot"
                         hint="PNG or JPG · works best on Strava / Figma transparent previews"
                         accept="image/*" />
        <div className="sport-helper" style={{ marginTop: 16 }}>
          Tip: in Strava, open <strong>Share Activity</strong> on any of your runs and screenshot the design you want — even though it's marked "Subscribers only", you can still see the preview. We'll clean it up here.
        </div>
      </div>
    );
  }

  const w = origImage.width, h = origImage.height;
  const cropW = w - crop.left - crop.right;
  const cropH = h - crop.top - crop.bottom;
  const cropPctX1 = (crop.left / w) * 100;
  const cropPctY1 = (crop.top / h) * 100;
  const cropPctX2 = ((w - crop.right) / w) * 100;
  const cropPctY2 = ((h - crop.bottom) / h) * 100;

  return (
    <div className="mini-tool sport-tool">
      <window.MMSports.SportsToolHeader title="Screenshot BG Remover"
        sub={filename} icon="erase" accent="#fc4c02" />

      <div className="ssr-actions-row">
        <button type="button" className="btn btn-primary"
                style={{ background: '#fc4c02', borderColor: '#fc4c02' }}
                onClick={autoStrava}>
          <window.Icon name="sparkle" size={14} /> Auto: Strava screenshot
        </button>
        <button type="button" className="filter-pill" onClick={autoDetect}>
          <window.Icon name="droplet" size={12} /> Auto-detect dominant colours
        </button>
        <button type="button" className="filter-pill" onClick={reset}>
          <window.Icon name="rotate" size={12} /> Reset
        </button>
        <button type="button" className="filter-pill" onClick={() => { setOrigImage(null); setOrigUrl(''); setFilename(''); }}>
          <window.Icon name="upload" size={12} /> New screenshot
        </button>
      </div>

      <div className="ssr-grid">
        {/* Source: click to pick OR drag to crop */}
        <div>
          <div className="ssr-source-head">
            <span className="mini-label" style={{ marginBottom: 0 }}>Original</span>
            <div className="ssr-mode-toggle">
              <button type="button" className={mode === 'pick' ? 'active' : ''} onClick={() => setMode('pick')}>
                <window.Icon name="droplet" size={12} /> Pick colour
              </button>
              <button type="button" className={mode === 'crop' ? 'active' : ''} onClick={() => setMode('crop')}>
                <window.Icon name="crop" size={12} /> Crop
              </button>
            </div>
          </div>
          <div className={`ssr-source ssr-mode-${mode}`}>
            <canvas ref={sourceCanvasRef}
                    onClick={onSourceClick}
                    onMouseDown={onSourceMouseDown}
                    onTouchStart={onSourceMouseDown} />
            {/* Persistent crop bounds */}
            <div className="ssr-crop-overlay"
                 style={{
                   left: cropPctX1 + '%',
                   top: cropPctY1 + '%',
                   right: (100 - cropPctX2) + '%',
                   bottom: (100 - cropPctY2) + '%',
                 }} />
            {/* Live drag rectangle while user is sketching a new crop */}
            {drag && (
              <div className="ssr-drag-overlay"
                   style={{
                     left:   (Math.min(drag.x1, drag.x2) / w * 100) + '%',
                     top:    (Math.min(drag.y1, drag.y2) / h * 100) + '%',
                     right:  ((w - Math.max(drag.x1, drag.x2)) / w * 100) + '%',
                     bottom: ((h - Math.max(drag.y1, drag.y2)) / h * 100) + '%',
                   }} />
            )}
          </div>
          <div className="ssr-source-hint">
            {mode === 'pick'
              ? 'Click any background square to add its colour. Click each shade you can still see in the preview.'
              : 'Drag to draw the crop rectangle. The orange box shows what will be exported.'}
          </div>
        </div>

        {/* Result preview on checkerboard */}
        <div>
          <div className="mini-label" style={{ marginBottom: 6 }}>
            Result · {cropW} × {cropH} px · transparent PNG
          </div>
          <div className="ssr-preview share-preview-stage">
            <canvas ref={previewCanvasRef} className="ssr-preview-canvas" />
          </div>
          <div className="ssr-source-hint">
            Still seeing background squares? Switch to <strong>Pick colour</strong> and tap each remaining shade — JPEG screenshots usually have 4-6 grey tones.
          </div>
        </div>
      </div>

      {/* Removed colors as chips */}
      <div className="ssr-section">
        <div className="mini-label">Colours being removed</div>
        <div className="ssr-color-chips">
          {removeColors.length === 0 && (
            <span style={{ color: 'var(--id-text-muted)', fontSize: 13 }}>
              None yet — click on the screenshot or use a button above.
            </span>
          )}
          {removeColors.map((c, i) => (
            <div key={i} className="ssr-chip">
              <span className="ssr-chip-swatch" style={{ background: `rgb(${c.r},${c.g},${c.b})` }} />
              <span className="ssr-chip-hex">
                {`#${c.r.toString(16).padStart(2, '0')}${c.g.toString(16).padStart(2, '0')}${c.b.toString(16).padStart(2, '0')}`.toUpperCase()}
              </span>
              <button type="button" className="ssr-chip-x" onClick={() => removeColorAt(i)} aria-label="Remove this colour">
                <window.Icon name="x" size={12} />
              </button>
            </div>
          ))}
        </div>
      </div>

      <div className="ssr-section">
        <div className="cmp-slider-row">
          <div className="cmp-label">
            <span>Tolerance</span>
            <span className="val">{tolerance}</span>
          </div>
          <input type="range" min="0" max="120" value={tolerance}
                 onChange={(e) => setTolerance(Number(e.target.value))} className="cmp-slider" />
          <div className="cmp-meta">
            Higher tolerance also removes anti-aliased edges around the BG, but can eat into text strokes.
          </div>
        </div>
      </div>

      <div className="ssr-section">
        <div className="mini-label" style={{ marginBottom: 6 }}>Crop</div>
        <div className="sport-input-grid">
          <div className="mini-field">
            <label className="mini-label">Top (px)</label>
            <input type="number" min="0" max={h - 10} className="mini-input"
                   value={crop.top} onChange={(e) => setCrop({ ...crop, top: Math.max(0, Number(e.target.value) || 0) })} />
          </div>
          <div className="mini-field">
            <label className="mini-label">Bottom (px)</label>
            <input type="number" min="0" max={h - 10} className="mini-input"
                   value={crop.bottom} onChange={(e) => setCrop({ ...crop, bottom: Math.max(0, Number(e.target.value) || 0) })} />
          </div>
          <div className="mini-field">
            <label className="mini-label">Left (px)</label>
            <input type="number" min="0" max={w - 10} className="mini-input"
                   value={crop.left} onChange={(e) => setCrop({ ...crop, left: Math.max(0, Number(e.target.value) || 0) })} />
          </div>
          <div className="mini-field">
            <label className="mini-label">Right (px)</label>
            <input type="number" min="0" max={w - 10} className="mini-input"
                   value={crop.right} onChange={(e) => setCrop({ ...crop, right: Math.max(0, Number(e.target.value) || 0) })} />
          </div>
        </div>
      </div>

      <div className="cmp-actions">
        <button className="btn btn-primary" onClick={download} disabled={removeColors.length === 0}>
          <window.Icon name="download" size={16} /> Download transparent PNG
        </button>
      </div>

      <div className="sport-helper">
        How it works: each pixel is compared to your "remove" colours (in RGB space). If any one is within the tolerance radius, that pixel becomes fully transparent. Anti-aliased text edges (white-on-grey) usually survive thanks to colour distance — bump tolerance only if grey halos remain.
      </div>
    </div>
  );
};
