// Scanned PDF — make a digital PDF look like it was printed and scanned.
// Uses pdf.js to render pages and pdf-lib to build the output PDF with scan effects
// (noise, rotation jitter, brightness/contrast, paper tint) applied on canvas.

var SCANNED_PDFJS_URL = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/build/pdf.min.js';
var SCANNED_PDFJS_WORKER = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/build/pdf.worker.min.js';
var SCANNED_PDFLIB_URL = 'https://cdn.jsdelivr.net/npm/pdf-lib@1.17.1/dist/pdf-lib.min.js';

window.TOOL_HANDLERS['scanned-pdf'] = function ScannedPdfTool() {
  var _useState = function (init) { return React.useState(init); };

  var ref = React.useRef;
  var useState = _useState;
  var useEffect = React.useEffect;
  var useCallback = React.useCallback;

  var readyS = useState(false);
  var ready = readyS[0]; var setReady = readyS[1];

  var loadErrS = useState('');
  var loadErr = loadErrS[0]; var setLoadErr = loadErrS[1];

  var fileS = useState(null);
  var file = fileS[0]; var setFile = fileS[1];

  var noiseS = useState(30);
  var noise = noiseS[0]; var setNoise = noiseS[1];

  var jitterS = useState(1);
  var jitter = jitterS[0]; var setJitter = jitterS[1];

  var brightnessS = useState(-10);
  var brightness = brightnessS[0]; var setBrightness = brightnessS[1];

  var contrastS = useState(10);
  var contrast = contrastS[0]; var setContrast = contrastS[1];

  var paperColorS = useState('white');
  var paperColor = paperColorS[0]; var setPaperColor = paperColorS[1];

  var qualityS = useState('medium');
  var quality = qualityS[0]; var setQuality = qualityS[1];

  var busyS = useState(false);
  var busy = busyS[0]; var setBusy = busyS[1];

  var progressS = useState(0);
  var progress = progressS[0]; var setProgress = progressS[1];

  var statusS = useState('');
  var status = statusS[0]; var setStatus = statusS[1];

  var errS = useState('');
  var err = errS[0]; var setErr = errS[1];

  var previewBeforeS = useState('');
  var previewBefore = previewBeforeS[0]; var setPreviewBefore = previewBeforeS[1];

  var previewAfterS = useState('');
  var previewAfter = previewAfterS[0]; var setPreviewAfter = previewAfterS[1];

  var resultBlobS = useState(null);
  var resultBlob = resultBlobS[0]; var setResultBlob = resultBlobS[1];

  var totalPagesS = useState(0);
  var totalPages = totalPagesS[0]; var setTotalPages = totalPagesS[1];

  var DPI_MAP = { low: 150, medium: 200, high: 300 };

  // Load both libraries on mount
  useEffect(function () {
    Promise.all([
      window.loadScript(SCANNED_PDFJS_URL),
      window.loadScript(SCANNED_PDFLIB_URL),
    ]).then(function () {
      window.pdfjsLib.GlobalWorkerOptions.workerSrc = SCANNED_PDFJS_WORKER;
      setReady(true);
    }).catch(function (e) {
      setLoadErr(e.message || 'Failed to load PDF libraries');
    });
  }, []);

  // Apply scan effects to canvas image data
  var applyScanEffects = function (canvas, opts) {
    var ctx = canvas.getContext('2d');
    var w = canvas.width;
    var h = canvas.height;

    // 1. Rotation jitter: redraw with slight random rotation
    if (opts.jitter > 0) {
      var angle = (Math.random() * 2 - 1) * opts.jitter * (Math.PI / 180);
      var tempCanvas = document.createElement('canvas');
      tempCanvas.width = w;
      tempCanvas.height = h;
      var tempCtx = tempCanvas.getContext('2d');
      tempCtx.drawImage(canvas, 0, 0);

      // Clear and rotate
      ctx.clearRect(0, 0, w, h);
      // Fill with paper background so rotated edges aren't transparent
      ctx.fillStyle = opts.paperColor === 'yellowed' ? '#f5f0e0' : '#ffffff';
      ctx.fillRect(0, 0, w, h);
      ctx.save();
      ctx.translate(w / 2, h / 2);
      ctx.rotate(angle);
      ctx.drawImage(tempCanvas, -w / 2, -h / 2);
      ctx.restore();
    }

    // 2. Pixel manipulation: noise, brightness, contrast, tint
    var imageData = ctx.getImageData(0, 0, w, h);
    var data = imageData.data;
    var contrastFactor = (259 * (opts.contrast + 255)) / (255 * (259 - opts.contrast));
    var noiseAmt = opts.noise;
    var bright = opts.brightness;
    var yellowed = opts.paperColor === 'yellowed';

    for (var i = 0; i < data.length; i += 4) {
      var r = data[i];
      var g = data[i + 1];
      var b = data[i + 2];

      // Add noise (random per channel)
      if (noiseAmt > 0) {
        r += (Math.random() * 2 - 1) * noiseAmt;
        g += (Math.random() * 2 - 1) * noiseAmt;
        b += (Math.random() * 2 - 1) * noiseAmt;
      }

      // Brightness
      r += bright;
      g += bright;
      b += bright;

      // Contrast
      r = contrastFactor * (r - 128) + 128;
      g = contrastFactor * (g - 128) + 128;
      b = contrastFactor * (b - 128) + 128;

      // Yellow tint: boost R and G slightly
      if (yellowed) {
        r += 12;
        g += 8;
        b -= 6;
      }

      // Clamp
      data[i] = Math.max(0, Math.min(255, r));
      data[i + 1] = Math.max(0, Math.min(255, g));
      data[i + 2] = Math.max(0, Math.min(255, b));
    }
    ctx.putImageData(imageData, 0, 0);
  };

  // Render a single page to a canvas with scan effects applied
  var renderPage = function (pdfDoc, pageNum, dpi, opts) {
    return pdfDoc.getPage(pageNum).then(function (page) {
      var scale = dpi / 72;
      var viewport = page.getViewport({ scale: scale });
      var canvas = document.createElement('canvas');
      canvas.width = viewport.width;
      canvas.height = viewport.height;
      var ctx = canvas.getContext('2d');

      // Fill background
      ctx.fillStyle = opts.paperColor === 'yellowed' ? '#f5f0e0' : '#ffffff';
      ctx.fillRect(0, 0, canvas.width, canvas.height);

      return page.render({ canvasContext: ctx, viewport: viewport }).promise.then(function () {
        applyScanEffects(canvas, opts);
        return canvas;
      });
    });
  };

  var process = function () {
    if (!file || busy) return;
    setBusy(true);
    setErr('');
    setProgress(0);
    setStatus('Reading PDF...');
    setResultBlob(null);
    setPreviewBefore('');
    setPreviewAfter('');

    var dpi = DPI_MAP[quality] || 200;
    var opts = {
      noise: noise,
      jitter: jitter,
      brightness: brightness,
      contrast: contrast,
      paperColor: paperColor,
    };

    file.arrayBuffer().then(function (buf) {
      var bytes = new Uint8Array(buf);
      return window.pdfjsLib.getDocument({ data: bytes }).promise;
    }).then(function (pdfDoc) {
      var numPages = pdfDoc.numPages;
      setTotalPages(numPages);
      setStatus('Rendering pages...');

      // First render page 1 clean for "before" preview
      var beforeScale = 200 / 72;
      return pdfDoc.getPage(1).then(function (page) {
        var vp = page.getViewport({ scale: beforeScale });
        var bc = document.createElement('canvas');
        bc.width = vp.width;
        bc.height = vp.height;
        var bctx = bc.getContext('2d');
        bctx.fillStyle = '#ffffff';
        bctx.fillRect(0, 0, bc.width, bc.height);
        return page.render({ canvasContext: bctx, viewport: vp }).promise.then(function () {
          setPreviewBefore(bc.toDataURL('image/jpeg', 0.92));
          return { pdfDoc: pdfDoc, numPages: numPages };
        });
      });
    }).then(function (ctx) {
      var pdfDoc = ctx.pdfDoc;
      var numPages = ctx.numPages;
      var dpi = DPI_MAP[quality] || 200;
      var jpegBuffers = [];
      var pageDims = [];

      // Process pages sequentially
      var chain = Promise.resolve();
      for (var i = 1; i <= numPages; i++) {
        (function (pageNum) {
          chain = chain.then(function () {
            setStatus('Processing page ' + pageNum + ' / ' + numPages + '...');
            setProgress(Math.round(((pageNum - 1) / numPages) * 80));
            return renderPage(pdfDoc, pageNum, dpi, opts);
          }).then(function (canvas) {
            // Save preview of first page after effects
            if (pageNum === 1) {
              setPreviewAfter(canvas.toDataURL('image/jpeg', 0.92));
            }
            pageDims.push({ w: canvas.width, h: canvas.height });
            return new Promise(function (resolve) {
              canvas.toBlob(function (blob) {
                blob.arrayBuffer().then(function (ab) {
                  jpegBuffers.push(new Uint8Array(ab));
                  resolve();
                });
              }, 'image/jpeg', quality === 'low' ? 0.7 : quality === 'high' ? 0.92 : 0.82);
            });
          });
        })(i);
      }

      return chain.then(function () {
        return { jpegBuffers: jpegBuffers, pageDims: pageDims };
      });
    }).then(function (ctx) {
      setStatus('Building output PDF...');
      setProgress(85);
      var PDFDocument = window.PDFLib.PDFDocument;
      return PDFDocument.create().then(function (outPdf) {
        var chain = Promise.resolve();
        ctx.jpegBuffers.forEach(function (jpegBytes, idx) {
          chain = chain.then(function () {
            return outPdf.embedJpg(jpegBytes).then(function (img) {
              var dims = ctx.pageDims[idx];
              // Page size at 72 DPI (standard PDF points)
              var dpi = DPI_MAP[quality] || 200;
              var pw = (dims.w / dpi) * 72;
              var ph = (dims.h / dpi) * 72;
              var page = outPdf.addPage([pw, ph]);
              page.drawImage(img, { x: 0, y: 0, width: pw, height: ph });
            });
          });
        });
        return chain.then(function () {
          return outPdf.save();
        });
      });
    }).then(function (pdfBytes) {
      setProgress(100);
      setStatus('Done!');
      var blob = new Blob([pdfBytes], { type: 'application/pdf' });
      setResultBlob(blob);
      setBusy(false);
      window.mmTrackComplete && window.mmTrackComplete('scanned-pdf', { success: true });
    }).catch(function (e) {
      setErr(e.message || 'Failed to process PDF');
      setBusy(false);
      setStatus('');
      setProgress(0);
    });
  };

  var download = function () {
    if (!resultBlob || !file) return;
    var name = file.name.replace(/\.pdf$/i, '') + '-scanned.pdf';
    window.downloadBlob(resultBlob, name);
  };

  var reset = function () {
    setFile(null);
    setResultBlob(null);
    setPreviewBefore('');
    setPreviewAfter('');
    setProgress(0);
    setStatus('');
    setErr('');
    setTotalPages(0);
  };

  if (loadErr) return <window.ToolError error={loadErr} hint="Could not load PDF libraries from CDN." />;
  if (!ready) return <window.LoadingCard label="Loading PDF libraries..." sub="pdf.js + pdf-lib from CDN" />;

  if (!file) {
    return <window.Dropzone onFile={function (f) { setFile(f); }} title="Drop a PDF here" hint="Make it look like a scanned document" accept="application/pdf,.pdf" />;
  }

  return (
    <div className="mini-tool">
      <div className="mini-label" style={{ marginBottom: 4 }}>
        {file.name} ({window.fmtBytes(file.size)})
        {totalPages > 0 && <span> &middot; {totalPages} page{totalPages === 1 ? '' : 's'}</span>}
      </div>

      {/* Controls */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '10px 20px', marginTop: 12 }}>
        <div>
          <div className="cmp-label"><span>Noise level</span><span className="val">{noise}</span></div>
          <input type="range" min="0" max="100" step="1" value={noise}
                 onChange={function (e) { setNoise(Number(e.target.value)); }}
                 className="cmp-slider" disabled={busy} />
        </div>
        <div>
          <div className="cmp-label"><span>Rotation jitter</span><span className="val">{jitter}&deg;</span></div>
          <input type="range" min="0" max="5" step="0.5" value={jitter}
                 onChange={function (e) { setJitter(Number(e.target.value)); }}
                 className="cmp-slider" disabled={busy} />
        </div>
        <div>
          <div className="cmp-label"><span>Brightness</span><span className="val">{brightness}</span></div>
          <input type="range" min="-50" max="50" step="1" value={brightness}
                 onChange={function (e) { setBrightness(Number(e.target.value)); }}
                 className="cmp-slider" disabled={busy} />
        </div>
        <div>
          <div className="cmp-label"><span>Contrast</span><span className="val">{contrast}</span></div>
          <input type="range" min="-50" max="50" step="1" value={contrast}
                 onChange={function (e) { setContrast(Number(e.target.value)); }}
                 className="cmp-slider" disabled={busy} />
        </div>
      </div>

      <div className="mini-row" style={{ marginTop: 14, gap: 16 }}>
        <div>
          <label className="mini-label">Paper color</label>
          <div style={{ display: 'flex', gap: 6 }}>
            {[['white', 'White'], ['yellowed', 'Yellowed']].map(function (pair) {
              return (
                <button key={pair[0]}
                        className={'filter-pill' + (paperColor === pair[0] ? ' active' : '')}
                        onClick={function () { setPaperColor(pair[0]); }}
                        disabled={busy}>
                  {pair[1]}
                </button>
              );
            })}
          </div>
        </div>
        <div>
          <label className="mini-label">Quality (DPI)</label>
          <div style={{ display: 'flex', gap: 6 }}>
            {[['low', 'Low (150)'], ['medium', 'Medium (200)'], ['high', 'High (300)']].map(function (pair) {
              return (
                <button key={pair[0]}
                        className={'filter-pill' + (quality === pair[0] ? ' active' : '')}
                        onClick={function () { setQuality(pair[0]); }}
                        disabled={busy}>
                  {pair[1]}
                </button>
              );
            })}
          </div>
        </div>
      </div>

      {/* Progress bar */}
      {busy && (
        <div style={{ marginTop: 16 }}>
          <div className="cmp-meta" style={{ marginBottom: 6 }}>{status}</div>
          <div style={{
            width: '100%',
            height: 8,
            background: 'var(--id-border)',
            borderRadius: 4,
            overflow: 'hidden',
          }}>
            <div style={{
              width: progress + '%',
              height: '100%',
              background: 'var(--id-primary)',
              borderRadius: 4,
              transition: 'width 0.3s ease',
            }} />
          </div>
        </div>
      )}

      {err && (
        <div style={{ color: '#c8321f', marginTop: 12, padding: '8px 12px', background: 'rgba(200,50,31,0.08)', borderRadius: 8, fontSize: 13 }}>
          <window.Icon name="x" size={14} style={{ verticalAlign: -2, marginRight: 4 }} /> {err}
        </div>
      )}

      {/* Before/After preview */}
      {(previewBefore || previewAfter) && (
        <div style={{ marginTop: 16 }}>
          <div className="mini-label">Preview (page 1)</div>
          <div className="cmp-preview" style={{ gridTemplateColumns: '1fr 1fr', gap: 12, marginTop: 6 }}>
            {previewBefore && (
              <div className="cmp-side">
                <div className="cmp-ttl">Original</div>
                <img src={previewBefore} alt="Original page 1" style={{ width: '100%', borderRadius: 8, border: '1px solid var(--id-border)' }} />
              </div>
            )}
            {previewAfter && (
              <div className="cmp-side after">
                <div className="cmp-ttl">Scanned</div>
                <img src={previewAfter} alt="Scanned page 1" style={{ width: '100%', borderRadius: 8, border: '1px solid var(--id-border)' }} />
              </div>
            )}
          </div>
        </div>
      )}

      <div className="cmp-actions">
        <button className="btn btn-secondary" onClick={reset} disabled={busy}>
          <window.Icon name="upload" size={16} /> Choose another
        </button>
        {!resultBlob && (
          <button className="btn btn-primary" onClick={process} disabled={busy}>
            <window.Icon name="bolt" size={16} /> {busy ? 'Processing...' : 'Make it look scanned'}
          </button>
        )}
        {resultBlob && (
          <button className="btn btn-primary" onClick={download}>
            <window.Icon name="download" size={16} /> Download scanned PDF
          </button>
        )}
      </div>

      {resultBlob && (
        <div className="cmp-meta" style={{ marginTop: 8, textAlign: 'center' }}>
          Output: {window.fmtBytes(resultBlob.size)}
          {' '}&middot;{' '}
          <button className="filter-pill" onClick={function () { setResultBlob(null); setPreviewAfter(''); process(); }}
                  style={{ fontSize: 12 }}>
            Re-process with new settings
          </button>
        </div>
      )}
    </div>
  );
};
