'use client';

import { useRef, useState, useEffect, useLayoutEffect, useCallback } from 'react';
import { Stage, Layer, Text, TextPath, Image as KonvaImage, Transformer, Rect, Group } from 'react-konva';
import type Konva from 'konva';
import { v4 as uuid } from 'uuid';
import ProductMockup from './ProductMockup';
import Price from './Price';
import LoginPromptModal from './LoginPromptModal';
import { useCart } from '@/lib/cartStore';
import { getEffectivePrice } from '@/lib/pricing';
import { checkCustomerAuth } from '@/app/actions';
import type { DesignElement, PrintArea, ProductDTO } from '@/lib/types';

const DISPLAY = 560; // css px size the mockup + stage are rendered at
const CAPTURE_SCALE = 2; // matches pixelRatio used for exports, for crisp downloads

function loadImage(src: string): Promise<HTMLImageElement> {
  return new Promise((resolve, reject) => {
    const img = new window.Image();
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = src;
  });
}

// Draws `img` into the canvas region like CSS `object-fit: cover` would.
function drawCover(ctx: CanvasRenderingContext2D, img: HTMLImageElement, dw: number, dh: number) {
  const imgRatio = img.width / img.height;
  const boxRatio = dw / dh;
  let sx: number, sy: number, sw: number, sh: number;
  if (imgRatio > boxRatio) {
    sh = img.height;
    sw = sh * boxRatio;
    sx = (img.width - sw) / 2;
    sy = 0;
  } else {
    sw = img.width;
    sh = sw / boxRatio;
    sx = 0;
    sy = (img.height - sh) / 2;
  }
  ctx.drawImage(img, sx, sy, sw, sh, 0, 0, dw, dh);
}

// Builds a reference image showing the design placed on the actual product photo
// (garment + artwork composited together) — separate from the clean, print-ready,
// transparent-background export. Returns null if there's no real photo to composite
// onto (illustration-only products skip this; there's nothing photographic to show).
async function composePlacementImage(
  photoUrl: string,
  recolor: { tint: boolean; color: string } | null,
  stage: Konva.Stage,
  box: { left: number; top: number; w: number; h: number },
): Promise<string> {
  const canvas = document.createElement('canvas');
  canvas.width = DISPLAY * CAPTURE_SCALE;
  canvas.height = DISPLAY * CAPTURE_SCALE;
  const ctx = canvas.getContext('2d');
  if (!ctx) return '';

  const photoImg = await loadImage(photoUrl);

  if (recolor?.tint) {
    ctx.filter = 'grayscale(1) brightness(2.1) contrast(1.15)';
    drawCover(ctx, photoImg, canvas.width, canvas.height);
    ctx.filter = 'none';
    ctx.globalCompositeOperation = 'multiply';
    ctx.fillStyle = recolor.color;
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.globalCompositeOperation = 'source-over';
  } else {
    drawCover(ctx, photoImg, canvas.width, canvas.height);
  }

  const designCanvas = stage.toCanvas({ pixelRatio: CAPTURE_SCALE });
  ctx.drawImage(
    designCanvas,
    box.left * CAPTURE_SCALE,
    box.top * CAPTURE_SCALE,
    box.w * CAPTURE_SCALE,
    box.h * CAPTURE_SCALE,
  );

  return canvas.toDataURL('image/png');
}

const FONTS = [
  'Inter',
  'Fraunces',
  'Caveat',
  'Playfair Display',
  'Oswald',
  'Bebas Neue',
  'Pacifico',
  'Permanent Marker',
  'JetBrains Mono',
  'Georgia',
  'Arial',
];

function UploadedImage({
  el,
  onSelect,
  onChange,
  shapeRef,
}: {
  el: Extract<DesignElement, { type: 'image' }>;
  onSelect: () => void;
  onChange: (attrs: Partial<DesignElement>) => void;
  shapeRef: (node: Konva.Image | null) => void;
}) {
  const [img, setImg] = useState<HTMLImageElement | null>(null);

  useEffect(() => {
    const image = new window.Image();
    image.src = el.src;
    image.onload = () => setImg(image);
  }, [el.src]);

  if (!img) return null;

  return (
    <KonvaImage
      ref={shapeRef}
      image={img}
      x={el.x}
      y={el.y}
      width={el.width}
      height={el.height}
      rotation={el.rotation}
      draggable
      listening={true}
      onClick={onSelect}
      onTap={onSelect}
      onDragEnd={(e) => onChange({ x: e.target.x(), y: e.target.y() })}
      onTransformEnd={(e) => {
        const node = e.target;
        onChange({
          x: node.x(),
          y: node.y(),
          rotation: node.rotation(),
          width: Math.max(10, node.width() * node.scaleX()),
          height: Math.max(10, node.height() * node.scaleY()),
        });
        node.scaleX(1);
        node.scaleY(1);
      }}
    />
  );
}

