// ─────────────────────────────────────────────────────────────────────────────
// Workshop bench — cork board surface + drag/snap behavior
//
// CorkBoard renders the surface (texture, frame, hairline grid).
// useBench hook owns card layout state + drag/drop + soft snap.
// ─────────────────────────────────────────────────────────────────────────────

const { useState, useEffect, useRef, useCallback, useMemo } = React;

// ── Cork board surface ──────────────────────────────────────────────────────
// SVG-based cork texture: a warm tan ground sprinkled with hundreds of tiny
// flecks at varied opacity & rotation. Cheap, deterministic, looks real.
function CorkBoard({ children, height = 1100, refEl }) {
  const flecks = useMemo(() => {
    // deterministic PRNG so flecks don't reshuffle on re-render
    let s = 7;
    const rng = () => {
      s = (s * 9301 + 49297) % 233280;
      return s / 233280;
    };
    const items = [];
    const N = 1400;
    for (let i = 0; i < N; i++) {
      const x = rng() * 100;     // %
      const y = rng() * 100;
      const r = 0.4 + rng() * 1.6;
      const rot = rng() * 360;
      const tone = rng();
      // 4 cork tones — light tan, mid, dark, occasional umber
      const fill =
        tone < 0.40 ? 'rgba(120, 78, 38, 0.42)' :
        tone < 0.75 ? 'rgba(86, 54, 22, 0.36)'  :
        tone < 0.92 ? 'rgba(58, 36, 14, 0.55)'  :
                      'rgba(168, 118, 60, 0.32)';
      const op = 0.45 + rng() * 0.55;
      items.push({ x, y, r, rot, fill, op });
    }
    return items;
  }, []);

  return (
    <div
      ref={refEl}
      style={{
        position: 'relative',
        height,
        // base cork color — warm tan, slightly desaturated
        background:
          'radial-gradient(ellipse at 30% 20%, #C49363 0%, #B07F4D 35%, #9A6A3A 75%, #7E5226 100%)',
        boxShadow:
          // dark frame inside (vignette) + outer shadow for depth
          'inset 0 0 80px rgba(40, 22, 6, 0.55), ' +
          'inset 0 2px 6px rgba(255, 220, 180, 0.18), ' +
          '0 30px 60px -25px rgba(20, 14, 6, 0.45), ' +
          '0 8px 18px -8px rgba(20, 14, 6, 0.30)',
        overflow: 'hidden',
        // wood-look outer frame via border
        border: '14px solid #3A2410',
        borderImage:
          'linear-gradient(135deg, #5A3A1C 0%, #3A2410 35%, #2A180A 65%, #4A2E14 100%) 1',
        outline: '1px solid rgba(0,0,0,0.4)',
        outlineOffset: '-1px',
      }}
    >
      {/* cork flecks */}
      <svg
        aria-hidden
        width="100%"
        height="100%"
        viewBox="0 0 100 100"
        preserveAspectRatio="none"
        style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}
      >
        {flecks.map((f, i) => (
          <ellipse
            key={i}
            cx={f.x}
            cy={f.y}
            rx={f.r * 0.06}
            ry={f.r * 0.04}
            fill={f.fill}
            opacity={f.op}
            transform={`rotate(${f.rot} ${f.x} ${f.y})`}
          />
        ))}
      </svg>

      {/* subtle horizontal fiber grain */}
      <div
        aria-hidden
        style={{
          position: 'absolute', inset: 0, pointerEvents: 'none',
          background:
            'repeating-linear-gradient(2deg, ' +
              'transparent 0 3px, ' +
              'rgba(60, 32, 10, 0.04) 3px 4px, ' +
              'transparent 4px 7px)',
        }}
      />

      {/* warm light from upper-left */}
      <div
        aria-hidden
        style={{
          position: 'absolute', inset: 0, pointerEvents: 'none',
          background:
            'radial-gradient(ellipse 60% 50% at 25% 15%, rgba(255, 230, 180, 0.18), transparent 60%)',
        }}
      />

      {children}
    </div>
  );
}

