// ===========================================================================
// LEONCAD — two-dimensional drafting
// ===========================================================================
// Modelled on AutoCAD's working shape, which is four things and not a menu:
//   · a COMMAND LINE that every tool can also be reached from (L, C, A, DIM…)
//   · LAYERS, each with a colour, a line type and a lock
//   · OBJECT SNAP — endpoint, midpoint, centre, intersection, grid
//   · a MODEL space you draw in and a PAPER sheet you issue from
//
// What it deliberately is NOT: a DWG editor. DWG is an undocumented binary
// format and a browser cannot open one honestly; nothing here pretends to. It
// reads and writes its OWN drawings, and exports DXF — which is documented, is
// what AutoCAD itself uses for interchange, and is what the fenestration
// importer already reads.

const CAD_TOOLS = [
  { key: 'select', label: 'Select', cmd: 'S', icon: '➤', hint: 'Click a shape. Shift-click to add.' },
  { key: 'line', label: 'Line', cmd: 'L', icon: '╱', hint: 'Click for each point. Enter or right-click ends it.' },
  { key: 'pline', label: 'Polyline', cmd: 'PL', icon: '⌇', hint: 'A chain of segments, kept as one object.' },
  { key: 'rect', label: 'Rectangle', cmd: 'REC', icon: '▭', hint: 'Two opposite corners.' },
  { key: 'circle', label: 'Circle', cmd: 'C', icon: '○', hint: 'Centre, then a point on it.' },
  { key: 'arc', label: 'Arc', cmd: 'A', icon: '◜', hint: 'Start, end, then a point it passes through.' },
  { key: 'dim', label: 'Dimension', cmd: 'DIM', icon: '↔', hint: 'Two points; the figure is measured, never typed.' },
  { key: 'text', label: 'Text', cmd: 'T', icon: 'A', hint: 'Click where it goes.' },
  { key: 'move', label: 'Move', cmd: 'M', icon: '✥', hint: 'Select first, then a base point and a destination.' },
  { key: 'erase', label: 'Erase', cmd: 'E', icon: '⌫', hint: 'Click what goes.' },
];
const CAD_SNAPS = [
  { key: 'end', label: 'Endpoint' },
  { key: 'mid', label: 'Midpoint' },
  { key: 'cen', label: 'Centre' },
  { key: 'grid', label: 'Grid' },
];
const CAD_LINETYPES = ['Continuous', 'Hidden', 'Center', 'Phantom'];
const CAD_DEFAULT_LAYERS = [
  { id: 'l-0', name: '0', color: '#111111', lineType: 'Continuous', weight: 0.35, on: true, locked: false },
  { id: 'l-walls', name: 'WALLS', color: '#111111', lineType: 'Continuous', weight: 0.6, on: true, locked: false },
  { id: 'l-hidden', name: 'HIDDEN', color: '#777777', lineType: 'Hidden', weight: 0.25, on: true, locked: false },
  { id: 'l-dims', name: 'DIMENSIONS', color: '#8a6d3b', lineType: 'Continuous', weight: 0.18, on: true, locked: false },
  { id: 'l-text', name: 'TEXT', color: '#111111', lineType: 'Continuous', weight: 0.18, on: true, locked: false },
  { id: 'l-centre', name: 'CENTRE', color: '#b03030', lineType: 'Center', weight: 0.18, on: true, locked: false },
];
const CAD_DASH = { Continuous: '', Hidden: '6 4', Center: '18 4 4 4', Phantom: '20 4 4 4 4 4' };

