// Scene canvas — renders the booth footprint and placed items in the active
// view (iso / front / top). Items belonging to the same group (a stand kit)
// move together as one unit.

const IsoCanvas = ({ space, items, view = "iso", onMoveGroup, onSelect, selectedId, overCap }) => {
  const wrapRef = React.useRef(null);
  const [wrap, setWrap] = React.useState({ w: 800, h: 600 });
  React.useEffect(() => {
    const el = wrapRef.current;
    if (!el) return;
    const r = () => setWrap({ w: el.clientWidth, h: el.clientHeight });
    r();
    const obs = new ResizeObserver(r);
    obs.observe(el);
    return () => obs.disconnect();
  }, []);

  const proj = window.makeProjector(view);
  const BOOTH_H = 10; // reference height so every view frames the full volume

  // Floor + volume corners (for centering the scene)
  const floorCorners = [[0,0],[space.w,0],[space.w,space.d],[0,space.d]].map(([x,y]) => proj(x,y,0));
  const volCorners = [];
  [[0,0],[space.w,0],[space.w,space.d],[0,space.d]].forEach(([x,y]) => {
    volCorners.push(proj(x,y,0));
    volCorners.push(proj(x,y,BOOTH_H));
  });
  const exCorners = view === "front" ? volCorners : floorCorners;
  const xs = exCorners.map(c => c[0]), ys = exCorners.map(c => c[1]);
  const minX = Math.min(...xs), maxX = Math.max(...xs);
  const minY = Math.min(...ys), maxY = Math.max(...ys);
  const bw = maxX - minX, bh = maxY - minY;

  const tyNudge = view === "iso" ? -20 : (view === "front" ? 40 : 0);
  const tx = wrap.w / 2 - (minX + bw / 2);
  const ty = wrap.h / 2 - (minY + bh / 2) + tyNudge;

  const [drag, setDrag] = React.useState(null);

  const onDownItem = (e, item) => {
    e.stopPropagation();
    onSelect(item.gid);
    const startPositions = items
      .filter(i => i.gid === item.gid)
      .map(i => ({ uid: i.uid, x: i.x, y: i.y, w: i.w, d: i.d }));
    setDrag({ gid: item.gid, startX: e.clientX, startY: e.clientY, startPositions });
  };

  React.useEffect(() => {
    if (!drag) return;
    const move = (e) => {
      const dxPx = e.clientX - drag.startX;
      const dyPx = e.clientY - drag.startY;
      let [pdx, pdy] = window.groundInverse(view, dxPx, dyPx);

      // Clamp the whole group's bounding box inside the booth
      const g = drag.startPositions;
      const gMinX = Math.min(...g.map(p => p.x));
      const gMinY = Math.min(...g.map(p => p.y));
      const gMaxX = Math.max(...g.map(p => p.x + p.w));
      const gMaxY = Math.max(...g.map(p => p.y + p.d));
      pdx = Math.max(-gMinX, Math.min(space.w - gMaxX, pdx));
      pdy = Math.max(-gMinY, Math.min(space.d - gMaxY, pdy));

      onMoveGroup(g.map(p => ({ uid: p.uid, x: p.x + pdx, y: p.y + pdy })));
    };
    const up = () => setDrag(null);
    window.addEventListener("mousemove", move);
    window.addEventListener("mouseup", up);
    return () => {
      window.removeEventListener("mousemove", move);
      window.removeEventListener("mouseup", up);
    };
  }, [drag, items, space, view, onMoveGroup]);

  // Depth sort: front view sorts by depth (y), others by (x+y)
  const sorted = [...items].sort((a, b) =>
    view === "front" ? (a.y - b.y) : ((a.x + a.y) - (b.x + b.y))
  );

  const floorPts = floorCorners.map(c => c.join(",")).join(" ");

  return (
    <div ref={wrapRef} className="iso-wrap">
      <div className={`iso-chip ${overCap ? "iso-chip--warn" : ""}`}>
        {space.w}′ × {space.d}′ · {space.mode === "outdoor" ? "Outdoor" : "Indoor"} · {items.length} part{items.length === 1 ? "" : "s"}
      </div>

      <svg className="iso-svg" width={wrap.w} height={wrap.h}>
        <g transform={`translate(${tx} ${ty})`}>
          {/* Booth floor */}
          <polygon points={floorPts} fill={space.mode === "outdoor" ? "#cfd6c8" : "#f3efe5"} stroke="#1a1918" strokeWidth="1.2" />
          {/* Floor grid — drawn as projected lines from the (0,0) corner so the
              squares always align to the booth corner/edges in every view. */}
          {view !== "front" && (
            <g stroke="rgba(0,0,0,0.06)" strokeWidth="1">
              {Array.from({ length: Math.floor(space.w) + 1 }, (_, i) => {
                const a = proj(i, 0, 0), b = proj(i, space.d, 0);
                return <line key={`gx${i}`} x1={a[0]} y1={a[1]} x2={b[0]} y2={b[1]} />;
              })}
              {Array.from({ length: Math.floor(space.d) + 1 }, (_, i) => {
                const a = proj(0, i, 0), b = proj(space.w, i, 0);
                return <line key={`gy${i}`} x1={a[0]} y1={a[1]} x2={b[0]} y2={b[1]} />;
              })}
            </g>
          )}

          {/* Dim labels */}
          {(() => {
            const [ax, ay] = proj(space.w/2, 0, 0);
            const [bx, by] = proj(0, space.d/2, 0);
            return (
              <>
                <text x={ax} y={ay - 10} textAnchor="middle" fontFamily="'JetBrains Mono', monospace" fontSize="10" letterSpacing="2" fill="#6a6761">{space.w}′</text>
                {view !== "front" && (
                  <text x={bx - 10} y={by + 4} textAnchor="end" fontFamily="'JetBrains Mono', monospace" fontSize="10" letterSpacing="2" fill="#6a6761">{space.d}′</text>
                )}
              </>
            );
          })()}

          {sorted.map((it) => (
            <IsoBox key={it.uid} it={it} proj={proj} view={view} selected={selectedId === it.gid} onDown={onDownItem} />
          ))}
        </g>
      </svg>

      {overCap && (
        <div style={{position:"absolute", bottom: 20, left: "50%", transform: "translateX(-50%)", background: "color-mix(in oklch, var(--accent) 18%, var(--bg))", border: "1px solid var(--accent)", padding: "10px 16px", fontFamily: "var(--mono)", fontSize: 11, letterSpacing: ".14em", textTransform: "uppercase"}}>
          ⚠ Items exceed booth footprint — resize space or remove items
        </div>
      )}
    </div>
  );
};