// One print surface (photo + the draggable design layer on top). Front and back
// each get their own instance, both always mounted (just shown/hidden with CSS)
// so their Konva stages stay exportable even when you're looking at the other side.
// Force recompile
function PrintSurface({
  photo,
  printArea,
  elements,
  selectedId,
  setSelectedId,
  updateElement,
  nodeRefs,
  stageRef,
  transformerRef,
  visible,
  caption,
  onNodeReady,
  scale,
  product,
}: {
  photo: React.ReactNode;
  printArea: PrintArea;
  elements: DesignElement[];
  selectedId: string | null;
  setSelectedId: (id: string | null) => void;
  updateElement: (id: string, attrs: Partial<DesignElement>) => void;
  nodeRefs: React.MutableRefObject<Map<string, Konva.Node>>;
  stageRef: React.RefObject<Konva.Stage>;
  transformerRef: React.RefObject<Konva.Transformer>;
  visible: boolean;
  caption: string;
  onNodeReady: () => void;
  scale: number;
  product: ProductDTO;
}) {
  const stageW = printArea.wPct * DISPLAY;
  const stageH = printArea.hPct * DISPLAY;
  const stageLeft = printArea.xPct * DISPLAY;
  const stageTop = printArea.yPct * DISPLAY;

  return (
    <div className={visible ? '' : 'hidden'}>
      {/* Konva's Stage stays a fixed 560x560 internally so element coordinates,
          print-area math, and export resolution never change — only the visual
          box shrinks via CSS transform to fit narrow viewports. */}
      <div style={{ width: DISPLAY * scale, height: DISPLAY * scale }}>
      <div
        className="relative border border-line bg-surface"
        style={{ width: DISPLAY, height: DISPLAY, transform: `scale(${scale})`, transformOrigin: 'top left' }}
      >
        <div className="pointer-events-none absolute inset-0" style={{ width: DISPLAY, height: DISPLAY }}>
          {photo}
        </div>

        {/* Horizontal Ruler */}
        {product.referenceWidthCm && product.referenceWidthCm > 0 && (
        <div
          className="absolute pointer-events-none bg-paper border-b border-line text-xs font-mono"
          style={{
            left: 0,
            top: -20,
            width: DISPLAY,
            height: 18,
            display: 'flex',
            alignItems: 'flex-end',
            paddingBottom: '2px',
          }}
        >
          {(() => {
            const marks = [];
            const pxPerCm = DISPLAY / product.referenceWidthCm;

            for (let cm = 0; cm <= Math.ceil(product.referenceWidthCm); cm += 2) {
              const px = cm * pxPerCm;
              if (px > DISPLAY) break;
              marks.push(
                <div
                  key={`h-${cm}`}
                  style={{
                    position: 'absolute',
                    left: `${px}px`,
                    fontSize: '9px',
                    color: '#888',
                    transform: 'translateX(-50%)',
                    whiteSpace: 'nowrap',
                  }}
                >
                  {cm}
                </div>
              );
            }
            return marks;
          })()}
        </div>
        )}

        {/* Vertical Ruler */}
        {product.referenceHeightCm && product.referenceHeightCm > 0 && (
        <div
          className="absolute pointer-events-none bg-paper border-r border-line text-xs font-mono"
          style={{
            left: -28,
            top: 0,
            width: 26,
            height: DISPLAY,
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'flex-end',
            paddingRight: '4px',
          }}
        >
          {(() => {
            const marks = [];
            const pxPerCm = DISPLAY / product.referenceHeightCm;

            for (let cm = 0; cm <= Math.ceil(product.referenceHeightCm); cm += 2) {
              const px = cm * pxPerCm;
              if (px > DISPLAY) break;
              marks.push(
                <div
                  key={`v-${cm}`}
                  style={{
                    position: 'absolute',
                    top: `${px}px`,
                    fontSize: '9px',
                    color: '#888',
                    transform: 'translateY(-50%)',
                    whiteSpace: 'nowrap',
                  }}
                >
                  {cm}
                </div>
              );
            }
            return marks;
          })()}
        </div>
        )}

        <div className="absolute" style={{ left: stageLeft, top: stageTop, width: stageW, height: stageH }}>
          <Stage
            ref={stageRef}
            width={stageW}
            height={stageH}
            onMouseDown={(e) => {
              if (e.target === e.target.getStage()) setSelectedId(null);
            }}
          >
            <Layer>
              <Rect
                name="printGuide"
                x={0}
                y={0}
                width={stageW}
                height={stageH}
                stroke="#E5227E"
                dash={[10, 6]}
                strokeWidth={3}
                shadowColor="#E5227E"
                shadowBlur={12}
                shadowOpacity={0.5}
                listening={false}
              />
              <Rect
                name="printGuide"
                x={0}
                y={0}
                width={stageW}
                height={stageH}
                fill="#E5227E"
                opacity={0.07}
                listening={false}
              />
              {elements.map((el) =>
                el.type === 'text' ? (
                  el.curvedPath ? (
                    // Curved text - TextPath with dragging via offset
                    (() => {
                      const offsetX = el.x - 280;
                      const offsetY = el.y - 280;
                      const pathData = generateCurvePath(el.curvedPath.type, el.curvedPath.radius, el.curvedPath.reverse, offsetX, offsetY);
                      console.log(`🔄 Rendering curved text ${el.text}: position (${el.x}, ${el.y}), offset (${offsetX}, ${offsetY})`);
                      return (
                        <TextPath
                          key={el.id}
                          ref={(node) => {
                            if (node) {
                              nodeRefs.current.set(el.id, node);
                              console.log(`✓ TextPath node ready: ${el.text}`);
                            }
                          }}
                          data={pathData}
                          text={el.text}
                          fontFamily={el.fontFamily}
                          fontSize={el.fontSize}
                          fill={el.fill}
                          draggable
                          listening={true}
                          onClick={() => setSelectedId(el.id)}
                          onTap={() => setSelectedId(el.id)}
                          onDragEnd={(e) => {
                            const node = e.target as any;
                            const dx = node.x();
                            const dy = node.y();
                            if (dx !== 0 || dy !== 0) {
                              updateElement(el.id, { x: el.x + dx, y: el.y + dy });
                              node.x(0);
                              node.y(0);
                            }
                          }}
                        />
                      );
                    })()
                  )
                  : (
                    // Regular straight text
                    <Text
                      key={el.id}
                      ref={(node) => {
                        if (node) nodeRefs.current.set(el.id, node);
                      }}
                      x={el.x}
                      y={el.y}
                      text={el.text}
                      fontFamily={el.fontFamily}
                      fontSize={el.fontSize}
                      fill={el.fill}
                      rotation={el.rotation}
                      draggable
                      listening={true}
                      onClick={() => setSelectedId(el.id)}
                      onTap={() => setSelectedId(el.id)}
                      onDragEnd={(e) => updateElement(el.id, { x: e.target.x(), y: e.target.y() })}
                      onTransformEnd={(e) => {
                        const node = e.target;
                        updateElement(el.id, {
                          x: node.x(),
                          y: node.y(),
                          rotation: node.rotation(),
                          fontSize: Math.max(8, el.fontSize * node.scaleX()),
                        });
                        node.scaleX(1);
                        node.scaleY(1);
                      }}
                    />
                  )
                ) : (
                  <UploadedImage
                    key={el.id}
                    el={el}
                    onSelect={() => setSelectedId(el.id)}
                    onChange={(attrs) => updateElement(el.id, attrs)}
                    shapeRef={(node) => {
                      if (node && nodeRefs.current.get(el.id) !== node) {
                        nodeRefs.current.set(el.id, node);
                        onNodeReady();
                      }
                    }}
                  />
                ),
              )}
              <Transformer
                ref={transformerRef}
                rotateEnabled
                flipEnabled={false}
                rotateAnchorOffset={30}
                anchorCornerRadius={4}
                anchorSize={8}
                borderStroke="#17181C"
                borderStrokeWidth={2}
                anchorStroke="#17181C"
                anchorFill="#FFF"
                boundBoxFunc={(oldBox, newBox) => (newBox.width < 8 || newBox.height < 8 ? oldBox : newBox)}
              />
            </Layer>
          </Stage>
        </div>
      </div>
      </div>
      <p className="tag-label mt-3">{caption}</p>
    </div>
  );
}