function cadMakeDrawing(data, by) {
  const d = data || {};
  return {
    id: d.id || uid('cad'),
    name: d.name || 'Drawing 1',
    projectId: d.projectId || null,
    // Millimetres, like every other dimension in this app. A drawing that keeps
    // its own unit is a drawing that disagrees with the rest of the Hub.
    units: 'mm',
    scaleDenom: d.scaleDenom || 20,
    sheet: d.sheet || 'A2',
    layers: Array.isArray(d.layers) ? cloneDeep(d.layers) : cloneDeep(CAD_DEFAULT_LAYERS),
    entities: Array.isArray(d.entities) ? cloneDeep(d.entities) : [],
    createdBy: by || '', createdDate: todayISO(), modifiedDate: todayISO(),
  };
}
function cadEnt(kind, layerId, props) {
  return Object.assign({ id: uid('cadent'), kind, layerId: layerId || 'l-0' }, props || {});
}
// Where a click really landed, once the snaps have had their say. Object snap
// is what separates drafting from drawing: a line that ends "about there" is
// not a line anyone can build from.
function cadSnapPoint(p, ents, opts) {
  const o = opts || {};
  const tol = o.tol || 8;
  let best = null, bestD = tol;
  const consider = (q, kind) => {
    const d = Math.hypot(q.x - p.x, q.y - p.y);
    if (d < bestD) { bestD = d; best = { x: q.x, y: q.y, kind }; }
  };
  (ents || []).forEach(e => {
    if (e.kind === 'line' || e.kind === 'dim') {
      if (o.end) { consider({ x: e.x1, y: e.y1 }, 'end'); consider({ x: e.x2, y: e.y2 }, 'end'); }
      if (o.mid) consider({ x: (e.x1 + e.x2) / 2, y: (e.y1 + e.y2) / 2 }, 'mid');
    } else if (e.kind === 'pline') {
      (e.pts || []).forEach((q, i) => {
        if (o.end) consider(q, 'end');
        if (o.mid && i) consider({ x: (q.x + e.pts[i - 1].x) / 2, y: (q.y + e.pts[i - 1].y) / 2 }, 'mid');
      });
    } else if (e.kind === 'rect') {
      const c = [{ x: e.x, y: e.y }, { x: e.x + e.w, y: e.y }, { x: e.x + e.w, y: e.y + e.h }, { x: e.x, y: e.y + e.h }];
      if (o.end) c.forEach(q => consider(q, 'end'));
      if (o.mid) c.forEach((q, i) => consider({ x: (q.x + c[(i + 1) % 4].x) / 2, y: (q.y + c[(i + 1) % 4].y) / 2 }, 'mid'));
      if (o.cen) consider({ x: e.x + e.w / 2, y: e.y + e.h / 2 }, 'cen');
    } else if (e.kind === 'circle' || e.kind === 'arc') {
      if (o.cen) consider({ x: e.cx, y: e.cy }, 'cen');
    }
  });
  if (!best && o.grid) {
    const g = o.gridSize || 10;
    best = { x: Math.round(p.x / g) * g, y: Math.round(p.y / g) * g, kind: 'grid' };
  }
  return best || { x: p.x, y: p.y, kind: null };
}
// Ortho: hold the second point to the horizontal or the vertical, whichever it
// is closer to. AutoCAD's F8, and the reason drawn lines are actually straight.
function cadOrtho(a, b) {
  if (!a) return b;
  return Math.abs(b.x - a.x) >= Math.abs(b.y - a.y) ? { x: b.x, y: a.y } : { x: a.x, y: b.y };
}

// ── Rendering ──────────────────────────────────────────────────────────────
function CadEntity({ e, layer, selected }) {
  if (!layer || layer.on === false) return null;
  const common = {
    stroke: selected ? 'var(--leon-brown)' : layer.color,
    strokeWidth: (selected ? 1.6 : 1) * (layer.weight || 0.3) * 2.2,
    strokeDasharray: CAD_DASH[layer.lineType] || '',
    fill: 'none', vectorEffect: 'non-scaling-stroke',
  };
  if (e.kind === 'line') return <line x1={e.x1} y1={e.y1} x2={e.x2} y2={e.y2} {...common} />;
  if (e.kind === 'pline') return <polyline points={(e.pts || []).map(p => `${p.x},${p.y}`).join(' ')} {...common} />;
  if (e.kind === 'rect') return <rect x={e.x} y={e.y} width={e.w} height={e.h} {...common} />;
  if (e.kind === 'circle') return <circle cx={e.cx} cy={e.cy} r={e.r} {...common} />;
  if (e.kind === 'arc') {
    const a0 = Math.atan2(e.y1 - e.cy, e.x1 - e.cx), a1 = Math.atan2(e.y2 - e.cy, e.x2 - e.cx);
    const large = Math.abs(a1 - a0) > Math.PI ? 1 : 0;
    return <path d={`M ${e.x1} ${e.y1} A ${e.r} ${e.r} 0 ${large} ${e.sweep ? 1 : 0} ${e.x2} ${e.y2}`} {...common} />;
  }
  if (e.kind === 'text') {
    return <text x={e.x} y={e.y} fill={selected ? 'var(--leon-brown)' : layer.color}
      fontSize={e.size || 24} fontFamily="'Century Gothic Leon', sans-serif">{e.text}</text>;
  }
  if (e.kind === 'dim') {
    // The figure is MEASURED off the geometry, never typed. A dimension that
    // can be typed over is a dimension that stops agreeing with the drawing —
    // which is the single most dangerous thing on a shop drawing.
    const len = Math.hypot(e.x2 - e.x1, e.y2 - e.y1);
    const mx = (e.x1 + e.x2) / 2, my = (e.y1 + e.y2) / 2;
    const ang = Math.atan2(e.y2 - e.y1, e.x2 - e.x1) * 180 / Math.PI;
    const tick = 10;
    const nx = -Math.sin(ang * Math.PI / 180) * tick, ny = Math.cos(ang * Math.PI / 180) * tick;
    return (
      <g>
        <line x1={e.x1} y1={e.y1} x2={e.x2} y2={e.y2} {...common} />
        <line x1={e.x1 - nx / 2} y1={e.y1 - ny / 2} x2={e.x1 + nx / 2} y2={e.y1 + ny / 2} {...common} />
        <line x1={e.x2 - nx / 2} y1={e.y2 - ny / 2} x2={e.x2 + nx / 2} y2={e.y2 + ny / 2} {...common} />
        <text x={mx} y={my - 6} fill={selected ? 'var(--leon-brown)' : layer.color} fontSize="22"
          textAnchor="middle" transform={`rotate(${Math.abs(ang) > 90 ? ang + 180 : ang} ${mx} ${my - 6})`}
          fontFamily="'Century Gothic Leon', sans-serif">{Math.round(len)}</text>
      </g>
    );
  }
  return null;
}