const IsoBox = ({ it, proj, view, selected, onDown }) => {
  const { x, y, w, d, h, color } = it;
  const c000 = proj(x,     y,     0);
  const c100 = proj(x+w,   y,     0);
  const c010 = proj(x,     y+d,   0);
  const c110 = proj(x+w,   y+d,   0);
  const c001 = proj(x,     y,     h);
  const c101 = proj(x+w,   y,     h);
  const c011 = proj(x,     y+d,   h);
  const c111 = proj(x+w,   y+d,   h);

  const top = [c001, c101, c111, c011].map(p => p.join(",")).join(" ");
  const right = [c101, c111, c110, c100].map(p => p.join(",")).join(" ");
  const front = [c011, c111, c110, c010].map(p => p.join(",")).join(" ");

  const darken = (c, amt) => {
    const m = c.match(/#([0-9a-f]{6})/i);
    if (!m) return c;
    const n = parseInt(m[1], 16);
    let r = (n >> 16) & 255, g = (n >> 8) & 255, b = n & 255;
    r = Math.max(0, Math.min(255, Math.round(r * amt)));
    g = Math.max(0, Math.min(255, Math.round(g * amt)));
    b = Math.max(0, Math.min(255, Math.round(b * amt)));
    return `rgb(${r},${g},${b})`;
  };

  // In the front elevation the only meaningful face is the front; show it at
  // full colour so elevations don't read muddy.
  const frontFill = view === "front" ? color : darken(color, 0.58);
  // The face drawn last and selected outline differ by view.
  const capPts = view === "front" ? front : top;

  return (
    <g className={`iso-fix ${selected ? "is-sel" : ""}`} onMouseDown={(e) => onDown(e, it)}>
      <polygon points={right} fill={darken(color, 0.72)} stroke="#1a1918" strokeWidth="0.8" />
      <polygon points={front} fill={frontFill}           stroke="#1a1918" strokeWidth="0.8" />
      <polygon points={top}   fill={color}               stroke="#1a1918" strokeWidth="0.8" />
      {selected && (
        <polygon points={capPts} fill="none" stroke="#b94a2a" strokeWidth="2" />
      )}
    </g>
  );
};

window.IsoCanvas = IsoCanvas;
