/* whiteboard.jsx — full-bleed canvas with Lucide-icon rail.
   Globals: WhiteboardPage
*/

(function () {
const { useState, useEffect, useRef } = React;

const WB_COLORS = [
  { key: 'black',  val: '#1a1410' },
  { key: 'red',    val: '#cc3030' },
  { key: 'green',  val: '#3a8a3a' },
  { key: 'blue',   val: '#3060c0' },
  { key: 'purple', val: '#7a3eb8' },
];
const WB_SIZES = ['dun', 'midden', 'dik'];
const WB_SIZE_MAP = {
  pen:    { dun: 2, midden: 4, dik: 8 },
  marker: { dun: 8, midden: 16, dik: 28 },
  line:   { dun: 2, midden: 4, dik: 8 },
  rect:   { dun: 2, midden: 4, dik: 8 },
  circle: { dun: 2, midden: 4, dik: 8 },
  eraser: { dun: 14, midden: 26, dik: 48 },
  text:   { dun: 18, midden: 28, dik: 44 },
};
const WB_MAX_PAGES = 20;
const WB_UNDO_LIMIT = 30;

function WhiteboardPage() {
  const [pages, setPages] = useState([{ id: 1, background: 'blank', ops: [] }]);
  const [pageIdx, setPageIdx] = useState(0);
  const [tool, setTool]   = useState('pen');
  const [color, setColor] = useState(WB_COLORS[0].val);
  const [size, setSize]   = useState('midden');
  const [selection, setSelection] = useState(new Set());
  const [bgSize, setBgSize] = useState(32);
  const [textInput, setTextInput] = useState(null);
  const [confirmClear, setConfirmClear] = useState(false);

  const undoRef = useRef([]);
  const redoRef = useRef([]);

  const canvasRef = useRef(null);
  const wrapRef   = useRef(null);
  const fileRef   = useRef(null);
  const bgImgRef  = useRef(null);
  const dragRef   = useRef(null);

  const currentPage = pages[pageIdx];
  const ops = currentPage.ops;

  const setOps = (next, { pushUndo = true } = {}) => {
    if (pushUndo) {
      undoRef.current.push(currentPage.ops);
      if (undoRef.current.length > WB_UNDO_LIMIT) undoRef.current.shift();
      redoRef.current = [];
    }
    setPages(p => p.map((pg, i) => i === pageIdx ? { ...pg, ops: typeof next === 'function' ? next(pg.ops) : next } : pg));
  };

  const setBackground = (bg) => {
    bgImgRef.current = null;
    setPages(p => p.map((pg, i) => i === pageIdx ? { ...pg, background: bg } : pg));
  };

  useEffect(() => {
    undoRef.current = [];
    redoRef.current = [];
    setSelection(new Set());
    setTextInput(null);
  }, [pageIdx]);

  useEffect(() => {
    const bg = currentPage.background;
    if (bg && typeof bg === 'object' && bg.kind === 'image') {
      const img = new Image();
      img.onload = () => { bgImgRef.current = img; redraw(); };
      img.src = bg.dataUrl;
    } else {
      bgImgRef.current = null;
    }
    redraw();
    // eslint-disable-next-line
  }, [pageIdx, currentPage.background]);

  useEffect(() => {
    const onResize = () => {
      const cv = canvasRef.current;
      const wr = wrapRef.current;
      if (!cv || !wr) return;
      const r = wr.getBoundingClientRect();
      const dpr = window.devicePixelRatio || 1;
      cv.width  = Math.floor(r.width  * dpr);
      cv.height = Math.floor(r.height * dpr);
      cv.style.width  = r.width  + 'px';
      cv.style.height = r.height + 'px';
      const ctx = cv.getContext('2d');
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      redraw();
    };
    onResize();
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
    // eslint-disable-next-line
  }, []);

  useEffect(() => { redraw(); /* eslint-disable-next-line */ }, [pages, pageIdx, selection, bgSize]);

  function drawOp(ctx, op) {
    if (op.kind === 'pen' || op.kind === 'marker') {
      ctx.save();
      ctx.strokeStyle = op.color;
      ctx.lineWidth = op.width;
      ctx.lineCap = 'round';
      ctx.lineJoin = 'round';
      if (op.kind === 'marker') ctx.globalAlpha = 0.45;
      ctx.beginPath();
      const pts = op.pts;
      if (pts.length > 0) {
        ctx.moveTo(pts[0].x + (op.dx || 0), pts[0].y + (op.dy || 0));
        for (let i = 1; i < pts.length; i++) {
          ctx.lineTo(pts[i].x + (op.dx || 0), pts[i].y + (op.dy || 0));
        }
        if (pts.length === 1) {
          ctx.lineTo(pts[0].x + (op.dx || 0) + 0.01, pts[0].y + (op.dy || 0) + 0.01);
        }
      }
      ctx.stroke();
      ctx.restore();
    } else if (op.kind === 'line') {
      ctx.save();
      ctx.strokeStyle = op.color;
      ctx.lineWidth = op.width;
      ctx.lineCap = 'round';
      ctx.beginPath();
      ctx.moveTo(op.x1 + (op.dx || 0), op.y1 + (op.dy || 0));
      ctx.lineTo(op.x2 + (op.dx || 0), op.y2 + (op.dy || 0));
      ctx.stroke();
      ctx.restore();
    } else if (op.kind === 'rect') {
      ctx.save();
      ctx.strokeStyle = op.color;
      ctx.lineWidth = op.width;
      ctx.strokeRect(op.x + (op.dx || 0), op.y + (op.dy || 0), op.w, op.h);
      ctx.restore();
    } else if (op.kind === 'circle') {
      ctx.save();
      ctx.strokeStyle = op.color;
      ctx.lineWidth = op.width;
      ctx.beginPath();
      ctx.ellipse(op.cx + (op.dx || 0), op.cy + (op.dy || 0), op.rx, op.ry, 0, 0, Math.PI * 2);
      ctx.stroke();
      ctx.restore();
    } else if (op.kind === 'text') {
      ctx.save();
      ctx.fillStyle = op.color;
      ctx.font = `${op.size}px VT323, monospace`;
      ctx.textBaseline = 'top';
      ctx.fillText(op.text, op.x + (op.dx || 0), op.y + (op.dy || 0));
      ctx.restore();
    } else if (op.kind === 'eraser') {
      ctx.save();
      ctx.globalCompositeOperation = 'destination-out';
      ctx.strokeStyle = '#000';
      ctx.lineWidth = op.width;
      ctx.lineCap = 'round';
      ctx.lineJoin = 'round';
      ctx.beginPath();
      const pts = op.pts;
      if (pts.length > 0) {
        ctx.moveTo(pts[0].x, pts[0].y);
        for (let i = 1; i < pts.length; i++) ctx.lineTo(pts[i].x, pts[i].y);
        if (pts.length === 1) ctx.lineTo(pts[0].x + 0.01, pts[0].y + 0.01);
      }
      ctx.stroke();
      ctx.restore();
    }
  }

  function bboxOf(op) {
    if (op.kind === 'pen' || op.kind === 'marker' || op.kind === 'eraser') {
      let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
      for (const p of op.pts) {
        if (p.x < minX) minX = p.x;
        if (p.y < minY) minY = p.y;
        if (p.x > maxX) maxX = p.x;
        if (p.y > maxY) maxY = p.y;
      }
      const pad = (op.width || 4) / 2;
      return { x: minX - pad + (op.dx || 0), y: minY - pad + (op.dy || 0), w: (maxX - minX) + 2 * pad, h: (maxY - minY) + 2 * pad };
    }
    if (op.kind === 'line') {
      const x = Math.min(op.x1, op.x2), y = Math.min(op.y1, op.y2);
      return { x: x + (op.dx || 0), y: y + (op.dy || 0), w: Math.abs(op.x2 - op.x1), h: Math.abs(op.y2 - op.y1) };
    }
    if (op.kind === 'rect') return { x: op.x + (op.dx || 0), y: op.y + (op.dy || 0), w: op.w, h: op.h };
    if (op.kind === 'circle') return { x: op.cx - op.rx + (op.dx || 0), y: op.cy - op.ry + (op.dy || 0), w: op.rx * 2, h: op.ry * 2 };
    if (op.kind === 'text') {
      const approxW = op.text.length * op.size * 0.55;
      return { x: op.x + (op.dx || 0), y: op.y + (op.dy || 0), w: approxW, h: op.size };
    }
    return { x: 0, y: 0, w: 0, h: 0 };
  }

  function hitTest(op, x, y) {
    const b = bboxOf(op);
    const slop = 6;
    return x >= b.x - slop && x <= b.x + b.w + slop && y >= b.y - slop && y <= b.y + b.h + slop;
  }

  function drawBackground(ctx, w, h) {
    const bg = currentPage.background;
    if (bg && typeof bg === 'object' && bg.kind === 'image') {
      const img = bgImgRef.current;
      if (img && img.complete) {
        const scale = Math.min(w / img.width, h / img.height);
        const dw = img.width * scale, dh = img.height * scale;
        ctx.drawImage(img, (w - dw) / 2, (h - dh) / 2, dw, dh);
      }
      return;
    }
    if (bg === 'grid') {
      ctx.save();
      ctx.strokeStyle = 'rgba(110,62,200,0.20)';
      ctx.lineWidth = 1;
      const step = bgSize;
      for (let x = 0; x <= w; x += step) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, h); ctx.stroke(); }
      for (let y = 0; y <= h; y += step) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(w, y); ctx.stroke(); }
      ctx.restore();
    } else if (bg === 'lined') {
      ctx.save();
      ctx.strokeStyle = 'rgba(60,96,192,0.30)';
      ctx.lineWidth = 1;
      const step = bgSize;
      for (let y = step; y <= h; y += step) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(w, y); ctx.stroke(); }
      ctx.restore();
    } else if (bg === 'dotted') {
      ctx.save();
      ctx.fillStyle = 'rgba(110,62,200,0.35)';
      const step = bgSize;
      for (let x = step; x <= w; x += step) {
        for (let y = step; y <= h; y += step) {
          ctx.beginPath(); ctx.arc(x, y, 1.4, 0, Math.PI * 2); ctx.fill();
        }
      }
      ctx.restore();
    }
  }

  function redraw(extraDraw) {
    const cv = canvasRef.current;
    if (!cv) return;
    const ctx = cv.getContext('2d');
    const dpr = window.devicePixelRatio || 1;
    const w = cv.width / dpr;
    const h = cv.height / dpr;
    ctx.fillStyle = '#ffffff';
    ctx.fillRect(0, 0, w, h);
    drawBackground(ctx, w, h);
    for (const op of ops) drawOp(ctx, op);
    if (selection.size > 0) {
      ctx.save();
      ctx.strokeStyle = '#7a3eb8';
      ctx.lineWidth = 2;
      ctx.setLineDash([6, 4]);
      for (const idx of selection) {
        const b = bboxOf(ops[idx]);
        if (b) ctx.strokeRect(b.x - 2, b.y - 2, b.w + 4, b.h + 4);
      }
      ctx.restore();
    }
    if (extraDraw) extraDraw(ctx);
  }

  function ptFromEvent(e) {
    const cv = canvasRef.current;
    const r = cv.getBoundingClientRect();
    return { x: e.clientX - r.left, y: e.clientY - r.top };
  }

  function onPointerDown(e) {
    if (textInput) return;
    e.preventDefault();
    canvasRef.current.setPointerCapture(e.pointerId);
    const p = ptFromEvent(e);
    const w = WB_SIZE_MAP[tool]?.[size] ?? 4;

    if (tool === 'text') {
      setTextInput({ x: p.x, y: p.y, val: '' });
      return;
    }

    if (tool === 'move') {
      let hitIdx = -1;
      for (let i = ops.length - 1; i >= 0; i--) {
        if (hitTest(ops[i], p.x, p.y)) { hitIdx = i; break; }
      }
      if (hitIdx >= 0) {
        let sel = new Set(selection);
        if (e.shiftKey || !sel.has(hitIdx)) {
          if (e.shiftKey) {
            if (sel.has(hitIdx)) sel.delete(hitIdx); else sel.add(hitIdx);
          } else {
            sel = new Set([hitIdx]);
          }
        }
        setSelection(sel);
        dragRef.current = { kind: 'move-selection', start: p, last: p, indices: Array.from(sel), origPos: Array.from(sel).reduce((acc, i) => { acc[i] = { dx: ops[i].dx || 0, dy: ops[i].dy || 0 }; return acc; }, {}) };
      } else {
        setSelection(new Set());
        dragRef.current = { kind: 'lasso', start: p, end: p };
      }
      return;
    }

    if (tool === 'pen' || tool === 'marker' || tool === 'eraser') {
      dragRef.current = { kind: 'stroke', op: { kind: tool, color, width: w, pts: [p] } };
      return;
    }
    if (tool === 'line') {
      dragRef.current = { kind: 'line', start: p, end: p, width: w };
      return;
    }
    if (tool === 'rect') {
      dragRef.current = { kind: 'rect', start: p, end: p, width: w };
      return;
    }
    if (tool === 'circle') {
      dragRef.current = { kind: 'circle', start: p, end: p, width: w };
      return;
    }
  }

  function onPointerMove(e) {
    if (!dragRef.current) return;
    const p = ptFromEvent(e);
    const d = dragRef.current;
    if (d.kind === 'stroke') {
      d.op.pts.push(p);
      redraw((ctx) => drawOp(ctx, d.op));
    } else if (d.kind === 'line') {
      d.end = p;
      redraw((ctx) => drawOp(ctx, { kind: 'line', color, width: d.width, x1: d.start.x, y1: d.start.y, x2: p.x, y2: p.y }));
    } else if (d.kind === 'rect') {
      d.end = p;
      const x = Math.min(d.start.x, p.x), y = Math.min(d.start.y, p.y);
      const w = Math.abs(p.x - d.start.x), h = Math.abs(p.y - d.start.y);
      redraw((ctx) => drawOp(ctx, { kind: 'rect', color, width: d.width, x, y, w, h }));
    } else if (d.kind === 'circle') {
      d.end = p;
      const cx = (d.start.x + p.x) / 2, cy = (d.start.y + p.y) / 2;
      const rx = Math.abs(p.x - d.start.x) / 2, ry = Math.abs(p.y - d.start.y) / 2;
      redraw((ctx) => drawOp(ctx, { kind: 'circle', color, width: d.width, cx, cy, rx, ry }));
    } else if (d.kind === 'lasso') {
      d.end = p;
      redraw((ctx) => {
        ctx.save();
        ctx.strokeStyle = '#7a3eb8';
        ctx.setLineDash([4, 4]);
        ctx.lineWidth = 1;
        const x = Math.min(d.start.x, p.x), y = Math.min(d.start.y, p.y);
        const w = Math.abs(p.x - d.start.x), h = Math.abs(p.y - d.start.y);
        ctx.strokeRect(x, y, w, h);
        ctx.restore();
      });
    } else if (d.kind === 'move-selection') {
      const dx = p.x - d.start.x;
      const dy = p.y - d.start.y;
      const baseOps = pages[pageIdx].ops;
      const tempOps = baseOps.map((op, i) => d.indices.includes(i)
        ? { ...op, dx: (d.origPos[i].dx || 0) + dx, dy: (d.origPos[i].dy || 0) + dy }
        : op);
      const cv = canvasRef.current; const ctx = cv.getContext('2d');
      const dpr = window.devicePixelRatio || 1;
      const w = cv.width / dpr, h = cv.height / dpr;
      ctx.fillStyle = '#ffffff';
      ctx.fillRect(0, 0, w, h);
      drawBackground(ctx, w, h);
      for (const op of tempOps) drawOp(ctx, op);
      ctx.save(); ctx.strokeStyle = '#7a3eb8'; ctx.lineWidth = 2; ctx.setLineDash([6, 4]);
      for (const idx of d.indices) {
        const b = bboxOf(tempOps[idx]);
        if (b) ctx.strokeRect(b.x - 2, b.y - 2, b.w + 4, b.h + 4);
      }
      ctx.restore();
      d.last = p;
    }
  }

  function onPointerUp(e) {
    const d = dragRef.current;
    if (!d) return;
    dragRef.current = null;
    const p = ptFromEvent(e);

    if (d.kind === 'stroke') {
      if (d.op.pts.length > 0) setOps(o => [...o, d.op]);
    } else if (d.kind === 'line') {
      if (Math.hypot(p.x - d.start.x, p.y - d.start.y) > 2) {
        setOps(o => [...o, { kind: 'line', color, width: d.width, x1: d.start.x, y1: d.start.y, x2: p.x, y2: p.y }]);
      }
    } else if (d.kind === 'rect') {
      const x = Math.min(d.start.x, p.x), y = Math.min(d.start.y, p.y);
      const w = Math.abs(p.x - d.start.x), h = Math.abs(p.y - d.start.y);
      if (w > 2 && h > 2) setOps(o => [...o, { kind: 'rect', color, width: d.width, x, y, w, h }]);
    } else if (d.kind === 'circle') {
      const cx = (d.start.x + p.x) / 2, cy = (d.start.y + p.y) / 2;
      const rx = Math.abs(p.x - d.start.x) / 2, ry = Math.abs(p.y - d.start.y) / 2;
      if (rx > 2 && ry > 2) setOps(o => [...o, { kind: 'circle', color, width: d.width, cx, cy, rx, ry }]);
    } else if (d.kind === 'lasso') {
      const x = Math.min(d.start.x, p.x), y = Math.min(d.start.y, p.y);
      const w = Math.abs(p.x - d.start.x), h = Math.abs(p.y - d.start.y);
      const sel = new Set();
      ops.forEach((op, i) => {
        const b = bboxOf(op);
        if (b.x >= x && b.y >= y && b.x + b.w <= x + w && b.y + b.h <= y + h) sel.add(i);
      });
      setSelection(sel);
      redraw();
    } else if (d.kind === 'move-selection') {
      const dx = p.x - d.start.x;
      const dy = p.y - d.start.y;
      if (Math.abs(dx) > 1 || Math.abs(dy) > 1) {
        setOps(prev => prev.map((op, i) => d.indices.includes(i)
          ? { ...op, dx: (d.origPos[i].dx || 0) + dx, dy: (d.origPos[i].dy || 0) + dy }
          : op));
      } else {
        redraw();
      }
    }
  }

  function commitTextInput(val) {
    if (textInput && val.trim()) {
      const sz = WB_SIZE_MAP.text[size];
      setOps(o => [...o, { kind: 'text', text: val, x: textInput.x, y: textInput.y, color, size: sz }]);
    }
    setTextInput(null);
  }

  function undo() {
    if (undoRef.current.length === 0) return;
    const prev = undoRef.current.pop();
    redoRef.current.push(currentPage.ops);
    setPages(p => p.map((pg, i) => i === pageIdx ? { ...pg, ops: prev } : pg));
    setSelection(new Set());
  }
  function redo() {
    if (redoRef.current.length === 0) return;
    const next = redoRef.current.pop();
    undoRef.current.push(currentPage.ops);
    setPages(p => p.map((pg, i) => i === pageIdx ? { ...pg, ops: next } : pg));
    setSelection(new Set());
  }

  useEffect(() => {
    const h = (e) => {
      if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
      if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'z') {
        e.preventDefault();
        if (e.shiftKey) redo(); else undo();
      } else if ((e.key === 'Delete' || e.key === 'Backspace') && selection.size > 0) {
        e.preventDefault();
        const sel = selection;
        setOps(prev => prev.filter((_, i) => !sel.has(i)));
        setSelection(new Set());
      } else if (e.key === 'Escape') {
        if (selection.size > 0) setSelection(new Set());
      }
    };
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
    // eslint-disable-next-line
  }, [selection, pageIdx, pages]);

  useEffect(() => {
    const onPaste = (e) => {
      const items = e.clipboardData?.items || [];
      for (const it of items) {
        if (it.type.startsWith('image/')) {
          const blob = it.getAsFile();
          const r = new FileReader();
          r.onload = () => setBackground({ kind: 'image', dataUrl: r.result });
          r.readAsDataURL(blob);
          e.preventDefault();
          return;
        }
      }
    };
    window.addEventListener('paste', onPaste);
    return () => window.removeEventListener('paste', onPaste);
    // eslint-disable-next-line
  }, [pageIdx]);

  const prevPage = () => { if (pageIdx > 0) setPageIdx(pageIdx - 1); };
  const nextPage = () => {
    if (pageIdx < pages.length - 1) { setPageIdx(pageIdx + 1); return; }
    if (pages.length >= WB_MAX_PAGES) return;
    setPages(p => [...p, { id: (p[p.length - 1]?.id || 0) + 1, background: 'blank', ops: [] }]);
    setPageIdx(pages.length);
  };

  const cycleBg = () => {
    const cur = currentPage.background;
    const order = ['blank', 'grid', 'lined', 'dotted'];
    if (typeof cur === 'object') { setBackground('blank'); return; }
    const idx = order.indexOf(cur);
    setBackground(order[(idx + 1) % order.length]);
  };
  const bgLabel = () => {
    const cur = currentPage.background;
    if (typeof cur === 'object') return 'Beeld';
    return { blank: 'Leeg', grid: 'Rooster', lined: 'Lijntjes', dotted: 'Stippen' }[cur];
  };

  const onPickImage = (e) => {
    const f = e.target.files?.[0];
    if (!f) return;
    const r = new FileReader();
    r.onload = () => setBackground({ kind: 'image', dataUrl: r.result });
    r.readAsDataURL(f);
    e.target.value = '';
  };

  const exportPng = () => {
    const cv = canvasRef.current;
    if (!cv) return;
    const a = document.createElement('a');
    a.href = cv.toDataURL('image/png');
    const d = new Date().toISOString().slice(0, 10);
    a.download = `whiteboard-pagina-${pageIdx + 1}-${d}.png`;
    a.click();
  };

  const doClear = () => {
    setOps([], { pushUndo: true });
    setBackground('blank');
    setSelection(new Set());
    setConfirmClear(false);
  };

  const ToolBtn = ({ id, label, icon }) => (
    <button
      className={`wb-tool ${tool === id ? 'on' : ''}`}
      onClick={() => { setTool(id); setSelection(new Set()); }}
      title={label}
    ><Lucide name={icon} size={20} /></button>
  );

  const SIZE_DOT_PX = { dun: 4, midden: 10, dik: 18 };

  const showBgSlider =
    currentPage.background !== 'blank' &&
    typeof currentPage.background !== 'object';

  return (
    <div className="wb-page">
      <aside className="wb-rail">
        <div className="wb-section">
          <ToolBtn id="pen"    label="Pen"                 icon="pen" />
          <ToolBtn id="marker" label="Marker"              icon="highlighter" />
          <ToolBtn id="line"   label="Lijn"                icon="slash" />
          <ToolBtn id="rect"   label="Rechthoek"           icon="square" />
          <ToolBtn id="circle" label="Cirkel"              icon="circle" />
          <ToolBtn id="eraser" label="Gum"                 icon="eraser" />
          <ToolBtn id="text"   label="Tekst"               icon="type" />
          <ToolBtn id="move"   label="Verplaats / selecteer" icon="move" />
        </div>

        <div className="wb-section">
          <div className="wb-size-row">
            {WB_SIZES.map(s => (
              <button
                key={s}
                className={`wb-size-dot ${size === s ? 'on' : ''}`}
                onClick={() => setSize(s)}
                title={s.charAt(0).toUpperCase() + s.slice(1)}
              >
                <SizeDot px={SIZE_DOT_PX[s]} />
              </button>
            ))}
          </div>
        </div>

        <div className="wb-section">
          <div className="wb-color-row">
            {WB_COLORS.map(c => (
              <button key={c.key} className={`wb-color ${color === c.val ? 'on' : ''}`}
                style={{ background: c.val }} onClick={() => setColor(c.val)} title={c.key} />
            ))}
          </div>
        </div>

        <div className="wb-section">
          <div className="wb-row-2">
            <button className="wb-tool" onClick={undo} title="Ongedaan (Ctrl+Z)" disabled={undoRef.current.length === 0}>
              <Lucide name="undo-2" size={18} />
            </button>
            <button className="wb-tool" onClick={redo} title="Opnieuw (Ctrl+Shift+Z)" disabled={redoRef.current.length === 0}>
              <Lucide name="redo-2" size={18} />
            </button>
          </div>
        </div>

        <div className="wb-section">
          <div className="wb-bg-row">
            <button className="wb-tool" onClick={cycleBg} title={`Achtergrond: ${bgLabel()}`}>
              <Lucide name="grid-3x3" size={18} />
            </button>
            {showBgSlider && (
              <input
                type="range"
                min="12" max="80"
                value={bgSize}
                onChange={(e) => setBgSize(+e.target.value)}
                className="wb-bg-slider"
                orient="vertical"
                title="Afstand"
              />
            )}
          </div>
          <div className="wb-row-2">
            <button className="wb-tool" onClick={() => fileRef.current?.click()} title="Foto als achtergrond (of Ctrl+V)">
              <Lucide name="image" size={18} />
            </button>
            <input ref={fileRef} type="file" accept="image/*" hidden onChange={onPickImage} />
            <button className="wb-tool" onClick={exportPng} title="Exporteer als PNG">
              <Lucide name="download" size={18} />
            </button>
          </div>
        </div>

        <div className="wb-section wb-page-section">
          <div className="wb-row-2">
            <button className="wb-tool" onClick={prevPage} disabled={pageIdx === 0} title="Vorige pagina">
              <Lucide name="chevron-left" size={18} />
            </button>
            <button
              className="wb-tool"
              onClick={nextPage}
              disabled={pages.length >= WB_MAX_PAGES && pageIdx === pages.length - 1}
              title="Volgende pagina (voegt nieuwe toe)"
            >
              <Lucide name="chevron-right" size={18} />
            </button>
          </div>
          <span className="wb-page-num">{pageIdx + 1}/{pages.length}</span>
        </div>

        <div className="wb-section">
          {confirmClear ? (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
              <span style={{ fontSize: 10, color: 'var(--danger)', textAlign: 'center' }}>Zeker?</span>
              <button className="wb-tool" style={{ borderColor: 'var(--danger)', color: 'var(--danger)' }} onClick={doClear} title="Ja, wis pagina">
                <Lucide name="check" size={18} />
              </button>
              <button className="wb-tool" onClick={() => setConfirmClear(false)} title="Annuleer">
                <Lucide name="x" size={18} />
              </button>
            </div>
          ) : (
            <button className="wb-tool" onClick={() => setConfirmClear(true)} title="Pagina wissen">
              <Lucide name="trash-2" size={18} />
            </button>
          )}
        </div>
      </aside>

      <div className="wb-canvas-wrap" ref={wrapRef}>
        <canvas
          ref={canvasRef}
          className="wb-canvas"
          onPointerDown={onPointerDown}
          onPointerMove={onPointerMove}
          onPointerUp={onPointerUp}
          onPointerCancel={onPointerUp}
        />
        {textInput && (
          <input
            autoFocus
            className="wb-text-input"
            style={{
              position: 'absolute',
              left: textInput.x,
              top: textInput.y,
              fontSize: WB_SIZE_MAP.text[size],
              color,
              fontFamily: 'VT323, monospace',
            }}
            value={textInput.val}
            onChange={(e) => setTextInput({ ...textInput, val: e.target.value })}
            onBlur={(e) => commitTextInput(e.target.value)}
            onKeyDown={(e) => {
              if (e.key === 'Enter') { e.preventDefault(); commitTextInput(e.target.value); }
              if (e.key === 'Escape') { e.preventDefault(); setTextInput(null); }
            }}
          />
        )}
      </div>
    </div>
  );
}

Object.assign(window, { WhiteboardPage });
})();