// ── DXF out ────────────────────────────────────────────────────────────────
// Documented, ASCII, and what AutoCAD itself uses for interchange — so this is
// a real export rather than a claim. Minimal R12 entities, which every CAD
// program still reads.
function cadToDxf(dwg) {
  const L = [];
  const p = (code, val) => { L.push(String(code)); L.push(String(val)); };
  p(0, 'SECTION'); p(2, 'ENTITIES');
  (dwg.entities || []).forEach(e => {
    const lay = (dwg.layers.find(l => l.id === e.layerId) || { name: '0' }).name;
    if (e.kind === 'line' || e.kind === 'dim') {
      p(0, 'LINE'); p(8, lay); p(10, e.x1); p(20, -e.y1); p(11, e.x2); p(21, -e.y2);
    } else if (e.kind === 'rect') {
      const c = [[e.x, e.y], [e.x + e.w, e.y], [e.x + e.w, e.y + e.h], [e.x, e.y + e.h], [e.x, e.y]];
      for (let i = 0; i < 4; i++) { p(0, 'LINE'); p(8, lay); p(10, c[i][0]); p(20, -c[i][1]); p(11, c[i + 1][0]); p(21, -c[i + 1][1]); }
    } else if (e.kind === 'pline') {
      const pts = e.pts || [];
      for (let i = 1; i < pts.length; i++) { p(0, 'LINE'); p(8, lay); p(10, pts[i - 1].x); p(20, -pts[i - 1].y); p(11, pts[i].x); p(21, -pts[i].y); }
    } else if (e.kind === 'circle') {
      p(0, 'CIRCLE'); p(8, lay); p(10, e.cx); p(20, -e.cy); p(40, e.r);
    } else if (e.kind === 'arc') {
      const a0 = Math.atan2(-(e.y1 - e.cy), e.x1 - e.cx) * 180 / Math.PI;
      const a1 = Math.atan2(-(e.y2 - e.cy), e.x2 - e.cx) * 180 / Math.PI;
      p(0, 'ARC'); p(8, lay); p(10, e.cx); p(20, -e.cy); p(40, e.r); p(50, a0); p(51, a1);
    } else if (e.kind === 'text') {
      p(0, 'TEXT'); p(8, lay); p(10, e.x); p(20, -e.y); p(40, e.size || 24); p(1, e.text || '');
    }
  });
  p(0, 'ENDSEC'); p(0, 'EOF');
  return L.join('\n');
}