// ── Push pin ────────────────────────────────────────────────────────────────
// Sits at top-center of a card. Drawn with SVG so it has highlights & a cast
// shadow on the card paper below. Color varies by id for variety.
const PIN_COLORS = [
  ['#C8412A', '#8B2A18', '#F4A89B'], // red
  ['#1B4FA0', '#0E2F65', '#7BA3D8'], // blue
  ['#2A5F3F', '#163925', '#7FB897'], // green
  ['#D4A11C', '#8C6710', '#F1D575'], // yellow
  ['#6B3FA0', '#3D2363', '#B89AD8'], // purple
  ['#3A2410', '#1F1208', '#8B6B4F'], // brown
];
function PushPin({ idx = 0, size = 22 }) {
  const [base, dark, hi] = PIN_COLORS[idx % PIN_COLORS.length];
  const r = size / 2;
  return (
    <svg
      width={size}
      height={size}
      viewBox="0 0 24 24"
      style={{
        position: 'absolute',
        top: -size * 0.55,
        left: '50%',
        transform: 'translateX(-50%)',
        filter: 'drop-shadow(0 4px 5px rgba(20, 12, 4, 0.55))',
        pointerEvents: 'none',
      }}
      aria-hidden
    >
      {/* pin head */}
      <defs>
        <radialGradient id={`pin-${idx}`} cx="35%" cy="30%" r="70%">
          <stop offset="0%" stopColor={hi} />
          <stop offset="35%" stopColor={base} />
          <stop offset="100%" stopColor={dark} />
        </radialGradient>
      </defs>
      <circle cx="12" cy="12" r="9" fill={`url(#pin-${idx})`} />
      {/* specular highlight */}
      <ellipse cx="9" cy="9" rx="3" ry="2" fill="rgba(255,255,255,0.55)" />
      {/* rim shadow */}
      <circle cx="12" cy="12" r="9" fill="none" stroke="rgba(0,0,0,0.25)" strokeWidth="0.5" />
    </svg>
  );
}

// ── Drag / snap state hook ──────────────────────────────────────────────────
// Soft snap to a 24px grid. Drag is captured via pointer events; on drop we
// snap. Click vs drag is disambiguated by movement threshold.
const SNAP = 24;
function snapTo(v) { return Math.round(v / SNAP) * SNAP; }