// Generate SVG path for curved text based on type and radius
function generateCurvePath(type: string, radius: number, reverse: boolean = false, offsetX: number = 0, offsetY: number = 0): string {
  const cx = 280 + offsetX; // center x (middle of 560px canvas + offset)
  const cy = 280 + offsetY; // center y + offset
  const r = radius;

  let path = '';

  switch (type) {
    case 'circle':
      // Full circle arc from bottom-left to top-right
      const large = 0; // arc flag
      const sweep = reverse ? 0 : 1;
      path = `M ${cx - r} ${cy} A ${r} ${r} 0 ${large} ${sweep} ${cx + r} ${cy}`;
      break;

    case 'wave':
      // Wave pattern
      const waveHeight = radius / 3;
      const waveLength = radius * 1.5;
      path = `M ${cx - waveLength} ${cy}`;
      for (let x = cx - waveLength; x <= cx + waveLength; x += 10) {
        const y = cy + Math.sin((x - (cx - waveLength)) / waveLength * Math.PI * 2) * waveHeight;
        path += ` L ${x} ${y}`;
      }
      break;

    case 'spiral':
      // Spiral arc
      const spiralTurns = 1.5;
      const spiralSteps = 100;
      path = `M ${cx} ${cy - radius}`;
      for (let i = 1; i <= spiralSteps; i++) {
        const angle = (i / spiralSteps) * Math.PI * 2 * spiralTurns;
        const r = radius * (1 - i / spiralSteps);
        const x = cx + r * Math.cos(angle);
        const y = cy - r * Math.sin(angle);
        path += ` L ${x} ${y}`;
      }
      break;

    case 'arc':
      // Simple arc
      path = `M ${cx - radius} ${cy} A ${radius} ${radius} 0 0 ${reverse ? 0 : 1} ${cx + radius} ${cy}`;
      break;

    default:
      path = `M 0 ${cy} L 560 ${cy}`; // fallback: straight line
  }

  return path;
}