function LeonCadSoftware({ ctx }) {
  const [dwgs, setDwgs] = useState(() => [cadMakeDrawing({ name: 'Drawing 1' }, ctx.currentUserName)]);
  const [at, setAt] = useState(0);
  const dwg = dwgs[at] || dwgs[0];
  const setDwg = fn => setDwgs(list => list.map((d, i) => i === at ? Object.assign({}, fn(d), { modifiedDate: todayISO() }) : d));

  const [tool, setTool] = useState('line');
  const [layerId, setLayerId] = useState('l-0');
  const [pending, setPending] = useState([]);        // points collected so far
  const [cursor, setCursor] = useState(null);
  const [sel, setSel] = useState([]);
  const [snaps, setSnaps] = useState({ end: true, mid: true, cen: true, grid: true });
  const [ortho, setOrtho] = useState(true);
  const [grid, setGrid] = useState(true);
  const [cmd, setCmd] = useState('');
  const [log, setLog] = useState(['LeonCAD ready. Type a command, or pick a tool.']);
  const [view, setView] = useState({ x: 0, y: 0, k: 1 });
  const svgRef = useRef(null);

  const layer = dwg.layers.find(l => l.id === layerId) || dwg.layers[0];
  const say = m => setLog(l => [m, ...l].slice(0, 60));

  // The world is millimetres; the viewBox is the window onto it.
  const W = 1600, H = 900;
  function toWorld(evt) {
    const svg = svgRef.current; if (!svg) return { x: 0, y: 0 };
    const pt = svg.createSVGPoint(); pt.x = evt.clientX; pt.y = evt.clientY;
    const m = svg.getScreenCTM(); if (!m) return { x: 0, y: 0 };
    const q = pt.matrixTransform(m.inverse());
    return { x: q.x, y: q.y };
  }
  function snapped(raw, from) {
    let p = cadSnapPoint(raw, dwg.entities, Object.assign({}, snaps, { gridSize: 10, tol: 12 / view.k }));
    if (ortho && from && !p.kind) p = Object.assign({}, cadOrtho(from, p), { kind: 'ortho' });
    else if (ortho && from && p.kind === 'grid') p = Object.assign({}, cadOrtho(from, p), { kind: 'ortho' });
    return p;
  }
  function add(e) {
    setDwg(d => Object.assign({}, d, { entities: [...d.entities, e] }));
  }

  function commit(pts) {
    const l = layerId;
    if (tool === 'line' && pts.length >= 2) {
      for (let i = 1; i < pts.length; i++) add(cadEnt('line', l, { x1: pts[i - 1].x, y1: pts[i - 1].y, x2: pts[i].x, y2: pts[i].y }));
      say(`LINE — ${pts.length - 1} segment${pts.length > 2 ? 's' : ''}.`);
    } else if (tool === 'pline' && pts.length >= 2) {
      add(cadEnt('pline', l, { pts: pts.slice() })); say(`PLINE — ${pts.length} points.`);
    } else if (tool === 'rect' && pts.length >= 2) {
      const [a, b] = pts;
      add(cadEnt('rect', l, { x: Math.min(a.x, b.x), y: Math.min(a.y, b.y), w: Math.abs(b.x - a.x), h: Math.abs(b.y - a.y) }));
      say(`RECTANGLE — ${Math.round(Math.abs(b.x - a.x))} × ${Math.round(Math.abs(b.y - a.y))}.`);
    } else if (tool === 'circle' && pts.length >= 2) {
      const [c, e] = pts; const r = Math.hypot(e.x - c.x, e.y - c.y);
      add(cadEnt('circle', l, { cx: c.x, cy: c.y, r })); say(`CIRCLE — radius ${Math.round(r)}.`);
    } else if (tool === 'arc' && pts.length >= 3) {
      const [a, b, m] = pts;
      // Circle through three points — the honest construction, not an eyeballed
      // curve: a bulge that is not on the arc is a part that will not fit.
      const d = 2 * (a.x * (b.y - m.y) + b.x * (m.y - a.y) + m.x * (a.y - b.y));
      if (Math.abs(d) > 1e-6) {
        const ux = ((a.x ** 2 + a.y ** 2) * (b.y - m.y) + (b.x ** 2 + b.y ** 2) * (m.y - a.y) + (m.x ** 2 + m.y ** 2) * (a.y - b.y)) / d;
        const uy = ((a.x ** 2 + a.y ** 2) * (m.x - b.x) + (b.x ** 2 + b.y ** 2) * (a.x - m.x) + (m.x ** 2 + m.y ** 2) * (b.x - a.x)) / d;
        const r = Math.hypot(a.x - ux, a.y - uy);
        const cross = (b.x - a.x) * (m.y - a.y) - (b.y - a.y) * (m.x - a.x);
        add(cadEnt('arc', l, { cx: ux, cy: uy, r, x1: a.x, y1: a.y, x2: b.x, y2: b.y, sweep: cross < 0 }));
        say(`ARC — radius ${Math.round(r)}.`);
      } else say('ARC — those three points are in a straight line.');
    } else if (tool === 'dim' && pts.length >= 2) {
      const [a, b] = pts;
      add(cadEnt('dim', 'l-dims', { x1: a.x, y1: a.y, x2: b.x, y2: b.y }));
      say(`DIMENSION — ${Math.round(Math.hypot(b.x - a.x, b.y - a.y))} mm, measured.`);
    }
    setPending([]);
  }

  function onClick(evt) {
    const raw = toWorld(evt);
    const from = pending.length ? pending[pending.length - 1] : null;
    const p = snapped(raw, from);
    if (tool === 'select' || tool === 'erase') {
      const hit = hitTest(p, dwg.entities);
      if (tool === 'erase' && hit) {
        setDwg(d => Object.assign({}, d, { entities: d.entities.filter(x => x.id !== hit.id) }));
        say('ERASE — 1 object.');
      } else setSel(hit ? (evt.shiftKey ? [...sel, hit.id] : [hit.id]) : []);
      return;
    }
    if (tool === 'text') {
      const t = prompt('Text:');
      if (t) { add(cadEnt('text', 'l-text', { x: p.x, y: p.y, text: t, size: 24 })); say('TEXT placed.'); }
      return;
    }
    const next = [...pending, p];
    const need = { line: 99, pline: 99, rect: 2, circle: 2, arc: 3, dim: 2 }[tool] || 2;
    if (next.length >= need) commit(next); else setPending(next);
  }
  function onMove(evt) {
    const raw = toWorld(evt);
    setCursor(snapped(raw, pending.length ? pending[pending.length - 1] : null));
  }
  function endPoly() { if (pending.length >= 2) commit(pending); else setPending([]); }

  function hitTest(p, ents) {
    const tol = 10 / view.k;
    for (let i = ents.length - 1; i >= 0; i--) {
      const e = ents[i];
      if (e.kind === 'line' || e.kind === 'dim') {
        const d = distToSeg(p, { x: e.x1, y: e.y1 }, { x: e.x2, y: e.y2 });
        if (d < tol) return e;
      } else if (e.kind === 'rect') {
        if (p.x > e.x - tol && p.x < e.x + e.w + tol && p.y > e.y - tol && p.y < e.y + e.h + tol) return e;
      } else if (e.kind === 'circle' || e.kind === 'arc') {
        if (Math.abs(Math.hypot(p.x - e.cx, p.y - e.cy) - e.r) < tol) return e;
      } else if (e.kind === 'pline') {
        for (let j = 1; j < (e.pts || []).length; j++) if (distToSeg(p, e.pts[j - 1], e.pts[j]) < tol) return e;
      } else if (e.kind === 'text') {
        if (Math.abs(p.x - e.x) < 200 && Math.abs(p.y - e.y) < 30) return e;
      }
    }
    return null;
  }
  function distToSeg(p, a, b) {
    const dx = b.x - a.x, dy = b.y - a.y;
    const t = Math.max(0, Math.min(1, ((p.x - a.x) * dx + (p.y - a.y) * dy) / ((dx * dx + dy * dy) || 1)));
    return Math.hypot(p.x - (a.x + t * dx), p.y - (a.y + t * dy));
  }

  // ── The command line ─────────────────────────────────────────────────────
  function runCommand(raw) {
    const s = String(raw || '').trim().toUpperCase();
    if (!s) { if (pending.length) endPoly(); return; }
    const t = CAD_TOOLS.find(x => x.cmd === s || x.key.toUpperCase() === s);
    if (t) { setTool(t.key); setPending([]); say(`${t.label.toUpperCase()} — ${t.hint}`); return; }
    if (s === 'ORTHO' || s === 'F8') { setOrtho(o => { say(`ORTHO ${!o ? 'on' : 'off'}.`); return !o; }); return; }
    if (s === 'GRID' || s === 'F7') { setGrid(g => { say(`GRID ${!g ? 'on' : 'off'}.`); return !g; }); return; }
    if (s === 'U' || s === 'UNDO') {
      setDwg(d => Object.assign({}, d, { entities: d.entities.slice(0, -1) })); say('UNDO — last object removed.'); return;
    }
    if (s === 'ZE' || s === 'ZOOM E' || s === 'ZOOM EXTENTS') { zoomExtents(); return; }
    if (s === 'DXF') { exportDxf(); return; }
    if (s === 'ESC') { setPending([]); setSel([]); say('Cancelled.'); return; }
    say(`Unknown command "${s}". Try L, PL, REC, C, A, DIM, T, M, E, U, ZE, DXF.`);
  }
  function zoomExtents() {
    const es = dwg.entities;
    if (!es.length) { setView({ x: 0, y: 0, k: 1 }); say('ZOOM EXTENTS — nothing drawn yet.'); return; }
    let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
    const put = (x, y) => { x0 = Math.min(x0, x); y0 = Math.min(y0, y); x1 = Math.max(x1, x); y1 = Math.max(y1, y); };
    es.forEach(e => {
      if (e.kind === 'line' || e.kind === 'dim') { put(e.x1, e.y1); put(e.x2, e.y2); }
      else if (e.kind === 'rect') { put(e.x, e.y); put(e.x + e.w, e.y + e.h); }
      else if (e.kind === 'circle' || e.kind === 'arc') { put(e.cx - e.r, e.cy - e.r); put(e.cx + e.r, e.cy + e.r); }
      else if (e.kind === 'pline') (e.pts || []).forEach(p => put(p.x, p.y));
      else if (e.kind === 'text') put(e.x, e.y);
    });
    const pad = 60;
    const k = Math.min(W / Math.max(1, x1 - x0 + pad * 2), H / Math.max(1, y1 - y0 + pad * 2));
    setView({ x: x0 - pad, y: y0 - pad, k });
    say('ZOOM EXTENTS.');
  }
  function exportDxf() {
    const txt = cadToDxf(dwg);
    try {
      const b = new Blob([txt], { type: 'application/dxf' });
      const u = URL.createObjectURL(b); const a = document.createElement('a');
      a.href = u; a.download = `${dwg.name}.dxf`; document.body.appendChild(a); a.click(); a.remove();
      setTimeout(() => URL.revokeObjectURL(u), 4000);
      say(`DXF — ${dwg.entities.length} objects written to ${dwg.name}.dxf.`);
    } catch (e) { say('DXF — the browser would not save the file.'); }
  }

  const vb = `${view.x} ${view.y} ${W / view.k} ${H / view.k}`;
  const ghost = (() => {
    if (!cursor || !pending.length) return null;
    const a = pending[pending.length - 1];
    if (tool === 'rect') return <rect x={Math.min(a.x, cursor.x)} y={Math.min(a.y, cursor.y)}
      width={Math.abs(cursor.x - a.x)} height={Math.abs(cursor.y - a.y)}
      fill="none" stroke="var(--leon-brown)" strokeDasharray="6 4" vectorEffect="non-scaling-stroke" />;
    if (tool === 'circle') return <circle cx={a.x} cy={a.y} r={Math.hypot(cursor.x - a.x, cursor.y - a.y)}
      fill="none" stroke="var(--leon-brown)" strokeDasharray="6 4" vectorEffect="non-scaling-stroke" />;
    return <line x1={a.x} y1={a.y} x2={cursor.x} y2={cursor.y}
      stroke="var(--leon-brown)" strokeDasharray="6 4" vectorEffect="non-scaling-stroke" />;
  })();

  return (
    <div className="space-y-3">
      <div className="flex items-start gap-3 flex-wrap">
        <div className="flex-1 min-w-[240px]">
          <h3 className="font-bold">✏️ LeonCAD</h3>
          <p className="text-sm text-[var(--leon-black)]/60 max-w-3xl">
            Two-dimensional drafting for the details the parametric tools do not cover. Layers, object
            snap, ortho and a command line &mdash; everything in millimetres, like the rest of the Hub.
          </p>
        </div>
        <div className="flex items-center gap-1.5">
          <Select className="!w-44" value={String(at)} onChange={e => { setAt(Number(e.target.value)); setPending([]); setSel([]); }}>
            {dwgs.map((d, i) => <option key={d.id} value={String(i)}>{d.name}</option>)}
          </Select>
          <Button size="sm" variant="outline" onClick={() => {
            setDwgs(l => [...l, cadMakeDrawing({ name: `Drawing ${l.length + 1}` }, ctx.currentUserName)]);
            setAt(dwgs.length); setPending([]); setSel([]);
          }}>+ New</Button>
          <Button size="sm" variant="outline" onClick={exportDxf}>⬇ DXF</Button>
        </div>
      </div>

      {/* THE TOOL PALETTE, with each tool's command beside it — which is how
          anyone actually learns a command line. */}
      <div className="flex flex-wrap gap-1">
        {CAD_TOOLS.map(t => (
          <button key={t.key} onClick={() => { setTool(t.key); setPending([]); say(`${t.label.toUpperCase()} — ${t.hint}`); }}
            title={`${t.label} (${t.cmd}) — ${t.hint}`}
            className={`px-2 py-1 rounded border text-xs flex items-center gap-1.5 ${tool === t.key
              ? 'bg-[var(--leon-brown)] text-white border-[var(--leon-brown)]'
              : 'border-[var(--leon-line)] hover:border-[var(--leon-brown)]'}`}>
            <span aria-hidden="true">{t.icon}</span>{t.label}
            <span className={tool === t.key ? 'opacity-70' : 'text-[var(--leon-black)]/35'}>{t.cmd}</span>
          </button>
        ))}
      </div>

      <div className="grid lg:grid-cols-[210px_1fr] gap-3">
        {/* ── Layers ─────────────────────────────────────────────────────── */}
        <div className="rounded-lg border border-[var(--leon-line)] bg-white overflow-hidden self-start">
          <div className="px-2.5 py-1.5 bg-[var(--leon-cream)] text-[11px] font-bold uppercase tracking-[0.14em] text-[var(--leon-black)]/55">
            Layers
          </div>
          <div className="divide-y divide-[var(--leon-line)]">
            {dwg.layers.map(l => (
              <div key={l.id} className={`flex items-center gap-1.5 px-2 py-1 text-[11px] cursor-pointer ${
                layerId === l.id ? 'bg-[var(--leon-cream)]/70' : ''}`}
                onClick={() => setLayerId(l.id)}>
                <button title={l.on ? 'Hide this layer' : 'Show this layer'}
                  onClick={ev => { ev.stopPropagation();
                    setDwg(d => Object.assign({}, d, { layers: d.layers.map(x => x.id === l.id ? { ...x, on: !x.on } : x) })); }}
                  className="w-4 text-center">{l.on ? '👁' : '–'}</button>
                <span className="w-3 h-3 rounded-sm border border-black/20 shrink-0" style={{ background: l.color }} />
                <span className={`flex-1 truncate ${layerId === l.id ? 'font-bold' : ''}`}>{l.name}</span>
                <span className="text-[9px] text-[var(--leon-black)]/35">{l.lineType.slice(0, 4)}</span>
              </div>
            ))}
          </div>
          <div className="p-2 border-t border-[var(--leon-line)] space-y-1.5">
            <div className="text-[10px] uppercase tracking-wide text-[var(--leon-black)]/40">Object snap</div>
            {CAD_SNAPS.map(s => (
              <label key={s.key} className="flex items-center gap-1.5 text-[11px]">
                <input type="checkbox" checked={!!snaps[s.key]}
                  onChange={e => setSnaps(v => ({ ...v, [s.key]: e.target.checked }))} />
                {s.label}
              </label>
            ))}
            <label className="flex items-center gap-1.5 text-[11px] pt-1 border-t border-[var(--leon-line)]">
              <input type="checkbox" checked={ortho} onChange={e => setOrtho(e.target.checked)} />
              Ortho <span className="text-[var(--leon-black)]/35">F8</span>
            </label>
            <label className="flex items-center gap-1.5 text-[11px]">
              <input type="checkbox" checked={grid} onChange={e => setGrid(e.target.checked)} />
              Grid <span className="text-[var(--leon-black)]/35">F7</span>
            </label>
          </div>
        </div>

        {/* ── The drawing ────────────────────────────────────────────────── */}
        <div className="space-y-2">
          <div className="rounded-lg border border-[var(--leon-line)] bg-white overflow-hidden">
            <svg ref={svgRef} viewBox={vb} width="100%" style={{ height: 520, display: 'block', cursor: 'crosshair' }}
              onClick={onClick} onMouseMove={onMove}
              onContextMenu={e => { e.preventDefault(); endPoly(); }}
              onWheel={e => {
                const f = e.deltaY > 0 ? 1 / 1.15 : 1.15;
                setView(v => ({ x: v.x, y: v.y, k: Math.max(0.05, Math.min(20, v.k * f)) }));
              }}>
              <defs>
                <pattern id="cadGrid" width="100" height="100" patternUnits="userSpaceOnUse">
                  <path d="M100 0 L0 0 0 100" fill="none" stroke="#e6e0d4" strokeWidth="1" vectorEffect="non-scaling-stroke" />
                </pattern>
                <pattern id="cadGridFine" width="10" height="10" patternUnits="userSpaceOnUse">
                  <path d="M10 0 L0 0 0 10" fill="none" stroke="#f2ece0" strokeWidth="0.6" vectorEffect="non-scaling-stroke" />
                </pattern>
              </defs>
              {grid && <>
                <rect x={view.x} y={view.y} width={W / view.k} height={H / view.k} fill="url(#cadGridFine)" />
                <rect x={view.x} y={view.y} width={W / view.k} height={H / view.k} fill="url(#cadGrid)" />
              </>}
              {/* origin crosshair, so a drawing has a datum */}
              <line x1={-1e5} y1={0} x2={1e5} y2={0} stroke="#d8cdb8" strokeWidth="1" vectorEffect="non-scaling-stroke" />
              <line x1={0} y1={-1e5} x2={0} y2={1e5} stroke="#d8cdb8" strokeWidth="1" vectorEffect="non-scaling-stroke" />
              {dwg.entities.map(e => (
                <CadEntity key={e.id} e={e} selected={sel.indexOf(e.id) >= 0}
                  layer={dwg.layers.find(l => l.id === e.layerId) || dwg.layers[0]} />
              ))}
              {ghost}
              {pending.map((p, i) => (
                <circle key={i} cx={p.x} cy={p.y} r={4 / view.k} fill="var(--leon-brown)" />
              ))}
              {cursor && cursor.kind && (
                <g>
                  <rect x={cursor.x - 6 / view.k} y={cursor.y - 6 / view.k} width={12 / view.k} height={12 / view.k}
                    fill="none" stroke="var(--leon-brown)" strokeWidth="1.5" vectorEffect="non-scaling-stroke" />
                  <text x={cursor.x + 10 / view.k} y={cursor.y - 8 / view.k} fontSize={14 / view.k}
                    fill="var(--leon-brown)">{cursor.kind}</text>
                </g>
              )}
            </svg>
          </div>

          {/* ── The command line and its history ─────────────────────────── */}
          <div className="rounded-lg border border-[var(--leon-line)] bg-[#1b1b1b] text-[#e8e2d6] font-mono text-[11px] overflow-hidden">
            <div className="max-h-24 overflow-y-auto px-2.5 py-1.5 space-y-0.5">
              {log.map((l, i) => <div key={i} className={i ? 'opacity-55' : ''}>{l}</div>)}
            </div>
            <div className="flex items-center gap-2 border-t border-white/10 px-2.5 py-1.5">
              <span className="opacity-60">Command:</span>
              <input value={cmd} onChange={e => setCmd(e.target.value)}
                onKeyDown={e => {
                  if (e.key === 'Enter') { runCommand(cmd); setCmd(''); }
                  else if (e.key === 'Escape') { setPending([]); setSel([]); setCmd(''); say('Cancelled.'); }
                }}
                placeholder="L, REC, C, A, DIM, U, ZE, DXF…"
                className="flex-1 bg-transparent outline-none text-[#e8e2d6] placeholder:text-white/25" />
              <span className="opacity-40">
                {Math.round(cursor ? cursor.x : 0)}, {Math.round(cursor ? cursor.y : 0)} mm
              </span>
            </div>
          </div>

          <div className="flex items-center gap-3 text-[11px] text-[var(--leon-black)]/45 flex-wrap">
            <span>{dwg.entities.length} objects</span>
            <span>Layer <b className="text-[var(--leon-black)]/70">{layer ? layer.name : '0'}</b></span>
            <span>{ortho ? 'Ortho on' : 'Ortho off'}</span>
            <button onClick={zoomExtents} className="font-semibold text-[var(--leon-brown)]">Zoom extents</button>
            <span className="ml-auto">Right-click or Enter ends a line. Scroll to zoom.</span>
          </div>
          <p className="text-[11px] text-[var(--leon-black)]/45">
            <b>LeonCAD does not open DWG.</b> That format is undocumented and a browser cannot read one
            honestly. It keeps its own drawings and exports <b>DXF</b> &mdash; which is documented, is what
            AutoCAD itself uses for interchange, and is what LEON Windows already imports.
          </p>
        </div>
      </div>
    </div>
  );
}