function useBench({ products, stageRef, dragLayerRef, cardW, cardH, cols = 3, padX = 56, initialMode = null }) {
  const [layouts, setLayouts] = useState(null);
  const [size, setSize] = useState({ w: 1200, h: 1100 });
  const zRef = useRef(10);
  const prevColsRef = useRef(cols);

  // measure stage
  useEffect(() => {
    if (!stageRef.current) return;
    const ro = new ResizeObserver((entries) => {
      for (const e of entries) {
        const cr = e.contentRect;
        setSize({ w: cr.width, h: cr.height });
      }
    });
    ro.observe(stageRef.current);
    return () => ro.disconnect();
  }, [stageRef]);

  // when breakpoint (cols) or stage width changes substantially, force a fresh layout
  const prevWRef = useRef(0);
  useEffect(() => {
    if (size.w < 100) return;
    const colsChanged = prevColsRef.current !== cols;
    const widthChanged = Math.abs(prevWRef.current - size.w) > 40;
    if (colsChanged || widthChanged) {
      prevColsRef.current = cols;
      prevWRef.current = size.w;
      setLayouts(null);
    }
  }, [cols, size.w]);

  // initial layout — loose grid with subtle randomized rotations (or stack)
  useEffect(() => {
    if (layouts || size.w < 100) return;
    const padY = 60;
    let s = 11;
    const rng = () => { s = (s * 9301 + 49297) % 233280; return s / 233280; };
    let next;
    if (initialMode === 'stack') {
      const cx = (size.w - cardW) / 2;
      const cy = (size.h - cardH) / 2;
      next = products.map((p, i) => ({
        id: p.id,
        x: snapTo(cx + (rng() - 0.5) * 80),
        y: snapTo(cy + (rng() - 0.5) * 50),
        rot: (rng() - 0.5) * 14,
        z: products.length - i, // Agent Handover (first product) on top
      }));
    } else {
      const rows = Math.ceil(products.length / cols);
      const slotW = (size.w - padX * 2) / cols;
      const slotH = (size.h - padY * 2) / rows;
      const compact = cols === 1;
      next = products.map((p, i) => {
        const c = i % cols, r = Math.floor(i / cols);
        const cx = padX + slotW * c + (slotW - cardW) / 2;
        const cy = padY + slotH * r + (slotH - cardH) / 2;
        const jx = (rng() - 0.5) * (compact ? 0 : 18);
        const jy = (rng() - 0.5) * (compact ? 0 : 14);
        const rot = (rng() - 0.5) * (compact ? 1.4 : 4.5);
        return {
          id: p.id,
          x: snapTo(cx + jx),
          y: snapTo(cy + jy),
          rot,
          z: i + 1,
        };
      });
    }
    zRef.current = products.length + 1;
    setLayouts(next);
  }, [size, layouts, products, cardW, cardH, cols, padX, initialMode]);

  const updateCard = useCallback((id, patch) => {
    setLayouts((cur) => cur ? cur.map((l) => l.id === id ? { ...l, ...patch } : l) : cur);
  }, []);

  const bringToTop = useCallback((id) => {
    zRef.current += 1;
    const z = zRef.current;
    setLayouts((cur) => cur ? cur.map((l) => l.id === id ? { ...l, z } : l) : cur);
  }, []);

  // commit-on-drop: snap x,y to grid, settle a small rotation drift
  const commitDrop = useCallback((id) => {
    setLayouts((cur) => cur ? cur.map((l) => {
      if (l.id !== id) return l;
      return { ...l, x: snapTo(l.x), y: snapTo(l.y) };
    }) : cur);
  }, []);

  // arrangement helpers
  const arrange = useCallback((mode) => {
    if (!layouts) return;
    const rows = Math.ceil(products.length / cols);
    const padY = 60;
    const slotW = (size.w - padX * 2) / cols;
    const slotH = (size.h - padY * 2) / rows;
    let s = mode === 'tidy' ? 23 : (mode === 'stack' ? 41 : Date.now() % 10000);
    const rng = () => { s = (s * 9301 + 49297) % 233280; return s / 233280; };
    if (mode === 'stack') zRef.current = products.length + 1;
    setLayouts((cur) => {
      if (!cur) return cur; // bail if state was reset between dispatch and apply
      return cur.map((l, i) => {
      if (mode === 'tidy') {
        const c = i % cols, r = Math.floor(i / cols);
        return {
          ...l,
          x: snapTo(padX + slotW * c + (slotW - cardW) / 2),
          y: snapTo(padY + slotH * r + (slotH - cardH) / 2),
          rot: (rng() - 0.5) * 1.5,
        };
      }
      if (mode === 'stack') {
        const cx = (size.w - cardW) / 2;
        const cy = (size.h - cardH) / 2;
        // Reverse z so the first product (Agent Handover) sits on top of the pile
        const stackedZ = products.length - i;
        return {
          ...l,
          x: snapTo(cx + (rng() - 0.5) * 80),
          y: snapTo(cy + (rng() - 0.5) * 50),
          rot: (rng() - 0.5) * 14,
          z: stackedZ,
        };
      }
      // scatter
      return {
        ...l,
        x: snapTo(padX + rng() * (size.w - padX * 2 - cardW)),
        y: snapTo(padY + rng() * (size.h - padY * 2 - cardH)),
        rot: (rng() - 0.5) * 10,
      };
    });
    });
  }, [layouts, products.length, size, cardW, cardH, cols, padX]);

  return { layouts, size, updateCard, bringToTop, commitDrop, arrange };
}

// expose to global scope so workshop-app.jsx can use them
Object.assign(window, { CorkBoard, PushPin, useBench, snapTo, SNAP, PIN_COLORS });