export default function DesignCanvas({ product, isAdminEditing = false }: { product: ProductDTO; isAdminEditing?: boolean }) {
  const [color, setColor] = useState(product.colors[0]);
  const [size, setSize] = useState<string | null>(product.sizes[0] ?? null);
  const [designWidthCm, setDesignWidthCm] = useState<number | null>(null);
  const [designHeightCm, setDesignHeightCm] = useState<number | null>(null);
  const [view, setView] = useState<'front' | 'back'>('front');
  const [elementsFront, setElementsFront] = useState<DesignElement[]>([]);
  const [elementsBack, setElementsBack] = useState<DesignElement[]>([]);
  const [selectedId, setSelectedId] = useState<string | null>(null);
  const [quantity, setQuantity] = useState(1);
  const [justAdded, setJustAdded] = useState(false);
  const [showLoginPrompt, setShowLoginPrompt] = useState(false);
  const [nodeReadyTick, setNodeReadyTick] = useState(0);
  const [approvalStatus, setApprovalStatus] = useState<'PENDING' | 'APPROVED' | 'REJECTED' | null>(null);
  const [submittingForApproval, setSubmittingForApproval] = useState(false);
  const [designApprovalId, setDesignApprovalId] = useState<string | null>(null);
  const [submissionMessage, setSubmissionMessage] = useState<string | null>(null);
  const [imageDimensions, setImageDimensions] = useState<Record<string, { widthCm: number | null; heightCm: number | null }>>({});
  const [expandedSections, setExpandedSections] = useState<Record<string, boolean>>({});

  const toggleSection = (section: string) => {
    setExpandedSections((prev) => ({ ...prev, [section]: !prev[section] }));
  };

  const stageFrontRef = useRef<Konva.Stage | null>(null);
  const stageBackRef = useRef<Konva.Stage | null>(null);
  const transformerFrontRef = useRef<Konva.Transformer | null>(null);
  const transformerBackRef = useRef<Konva.Transformer | null>(null);
  const nodeRefs = useRef<Map<string, Konva.Node>>(new Map());
  const fileInputRef = useRef<HTMLInputElement | null>(null);
  const canvasContainerRef = useRef<HTMLDivElement | null>(null);
  const [canvasScale, setCanvasScale] = useState(1);
  const addItem = useCart((s) => s.addItem);

  // Konva's Stage keeps a fixed 560x560 internal pixel size (element x/y,
  // print-area math, and export resolution all key off DISPLAY) — on narrow
  // viewports we shrink it purely visually via CSS transform instead of
  // touching that coordinate system. Konva reads the container's actual
  // rendered (post-transform) bounding box for pointer math, so clicks/drags
  // still line up correctly at any scale.
  useEffect(() => {
    if (typeof window === 'undefined') return;

    // Load approval status
    const approvalSaved = localStorage.getItem(`designApproval_${product.id}`);
    if (approvalSaved) {
      try {
        const data = JSON.parse(approvalSaved);
        setDesignApprovalId(data.id);
        setApprovalStatus(data.status);
        console.log('✓ Approval status restored');
      } catch (e) {
        console.error('Failed to load approval status:', e);
      }
    }

    // Load design draft (saved when user tried to checkout without login)
    const designDraft = localStorage.getItem(`designDraft_${product.id}`);
    if (designDraft) {
      try {
        const data = JSON.parse(designDraft);
        console.log('📋 Found design draft, restoring...', data);

        if (data.elementsFront && data.elementsFront.length > 0) {
          setElementsFront(data.elementsFront);
          console.log('✓ Restored', data.elementsFront.length, 'front elements');
        }
        if (data.elementsBack && data.elementsBack.length > 0) {
          setElementsBack(data.elementsBack);
          console.log('✓ Restored', data.elementsBack.length, 'back elements');
        }
        if (data.color) setColor(data.color);
        if (data.size) setSize(data.size);
        if (data.designWidthCm !== null && data.designWidthCm !== undefined) setDesignWidthCm(data.designWidthCm);
        if (data.designHeightCm !== null && data.designHeightCm !== undefined) setDesignHeightCm(data.designHeightCm);
        if (data.imageDimensions) setImageDimensions(data.imageDimensions);
        if (data.quantity) setQuantity(data.quantity);

        console.log('✅ Design fully restored from draft');
        // Keep the draft in localStorage until user completes checkout
        // Only remove after successful add to bag
      } catch (e) {
        console.error('Failed to load design draft:', e);
      }
    }
  }, [product.id]);

  useLayoutEffect(() => {
    const el = canvasContainerRef.current;
    if (!el) return;
    const update = () => setCanvasScale(Math.min(1, el.clientWidth / DISPLAY));
    update();
    const observer = new ResizeObserver(update);
    observer.observe(el);
    return () => observer.disconnect();
  }, []);

  const hasBack = Boolean(product.imageUrlBack);
  const canPersonalize = product.showOnPersonalised;
  const frontPrintArea = product.printArea;
  const backPrintArea = product.printAreaBack ?? product.printArea;
  const activePrintArea = view === 'front' ? frontPrintArea : backPrintArea;
  const activeStageW = activePrintArea.wPct * DISPLAY;
  const activeStageH = activePrintArea.hPct * DISPLAY;

  // Calculate cm per pixel for display using product reference size
  // Reference size maps to full canvas width/height (560px)
  const cmPerPx = product.referenceWidthCm && product.referenceWidthCm > 0 ? product.referenceWidthCm / DISPLAY : 0;
  const pxToCm = (px: number) => {
    if (!cmPerPx || cmPerPx <= 0) return '—';
    const cm = px * cmPerPx;
    return isNaN(cm) ? '?' : cm.toFixed(2);
  };
  const setActiveElements = view === 'front' ? setElementsFront : setElementsBack;

  // Keep whichever transformer actually owns the selected element in sync, and
  // clear the other one — an id only ever lives in one of the two arrays.
  // nodeReadyTick re-runs this once an uploaded image's Konva node actually
  // mounts (it loads asynchronously, unlike text, so it isn't there yet on the
  // same render where it gets selected).
  useEffect(() => {
    const frontNode = selectedId && elementsFront.some((e) => e.id === selectedId) ? nodeRefs.current.get(selectedId) : null;
    const backNode = selectedId && elementsBack.some((e) => e.id === selectedId) ? nodeRefs.current.get(selectedId) : null;
    if (transformerFrontRef.current) {
      transformerFrontRef.current.nodes(frontNode ? [frontNode] : []);
      transformerFrontRef.current.getLayer()?.draw();
    }
    if (transformerBackRef.current) {
      transformerBackRef.current.nodes(backNode ? [backNode] : []);
      transformerBackRef.current.getLayer()?.draw();
    }
  }, [selectedId, elementsFront.length, elementsBack.length, nodeReadyTick]);

  // Canvas text can render with a fallback font if drawn before a web font finishes
  // loading — redraw once fonts are ready so custom font choices show up correctly.
  useEffect(() => {
    document.fonts?.ready.then(() => {
      stageFrontRef.current?.getLayers().forEach((layer) => layer.batchDraw());
      stageBackRef.current?.getLayers().forEach((layer) => layer.batchDraw());
    });
  }, []);

  const updateElement = useCallback((id: string, attrs: Partial<DesignElement>) => {
    setElementsFront((prev) =>
      prev.some((el) => el.id === id) ? prev.map((el) => (el.id === id ? ({ ...el, ...attrs } as DesignElement) : el)) : prev,
    );
    setElementsBack((prev) =>
      prev.some((el) => el.id === id) ? prev.map((el) => (el.id === id ? ({ ...el, ...attrs } as DesignElement) : el)) : prev,
    );
  }, []);

  const addText = () => {
    const id = uuid();
    setActiveElements((prev) => [
      ...prev,
      {
        id,
        type: 'text',
        x: activeStageW / 2 - 40,
        y: activeStageH / 2 - 10,
        rotation: 0,
        text: 'Your text',
        fontFamily: 'Fraunces',
        fontSize: 28,
        fill: '#17181C',
        curvedPath: null,
      },
    ]);
    setSelectedId(id);
  };

  const handleUploadClick = () => fileInputRef.current?.click();

  const handleFile = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = () => {
      const src = reader.result as string;
      const img = new window.Image();
      img.onload = () => {
        const maxDim = Math.min(activeStageW, activeStageH) * 0.7;
        const scale = Math.min(maxDim / img.width, maxDim / img.height, 1);
        const id = uuid();
        setActiveElements((prev) => [
          ...prev,
          {
            id,
            type: 'image',
            x: activeStageW / 2 - (img.width * scale) / 2,
            y: activeStageH / 2 - (img.height * scale) / 2,
            rotation: 0,
            width: img.width * scale,
            height: img.height * scale,
            src,
          },
        ]);
        setSelectedId(id);
      };
      img.src = src;
    };
    reader.readAsDataURL(file);
    e.target.value = '';
  };

  const deleteSelected = () => {
    if (!selectedId) return;
    setElementsFront((prev) => prev.filter((el) => el.id !== selectedId));
    setElementsBack((prev) => prev.filter((el) => el.id !== selectedId));
    setSelectedId(null);
  };

  const selected = elementsFront.find((el) => el.id === selectedId) ?? elementsBack.find((el) => el.id === selectedId);

  // Calculate the effective price for made-to-order items (use personalisedPrice if available)
  const effectivePriceForPersonalised = canPersonalize
    ? getEffectivePrice(
        {
          id: product.id,
          basePrice: product.basePrice,
          personalisedPrice: product.personalisedPrice,
          salePrice: product.onSale ? product.effectivePrice : null,
          saleStartsAt: null,
          saleEndsAt: null,
        },
        [],
        new Date(),
        true,
      ).price
    : product.effectivePrice;

  const handleAddToBag = async () => {
    const { isAuthenticated } = await checkCustomerAuth();
    if (!isAuthenticated) {
      // Save design draft before redirecting to login
      if (typeof window !== 'undefined' && (elementsFront.length > 0 || elementsBack.length > 0)) {
        localStorage.setItem(`designDraft_${product.id}`, JSON.stringify({
          elementsFront,
          elementsBack,
          color,
          size,
          designWidthCm,
          designHeightCm,
          imageDimensions,
          quantity,
          timestamp: new Date().toISOString(),
        }));
        console.log('Design saved to draft');
      }
      setShowLoginPrompt(true);
      return;
    }

    if (!canPersonalize) {
      const flatPhoto = product.colorPhotos[color] ?? product.imageUrl ?? '';
      addItem({
        cartItemId: uuid(),
        productId: product.id,
        slug: product.slug,
        name: product.name,
        mockup: product.mockup,
        color,
        size,
        quantity,
        unitPrice: product.effectivePrice,
        designJson: { front: [], back: [] },
        designPreviewUrl: flatPhoto,
        designPreviewUrlBack: null,
        placementPreviewUrl: flatPhoto || null,
        placementPreviewUrlBack: product.imageUrlBack ?? null,
        designWidthCm: null,
        designHeightCm: null,
      });

      // Clear design draft if any
      if (typeof window !== 'undefined') {
        localStorage.removeItem(`designDraft_${product.id}`);
      }

      setJustAdded(true);
      setTimeout(() => setJustAdded(false), 2200);
      return;
    }

    setSelectedId(null); // clear transformer handles before export
    requestAnimationFrame(async () => {
      const frontStage = stageFrontRef.current;
      if (!frontStage) return;

      // Hide the dashed guide box + tint before exporting, so the saved PNG is
      // just the design itself — transparent background, no shirt, no guide
      // marks — ready to hand off for printing.
      const frontGuides = frontStage.find('.printGuide');
      frontGuides.forEach((g) => g.hide());
      const frontDataUrl = frontStage.toDataURL({ pixelRatio: 2 });

      const frontBox = {
        left: frontPrintArea.xPct * DISPLAY,
        top: frontPrintArea.yPct * DISPLAY,
        w: frontPrintArea.wPct * DISPLAY,
        h: frontPrintArea.hPct * DISPLAY,
      };
      const frontPhotoInfo = getPhotoInfo('front');
      const frontPlacementUrl = frontPhotoInfo
        ? await composePlacementImage(
            frontPhotoInfo.url,
            frontPhotoInfo.tint ? { tint: true, color } : null,
            frontStage,
            frontBox,
          ).catch(() => null)
        : null;
      frontGuides.forEach((g) => g.show());

      let backDataUrl: string | null = null;
      let backPlacementUrl: string | null = null;
      if (hasBack && stageBackRef.current) {
        const backStage = stageBackRef.current;
        const backGuides = backStage.find('.printGuide');
        backGuides.forEach((g) => g.hide());
        backDataUrl = backStage.toDataURL({ pixelRatio: 2 });

        const backBox = {
          left: backPrintArea.xPct * DISPLAY,
          top: backPrintArea.yPct * DISPLAY,
          w: backPrintArea.wPct * DISPLAY,
          h: backPrintArea.hPct * DISPLAY,
        };
        const backPhotoInfo = getPhotoInfo('back');
        backPlacementUrl = backPhotoInfo
          ? await composePlacementImage(
              backPhotoInfo.url,
              backPhotoInfo.tint ? { tint: true, color } : null,
              backStage,
              backBox,
            ).catch(() => null)
          : null;
        backGuides.forEach((g) => g.show());
      }

      const cartItem = {
        cartItemId: uuid(),
        productId: product.id,
        slug: product.slug,
        name: product.name,
        mockup: product.mockup,
        color,
        size,
        quantity,
        unitPrice: effectivePriceForPersonalised,
        designJson: { front: elementsFront, back: elementsBack },
        designPreviewUrl: frontDataUrl,
        designPreviewUrlBack: backDataUrl,
        placementPreviewUrl: frontPlacementUrl ?? frontDataUrl,
        placementPreviewUrlBack: backPlacementUrl ?? backDataUrl,
        designWidthCm,
        designHeightCm,
      };
      console.log('Adding to cart with dimensions:', { designWidthCm, designHeightCm, cartItem });
      addItem(cartItem);

      // Clear design draft now that it's been added to cart
      if (typeof window !== 'undefined') {
        localStorage.removeItem(`designDraft_${product.id}`);
        console.log('✓ Design draft cleared after adding to cart');
      }

      setJustAdded(true);
      setTimeout(() => setJustAdded(false), 2200);
    });
  };

  const handleSubmitForApproval = async () => {
    // First, save design to localStorage (in case user needs to login)
    if (typeof window !== 'undefined' && (elementsFront.length > 0 || elementsBack.length > 0)) {
      localStorage.setItem(`designDraft_${product.id}`, JSON.stringify({
        elementsFront,
        elementsBack,
        color,
        size,
        designWidthCm,
        designHeightCm,
        imageDimensions,
        quantity,
        timestamp: new Date().toISOString(),
      }));
    }

    if (elementsFront.length === 0 && elementsBack.length === 0) {
      return;
    }

    setSubmittingForApproval(true);
    setSelectedId(null);
    requestAnimationFrame(async () => {
      const frontStage = stageFrontRef.current;
      if (!frontStage) {
        setSubmittingForApproval(false);
        return;
      }

      const frontGuides = frontStage.find('.printGuide');
      frontGuides.forEach((g) => g.hide());
      const frontDataUrl = frontStage.toDataURL({ pixelRatio: 2 });

      const frontBox = {
        left: frontPrintArea.xPct * DISPLAY,
        top: frontPrintArea.yPct * DISPLAY,
        w: frontPrintArea.wPct * DISPLAY,
        h: frontPrintArea.hPct * DISPLAY,
      };
      const frontPhotoInfo = getPhotoInfo('front');
      const frontPlacementUrl = frontPhotoInfo
        ? await composePlacementImage(
            frontPhotoInfo.url,
            frontPhotoInfo.tint ? { tint: true, color } : null,
            frontStage,
            frontBox,
          ).catch(() => null)
        : null;
      frontGuides.forEach((g) => g.show());

      let backDataUrl: string | null = null;
      let backPlacementUrl: string | null = null;
      if (hasBack && stageBackRef.current) {
        const backStage = stageBackRef.current;
        const backGuides = backStage.find('.printGuide');
        backGuides.forEach((g) => g.hide());
        backDataUrl = backStage.toDataURL({ pixelRatio: 2 });

        const backBox = {
          left: backPrintArea.xPct * DISPLAY,
          top: backPrintArea.yPct * DISPLAY,
          w: backPrintArea.wPct * DISPLAY,
          h: backPrintArea.hPct * DISPLAY,
        };
        const backPhotoInfo = getPhotoInfo('back');
        backPlacementUrl = backPhotoInfo
          ? await composePlacementImage(
              backPhotoInfo.url,
              backPhotoInfo.tint ? { tint: true, color } : null,
              backStage,
              backBox,
            ).catch(() => null)
          : null;
        backGuides.forEach((g) => g.show());
      }

      try {
        const res = await fetch('/api/designs/submit', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            productId: product.id,
            designJson: JSON.stringify({ front: elementsFront, back: elementsBack }),
            designPreviewUrl: frontDataUrl,
            designPreviewUrlBack: backDataUrl,
            placementPreviewUrl: frontPlacementUrl ?? frontDataUrl,
            placementPreviewUrlBack: backPlacementUrl ?? backDataUrl,
            designWidthCm,
            designHeightCm,
            designImageDimensions: Object.entries(imageDimensions).map(([imageId, dims]) => ({
              imageId,
              widthCm: dims.widthCm,
              heightCm: dims.heightCm,
            })),
            color,
            size,
          }),
        });

        if (res.ok) {
          const design = await res.json();
          setDesignApprovalId(design.id);
          setApprovalStatus('PENDING');
          setSubmissionMessage(`✓ Design submitted for approval! You'll receive an email when it's ready to add to your bag.`);
          // Clear design elements so user can start fresh
          setElementsFront([]);
          setElementsBack([]);
          // Save to localStorage so status persists on page reload
          if (typeof window !== 'undefined') {
            localStorage.setItem(`designApproval_${product.id}`, JSON.stringify({
              id: design.id,
              status: 'PENDING',
              submittedAt: new Date().toISOString(),
            }));
          }
          console.log('Design submitted for approval:', design.id);
          setTimeout(() => setSubmissionMessage(null), 5000);
        } else if (res.status === 401) {
          setShowLoginPrompt(true);
          console.log('User not authenticated, showing login prompt');
        } else {
          const err = await res.json().catch(() => ({ error: 'Unknown error' }));
          console.error('Failed to submit design for approval:', err.error);
          setSubmissionMessage(`✗ Failed to submit design: ${err.error || 'Unknown error'}`);
        }
      } finally {
        setSubmittingForApproval(false);
      }
    });
  };

  function renderPhoto(v: 'front' | 'back') {
    const colorPhoto = v === 'front' ? product.colorPhotos[color] : product.colorPhotosBack[color];
    if (colorPhoto) {
      return <img src={colorPhoto} alt={`${product.name} in ${color}`} className="h-full w-full object-cover" />;
    }

    const activePhoto = v === 'front' ? product.imageUrl : product.imageUrlBack;
    if (!activePhoto) {
      return <ProductMockup mockup={product.mockup} color={color} />;
    }
    if (product.photoRecolorable) {
      return (
        <div className="relative h-full w-full">
          <img
            src={activePhoto}
            alt={product.name}
            className="h-full w-full object-cover"
            style={{ filter: 'grayscale(1) brightness(2.1) contrast(1.15)' }}
          />
          <div className="absolute inset-0" style={{ backgroundColor: color, mixBlendMode: 'multiply' }} />
        </div>
      );
    }
    return <img src={activePhoto} alt={product.name} className="h-full w-full object-cover" />;
  }

  // Same resolution logic as renderPhoto, but returns raw data instead of JSX —
  // used when compositing the placement-reference image for the order record.
  function getPhotoInfo(v: 'front' | 'back'): { url: string; tint: boolean } | null {
    const colorPhoto = v === 'front' ? product.colorPhotos[color] : product.colorPhotosBack[color];
    if (colorPhoto) return { url: colorPhoto, tint: false };

    const activePhoto = v === 'front' ? product.imageUrl : product.imageUrlBack;
    if (!activePhoto) return null; // illustration only — nothing photographic to composite onto

    return { url: activePhoto, tint: product.photoRecolorable };
  }

  return (
    <div className="grid grid-cols-1 gap-10 lg:grid-cols-[560px_1fr]">
      {/* Canvas */}
      <div ref={canvasContainerRef} className="w-full min-w-0 max-w-[560px]">
        {hasBack && (
          <div className="mb-3 inline-flex border border-line">
            <button
              onClick={() => setView('front')}
              className={`px-4 py-1.5 text-sm ${view === 'front' ? 'bg-ink text-paper' : 'hover:text-clay'}`}
            >
              Front
            </button>
            <button
              onClick={() => setView('back')}
              className={`px-4 py-1.5 text-sm ${view === 'back' ? 'bg-ink text-paper' : 'hover:text-clay'}`}
            >
              Back
            </button>
          </div>
        )}

        {canPersonalize ? (
          <>
            <PrintSurface
              photo={renderPhoto('front')}
              printArea={frontPrintArea}
              elements={elementsFront}
              selectedId={selectedId}
              setSelectedId={setSelectedId}
              updateElement={updateElement}
              nodeRefs={nodeRefs}
              stageRef={stageFrontRef}
              transformerRef={transformerFrontRef}
              visible={view === 'front'}
              caption="Dashed line marks the print area"
              onNodeReady={() => setNodeReadyTick((t) => t + 1)}
              scale={canvasScale}
              product={product}
            />

            {hasBack && (
              <PrintSurface
                photo={renderPhoto('back')}
                printArea={backPrintArea}
                elements={elementsBack}
                selectedId={selectedId}
                setSelectedId={setSelectedId}
                updateElement={updateElement}
                nodeRefs={nodeRefs}
                stageRef={stageBackRef}
                transformerRef={transformerBackRef}
                visible={view === 'back'}
                caption="Dashed line marks the print area (back)"
                onNodeReady={() => setNodeReadyTick((t) => t + 1)}
                scale={canvasScale}
                product={product}
              />
            )}
          </>
        ) : (
          <div className="relative aspect-square w-full max-w-[560px] border border-line bg-surface">
            {renderPhoto(view)}
          </div>
        )}
      </div>

      {/* Controls */}
      <div className="flex flex-col gap-4">
        <div>
          <h1 className="font-display text-4xl">{product.name}</h1>
          <p className="mt-2 text-muted">{product.description}</p>
          <div className="mt-4">
            <p className="flex items-baseline gap-2 font-mono text-lg">
              {(() => {
                const { onSale, price, originalPrice } = getEffectivePrice(
                  {
                    id: product.id,
                    basePrice: product.basePrice,
                    personalisedPrice: product.personalisedPrice,
                    salePrice: product.onSale ? product.effectivePrice : null,
                    saleStartsAt: null,
                    saleEndsAt: null,
                  },
                  [],
                  new Date(),
                  true,
                );
                return (
                  <>
                    {onSale && originalPrice != null && (
                      <Price cents={originalPrice} className="text-base text-muted line-through" />
                    )}
                    <Price cents={price} className={onSale ? 'text-splash-pink' : undefined} />
                  </>
                );
              })()}
            </p>
            <p className="text-xs text-muted">For personalized design</p>
          </div>
        </div>

        {approvalStatus === 'PENDING' && (
          <p className="text-sm text-orange-600 bg-orange-50 border border-orange-200 px-4 py-3 rounded">
            ⏳ Your design is pending admin approval. You'll receive an email when it's ready to add to your bag.
          </p>
        )}
        {approvalStatus === 'APPROVED' && (
          <p className="text-sm text-pine bg-green-50 border border-green-200 px-4 py-3 rounded">
            ✓ Your design has been approved! You can now add it to your bag.
          </p>
        )}
        {approvalStatus === 'REJECTED' && (
          <p className="text-sm text-splash-pink bg-red-50 border border-splash-pink/30 px-4 py-3 rounded">
            Your design needs changes. Check your messages for feedback.
          </p>
        )}

        <div className="grid grid-cols-2 gap-4">
          <div>
            <p className="tag-label mb-2">Color</p>
            <div className="flex flex-wrap gap-2">
              {product.colors.map((c) => (
                <button
                  key={c}
                  onClick={() => setColor(c)}
                  aria-label={`Choose color ${c}`}
                  className={`h-8 w-8 rounded-full border transition-transform ${
                    color === c ? 'scale-110 border-ink ring-2 ring-ink ring-offset-1 ring-offset-paper' : 'border-line'
                  }`}
                  style={{ backgroundColor: c }}
                />
              ))}
            </div>
          </div>

          {product.sizes.length > 0 && (
            <div>
              <p className="tag-label mb-2">Size</p>
              <div className="flex flex-wrap gap-1">
                {product.sizes.map((s) => (
                  <button
                    key={s}
                    onClick={() => setSize(s)}
                    className={`min-w-[44px] border px-2 py-1 text-xs transition-colors ${
                      size === s
                        ? 'border-clay bg-clay text-paper'
                        : 'border-line text-ink hover:border-clay hover:text-clay'
                    }`}
                  >
                    {s}
                  </button>
                ))}
              </div>
            </div>
          )}
        </div>
        {product.imageUrl && !product.photoRecolorable && Object.keys(product.colorPhotos).length === 0 && (
          <p className="text-xs text-muted">
            This product uses a real photo, so the picture won&apos;t change color — your pick is
            still saved with the order.
          </p>
        )}


        {canPersonalize && (
        <div>
          <p className="tag-label mb-2">
            Your design {hasBack && <span className="normal-case text-muted">— editing the {view}</span>}
          </p>

          {/* Image Dimension Inputs */}
          {(() => {
            const images = view === 'front' ? elementsFront.filter(el => el.type === 'image') : elementsBack.filter(el => el.type === 'image');
            return images.length > 0 ? (
              <div className="mb-2 border border-line bg-surface">
                <button
                  onClick={() => toggleSection('imageDimensions')}
                  className="w-full px-3 py-2 flex items-center justify-between text-sm font-semibold hover:bg-ink/5"
                >
                  <span>Image Dimensions ({images.length})</span>
                  <span>{expandedSections.imageDimensions ? '−' : '+'}</span>
                </button>
                {expandedSections.imageDimensions && (
                  <div className="border-t border-line p-2 space-y-2">
                    {images.map((img, idx) => (
                      <div key={img.id} className="text-xs">
                        <p className="font-semibold mb-1">Image {idx + 1}</p>
                        <div className="flex gap-2">
                      <label className="flex flex-col gap-1 flex-1">
                        <span className="text-xs text-muted">Width (cm)</span>
                        <input
                          type="number"
                          step="0.1"
                          min="0"
                          value={imageDimensions[img.id]?.widthCm ?? ''}
                          onChange={(e) => {
                            const val = e.target.value ? Number(e.target.value) : null;
                            setImageDimensions((prev) => ({
                              ...prev,
                              [img.id]: { ...prev[img.id], widthCm: val },
                            }));
                          }}
                          placeholder="e.g. 10"
                          className="border border-line bg-paper px-3 py-2 text-sm"
                        />
                      </label>
                      <label className="flex flex-col gap-1 flex-1">
                        <span className="text-xs text-muted">Height (cm)</span>
                        <input
                          type="number"
                          step="0.1"
                          min="0"
                          value={imageDimensions[img.id]?.heightCm ?? ''}
                          onChange={(e) => {
                            const val = e.target.value ? Number(e.target.value) : null;
                            setImageDimensions((prev) => ({
                              ...prev,
                              [img.id]: { ...prev[img.id], heightCm: val },
                            }));
                          }}
                          placeholder="e.g. 10"
                          className="border border-line bg-paper px-3 py-2 text-sm"
                        />
                      </label>
                        </div>
                      </div>
                    ))}
                  </div>
                )}
              </div>
            ) : null;
          })()}

          {/* Font Properties Inputs */}
          {(() => {
            const texts = view === 'front' ? elementsFront.filter(el => el.type === 'text') : elementsBack.filter(el => el.type === 'text');
            return texts.length > 0 ? (
              <div className="mb-2 border border-line bg-surface">
                <button
                  onClick={() => toggleSection('fontProperties')}
                  className="w-full px-3 py-2 flex items-center justify-between text-sm font-semibold hover:bg-ink/5"
                >
                  <span>Font Properties ({texts.length})</span>
                  <span>{expandedSections.fontProperties ? '−' : '+'}</span>
                </button>
                {expandedSections.fontProperties && (
                  <div className="border-t border-line p-2 space-y-3">
                    {texts.map((text, idx) => (
                      <div key={text.id} className="border-b border-line pb-3 last:border-0 last:pb-0">
                        <p className="text-xs font-semibold mb-2">Font {idx + 1}</p>
                        <div className="space-y-2">
                      <label className="flex flex-col gap-1">
                        <span className="text-xs text-muted">Text</span>
                        <input
                          type="text"
                          value={text.text}
                          onChange={(e) => updateElement(text.id, { text: e.target.value })}
                          className="border border-line bg-paper px-3 py-2 text-sm"
                          placeholder="Text content"
                        />
                      </label>
                      <label className="flex flex-col gap-1">
                        <span className="text-xs text-muted">Font Family</span>
                        <select
                          value={text.fontFamily}
                          onChange={(e) => updateElement(text.id, { fontFamily: e.target.value })}
                          className="border border-line bg-paper px-3 py-2 text-sm"
                          style={{ fontFamily: text.fontFamily }}
                        >
                          {FONTS.map((f) => (
                            <option key={f} value={f} style={{ fontFamily: f }}>
                              {f}
                            </option>
                          ))}
                        </select>
                      </label>
                      <div className="flex gap-3">
                        <label className="flex flex-col gap-1 flex-1">
                          <span className="text-xs text-muted">Font Size</span>
                          <div className="flex gap-2 items-center">
                            <input
                              type="range"
                              min={10}
                              max={80}
                              value={text.fontSize}
                              onChange={(e) => updateElement(text.id, { fontSize: Number(e.target.value) })}
                              className="flex-1"
                            />
                            <span className="w-12 text-right font-mono text-xs">{text.fontSize}pt</span>
                          </div>
                        </label>
                        <label className="flex flex-col gap-1">
                          <span className="text-xs text-muted">Color</span>
                          <input
                            type="color"
                            value={text.fill}
                            onChange={(e) => updateElement(text.id, { fill: e.target.value })}
                            className="h-10 w-16 border border-line bg-paper p-1 cursor-pointer"
                          />
                        </label>
                      </div>
                      <label className="flex flex-col gap-1">
                        <span className="text-xs text-muted">Rotation (degrees)</span>
                        <div className="flex gap-2 items-center">
                          <input
                            type="range"
                            min={0}
                            max={360}
                            value={text.rotation || 0}
                            onChange={(e) => updateElement(text.id, { rotation: Number(e.target.value) })}
                            className="flex-1"
                          />
                          <span className="w-12 text-right font-mono text-xs">{text.rotation || 0}°</span>
                        </div>
                      </label>

                      {/* Curved Text Controls */}
                      <div className="border-t border-line pt-3">
                        <label className="flex items-center gap-2 text-sm text-muted mb-3">
                          <input
                            type="checkbox"
                            checked={text.curvedPath ? true : false}
                            onChange={(e) => updateElement(text.id, { curvedPath: e.target.checked ? { type: 'circle', radius: 80 } : null })}
                            className="cursor-pointer"
                          />
                          Curved text
                        </label>

                        {text.curvedPath && (
                          <div className="space-y-3">
                            <label className="flex flex-col gap-1">
                              <span className="text-xs text-muted">Curve type</span>
                              <select
                                value={text.curvedPath.type || 'circle'}
                                onChange={(e) => updateElement(text.id, { curvedPath: { ...text.curvedPath, type: e.target.value as any } })}
                                className="border border-line bg-paper px-2 py-1 text-xs"
                              >
                                <option value="circle">Circle</option>
                                <option value="wave">Wave</option>
                                <option value="spiral">Spiral</option>
                                <option value="arc">Arc</option>
                              </select>
                            </label>

                            <label className="flex flex-col gap-1">
                              <span className="text-xs text-muted">Radius / Intensity</span>
                              <div className="flex gap-2 items-center">
                                <input
                                  type="range"
                                  min={20}
                                  max={200}
                                  value={text.curvedPath.radius || 80}
                                  onChange={(e) => updateElement(text.id, { curvedPath: { ...text.curvedPath, radius: Number(e.target.value) } })}
                                  className="flex-1"
                                />
                                <span className="w-12 text-right font-mono text-xs">{text.curvedPath.radius || 80}</span>
                              </div>
                            </label>

                            <label className="flex items-center gap-2 text-xs">
                              <input
                                type="checkbox"
                                checked={text.curvedPath.reverse ? true : false}
                                onChange={(e) => updateElement(text.id, { curvedPath: { ...text.curvedPath, reverse: e.target.checked } })}
                                className="cursor-pointer"
                              />
                              <span className="text-muted">Reverse direction</span>
                            </label>
                          </div>
                        )}
                        </div>
                      </div>
                    </div>
                ))}
                  </div>
                )}
              </div>
            ) : null;
          })()}

          <div className="flex flex-wrap gap-3">
            <button onClick={addText} className="border border-ink px-4 py-2 text-sm hover:border-clay hover:bg-clay hover:text-paper">
              + Add text
            </button>
            <button
              onClick={handleUploadClick}
              className="border border-ink px-4 py-2 text-sm hover:border-clay hover:bg-clay hover:text-paper"
            >
              + Upload image
            </button>
            <input ref={fileInputRef} type="file" accept="image/*" className="hidden" onChange={handleFile} />
            {selected && (
              <button
                onClick={deleteSelected}
                className="border border-line px-4 py-2 text-sm text-muted hover:border-ink hover:text-ink"
              >
                Delete selected
              </button>
            )}
          </div>

          {selected?.type === 'text' && (
            <div className="mt-4 flex flex-wrap items-center gap-3 border border-line bg-surface p-4">
              <input
                value={selected.text}
                onChange={(e) => updateElement(selected.id, { text: e.target.value })}
                className="border border-line bg-paper px-2 py-1 text-sm text-ink placeholder:text-muted"
                placeholder="Text"
              />
              <select
                value={selected.fontFamily}
                onChange={(e) => updateElement(selected.id, { fontFamily: e.target.value })}
                className="border border-line bg-paper px-2 py-1 text-sm text-ink"
                style={{ fontFamily: selected.fontFamily }}
              >
                {FONTS.map((f) => (
                  <option key={f} value={f} style={{ fontFamily: f }}>
                    {f}
                  </option>
                ))}
              </select>
              <input
                type="color"
                value={selected.fill}
                onChange={(e) => updateElement(selected.id, { fill: e.target.value })}
                className="h-8 w-8 border border-line bg-paper p-0"
              />
              <label className="flex items-center gap-2 text-sm text-muted">
                Font Size
                <input
                  type="range"
                  min={10}
                  max={80}
                  value={selected.fontSize}
                  onChange={(e) => updateElement(selected.id, { fontSize: Number(e.target.value) })}
                />
                <span className="w-12 text-right font-mono text-xs">{selected.fontSize}pt</span>
              </label>
              <label className="flex items-center gap-2 text-sm text-muted">
                Angle
                <input
                  type="range"
                  min={0}
                  max={360}
                  value={selected.rotation || 0}
                  onChange={(e) => updateElement(selected.id, { rotation: Number(e.target.value) })}
                />
                <span className="w-10 text-right font-mono text-xs">{selected.rotation || 0}°</span>
              </label>
            </div>
          )}

        </div>
        )}

        <div className="flex flex-col gap-3">
          <div className="flex items-center gap-4">
            <div className="flex items-center border border-ink">
              <button
                onClick={() => setQuantity((q) => Math.max(1, q - 1))}
                className="px-3 py-2 text-sm"
                aria-label="Decrease quantity"
              >
                −
              </button>
              <span className="w-10 text-center font-mono text-sm">{quantity}</span>
              <button
                onClick={() => setQuantity((q) => q + 1)}
                className="px-3 py-2 text-sm"
                aria-label="Increase quantity"
              >
                +
              </button>
            </div>
            {approvalStatus === 'APPROVED' ? (
              <button
                onClick={handleAddToBag}
                disabled={elementsFront.length === 0 && elementsBack.length === 0}
                className={`flex-1 px-6 py-3 text-sm font-medium transition-colors ${
                  elementsFront.length === 0 && elementsBack.length === 0
                    ? 'bg-muted text-muted/50 cursor-not-allowed'
                    : 'bg-clay text-paper hover:bg-clay-dark'
                }`}
              >
                Add to bag — <Price cents={((elementsFront.length > 0 || elementsBack.length > 0) ? effectivePriceForPersonalised : product.effectivePrice) * quantity} />
              </button>
            ) : (
              <button
                onClick={handleSubmitForApproval}
                disabled={isAdminEditing || elementsFront.length === 0 && elementsBack.length === 0 || submittingForApproval || approvalStatus === 'PENDING'}
                className={`flex-1 px-6 py-3 text-sm font-medium transition-colors ${
                  isAdminEditing || elementsFront.length === 0 && elementsBack.length === 0 || submittingForApproval || approvalStatus === 'PENDING'
                    ? 'bg-muted text-muted/50 cursor-not-allowed'
                    : 'bg-clay text-paper hover:bg-clay-dark'
                }`}
              >
                {submittingForApproval ? 'Submitting…' : 'Submit for Approval'}
              </button>
            )}
          </div>
          {elementsFront.length === 0 && elementsBack.length === 0 && !approvalStatus && (
            <p className="text-xs text-splash-pink">Add text or images to personalize your design before submitting</p>
          )}
          {justAdded && <p className="text-sm text-pine">Added to your bag.</p>}
        </div>
      </div>

      <LoginPromptModal isOpen={showLoginPrompt} onClose={() => setShowLoginPrompt(false)} />
    </div>
  );
}
