import { useState, useCallback, useEffect, Fragment, useMemo } from 'react'
import { useParams, Link, useNavigate } from 'react-router-dom'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { useDropzone } from 'react-dropzone'
import {
  ArrowLeft, Pencil, Save, X, Box, Image,
  RotateCcw, RefreshCw, Upload, ChevronDown, ChevronRight, Wand2, Download, Plus, Trash2, Filter, Cuboid, Ruler,
} from 'lucide-react'
import { toast } from 'sonner'
import {
  getProduct, updateProduct, uploadProductCad, saveProductCadMaterials, regenerateProduct,
  reprocessProduct, reassignMaterialsFromExcel, getProductOrders, getProductRenders,
  createRenderPosition, updateRenderPosition, deleteRenderPosition, deleteProductRender,
  downloadProductRenders,
} from '../api/products'
import type { Product, CadPartMaterial, ProductRender, RenderPosition } from '../api/products'
import { listMaterials } from '../api/materials'
import MaterialInput from '../components/shared/MaterialInput'
import MaterialWizard from '../components/MaterialWizard'
import { useAuthStore } from '../store/auth'
import { downloadStl, generateStl, generateGltfGeometry, exportGltfColored } from '../api/cad'
import InlineCadViewer from '../components/cad/InlineCadViewer'

function CadStatusBadge({ status }: { status: string | null }) {
  if (!status) return (
    <span className="text-xs px-2 py-0.5 rounded-full bg-surface-muted text-content-muted">No STEP</span>
  )
  const map: Record<string, string> = {
    completed: 'bg-status-success-bg text-status-success-text',
    processing: 'bg-status-info-bg text-status-info-text animate-pulse',
    failed: 'bg-status-error-bg text-status-error-text',
    pending: 'bg-status-warning-bg text-status-warning-text',
  }
  return (
    <span className={`text-xs px-2 py-0.5 rounded-full font-medium ${map[status] || 'bg-surface-muted text-content-muted'}`}>
      {status}
    </span>
  )
}

const META_FIELDS: Array<{ key: keyof Product; label: string }> = [
  { key: 'ebene1', label: 'Ebene 1' },
  { key: 'ebene2', label: 'Ebene 2' },
  { key: 'baureihe', label: 'Baureihe' },
  { key: 'produkt_baureihe', label: 'Produkt-Baureihe' },
  { key: 'lagertyp', label: 'Lagertyp' },
  { key: 'name_cad_modell', label: 'Name CAD-Modell' },
]

export default function ProductDetailPage() {
  const { id } = useParams<{ id: string }>()
  const navigate = useNavigate()
  const qc = useQueryClient()
  const user = useAuthStore((s) => s.user)
  const isPrivileged = user?.role === 'admin' || user?.role === 'project_manager'

  const [editMode, setEditMode] = useState(false)
  const [draft, setDraft] = useState<Partial<Product>>({})
  const [showOrders, setShowOrders] = useState(false)
  const [showExcelRow, setShowExcelRow] = useState(false)
  const [materialRows, setMaterialRows] = useState<CadPartMaterial[]>([])
  const [materialsDirty, setMaterialsDirty] = useState(false)
  const [wizardOpen, setWizardOpen] = useState(false)
  const [wizardTargetIdx, setWizardTargetIdx] = useState<number | null>(null)

  const { data: product, isLoading } = useQuery({
    queryKey: ['product', id],
    queryFn: () => getProduct(id!),
    enabled: !!id,
  })

  const { data: materialLibrary = [] } = useQuery({
    queryKey: ['materials'],
    queryFn: listMaterials,
  })

  useEffect(() => {
    if (!product || materialsDirty) return
    const parsedNames = product.cad_parsed_objects ?? []
    if (parsedNames.length > 0) {
      // Build rows from parsed STEP objects, pre-filling any saved material assignments
      const savedMap = new Map(
        (product.cad_part_materials || []).map((m) => [m.part_name, m.material])
      )
      setMaterialRows(
        parsedNames.map((name) => ({ part_name: name, material: savedMap.get(name) ?? '' }))
      )
    } else {
      // Fallback: show whatever is saved (no parsed objects yet)
      setMaterialRows(product.cad_part_materials || [])
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [product?.id, product?.cad_parsed_objects?.length, product?.cad_part_materials.length])

  const { data: renders = [] } = useQuery<ProductRender[]>({
    queryKey: ['product-renders', id],
    queryFn: () => getProductRenders(id!),
    enabled: !!id,
  })

  const [pendingDelete, setPendingDelete] = useState<string | null>(null)
  const [selectMode, setSelectMode] = useState(false)
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
  const [batchConfirm, setBatchConfirm] = useState(false)
  const [batchLoading, setBatchLoading] = useState(false)
  const [filterOutputType, setFilterOutputType] = useState<string | null>(null)
  const [downloadLoading, setDownloadLoading] = useState(false)

  const outputTypeNames = useMemo(() => {
    const names = renders.map(r => r.output_type_name).filter((n): n is string => n !== null)
    return [...new Set(names)].sort()
  }, [renders])

  const filteredRenders = useMemo(() => {
    if (!filterOutputType) return renders
    return renders.filter(r => r.output_type_name === filterOutputType)
  }, [renders, filterOutputType])

  const toggleSelect = (lineId: string) => {
    setSelectedIds(prev => {
      const next = new Set(prev)
      if (next.has(lineId)) next.delete(lineId)
      else next.add(lineId)
      return next
    })
  }

  const exitSelectMode = () => {
    setSelectMode(false)
    setSelectedIds(new Set())
    setBatchConfirm(false)
  }

  const handleBatchDelete = async () => {
    if (selectedIds.size === 0 || batchLoading) return
    setBatchLoading(true)
    try {
      await Promise.all([...selectedIds].map(lineId => deleteProductRender(id!, lineId)))
      qc.invalidateQueries({ queryKey: ['product-renders', id] })
      qc.invalidateQueries({ queryKey: ['product', id] })
      toast.success(`${selectedIds.size} render${selectedIds.size > 1 ? 's' : ''} deleted`)
      exitSelectMode()
    } catch {
      toast.error('Failed to delete some renders')
    } finally {
      setBatchLoading(false)
    }
  }

  const handleDownloadSelected = async () => {
    if (selectedIds.size === 0 || downloadLoading) return
    setDownloadLoading(true)
    try {
      const productName = product?.name || product?.pim_id || 'product'
      const safe = productName.replace(/[^\w-]/g, '_')
      await downloadProductRenders(id!, [...selectedIds], `${safe}_renders.zip`)
      toast.success(`Downloading ${selectedIds.size} render${selectedIds.size > 1 ? 's' : ''}`)
    } catch {
      toast.error('Failed to download renders')
    } finally {
      setDownloadLoading(false)
    }
  }

  const handleDownloadAll = async () => {
    if (filteredRenders.length === 0 || downloadLoading) return
    setDownloadLoading(true)
    try {
      const productName = product?.name || product?.pim_id || 'product'
      const safe = productName.replace(/[^\w-]/g, '_')
      const suffix = filterOutputType ? `_${filterOutputType.replace(/[^\w-]/g, '_')}` : ''
      await downloadProductRenders(id!, filteredRenders.map(r => r.order_line_id), `${safe}${suffix}_renders.zip`)
      toast.success(`Downloading ${filteredRenders.length} render${filteredRenders.length > 1 ? 's' : ''}`)
    } catch {
      toast.error('Failed to download renders')
    } finally {
      setDownloadLoading(false)
    }
  }

  const deleteRenderMut = useMutation({
    mutationFn: (orderLineId: string) => deleteProductRender(id!, orderLineId),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['product-renders', id] })
      qc.invalidateQueries({ queryKey: ['product', id] })
      setPendingDelete(null)
      toast.success('Render deleted')
    },
    onError: () => {
      setPendingDelete(null)
      toast.error('Failed to delete render')
    },
  })

  const { data: orders, refetch: fetchOrders } = useQuery({
    queryKey: ['product-orders', id],
    queryFn: () => getProductOrders(id!),
    enabled: false,
  })

  const updateMut = useMutation({
    mutationFn: (data: Partial<Product>) => updateProduct(id!, data),
    onSuccess: (updated) => {
      toast.success('Product updated')
      qc.setQueryData(['product', id], updated)
      setEditMode(false)
      setDraft({})
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Update failed'),
  })

  const cadUploadMut = useMutation({
    mutationFn: (file: File) => uploadProductCad(id!, file),
    onSuccess: () => {
      toast.success('STEP file uploaded — processing started')
      qc.invalidateQueries({ queryKey: ['product', id] })
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Upload failed'),
  })

  const saveMaterialsMut = useMutation({
    mutationFn: () => saveProductCadMaterials(id!, materialRows),
    onSuccess: (updated) => {
      toast.success('Materials saved — thumbnail queued')
      qc.setQueryData(['product', id], updated)
      setMaterialsDirty(false)
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Save failed'),
  })

  const regenerateMut = useMutation({
    mutationFn: () => regenerateProduct(id!),
    onSuccess: () => toast.success('Thumbnail regeneration queued'),
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed'),
  })

  const reprocessMut = useMutation({
    mutationFn: () => reprocessProduct(id!),
    onSuccess: () => {
      toast.success('STEP reprocessing queued — part list will refresh when complete')
      qc.invalidateQueries({ queryKey: ['product', id] })
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed'),
  })

  const reassignMut = useMutation({
    mutationFn: () => reassignMaterialsFromExcel(id!),
    onSuccess: (updated) => {
      toast.success(`Materials populated from Excel — ${updated.cad_part_materials.length} part(s) assigned`)
      qc.setQueryData(['product', id], updated)
      setMaterialsDirty(false)
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed to reassign materials'),
  })

  // ── Render Positions ───────────────────────────────────────────────────────

  const [showPositions, setShowPositions] = useState(false)
  const [positionForm, setPositionForm] = useState<{ name: string; rotation_x: number; rotation_y: number; rotation_z: number } | null>(null)
  const [editingPositionId, setEditingPositionId] = useState<string | null>(null)

  const addPositionMut = useMutation({
    mutationFn: (data: { name: string; rotation_x: number; rotation_y: number; rotation_z: number }) =>
      createRenderPosition(id!, { ...data, sort_order: (product?.render_positions?.length ?? 0) }),
    onSuccess: () => {
      toast.success('Position added')
      qc.invalidateQueries({ queryKey: ['product', id] })
      setPositionForm(null)
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed to add position'),
  })

  const updatePositionMut = useMutation({
    mutationFn: ({ posId, data }: { posId: string; data: Partial<RenderPosition> }) =>
      updateRenderPosition(id!, posId, data),
    onSuccess: () => {
      toast.success('Position updated')
      qc.invalidateQueries({ queryKey: ['product', id] })
      setEditingPositionId(null)
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed to update'),
  })

  const deletePositionMut = useMutation({
    mutationFn: (posId: string) => deleteRenderPosition(id!, posId),
    onSuccess: () => {
      toast.success('Position deleted')
      qc.invalidateQueries({ queryKey: ['product', id] })
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed to delete'),
  })

  const exportGltfColoredMut = useMutation({
    mutationFn: () => exportGltfColored(product?.cad_file_id!),
    onError: () => toast.error('GLB export failed'),
  })

  const [editPositionDraft, setEditPositionDraft] = useState<Partial<RenderPosition>>({})

  const POSITION_PRESETS = [
    { label: 'Beauty', rx: 0, ry: 0, rz: 0 },
    { label: '3/4 Front', rx: -15, ry: 45, rz: 0 },
    { label: '3/4 Back', rx: -15, ry: -135, rz: 0 },
  ]

  const onDrop = useCallback(
    (files: File[]) => { if (files[0]) cadUploadMut.mutate(files[0]) },
    [cadUploadMut],
  )
  const { getRootProps, getInputProps, isDragActive } = useDropzone({
    onDrop,
    accept: { 'application/octet-stream': ['.stp', '.step'] },
    multiple: false,
  })

  if (isLoading) return <div className="p-8 text-content-muted">Loading…</div>
  if (!product) return <div className="p-8 text-red-500">Product not found</div>

  return (
    <div className="p-8">
      {/* Back */}
      <Link to="/products" className="inline-flex items-center gap-1 text-sm text-content-secondary hover:text-content mb-4">
        <ArrowLeft size={15} /> Products
      </Link>

      {/* Header */}
      <div className="card p-5 mb-4">
        <div className="flex items-start justify-between gap-4">
          <div className="flex-1 min-w-0">
            <div className="flex items-center gap-2 mb-1">
              <span className="text-xs font-mono bg-surface-muted text-content-secondary px-2 py-0.5 rounded">
                {product.pim_id}
              </span>
              {product.category_key && (
                <span className="text-xs px-2 py-0.5 rounded-full bg-accent-light text-accent font-medium">
                  {product.category_key}
                </span>
              )}
              <span className={`text-xs px-2 py-0.5 rounded-full ${
                product.is_active ? 'bg-status-success-bg text-status-success-text' : 'bg-surface-muted text-content-muted'
              }`}>
                {product.is_active ? 'active' : 'inactive'}
              </span>
            </div>

            {editMode ? (
              <input
                className="text-xl font-bold border-b-2 border-accent w-full bg-transparent focus:outline-none"
                value={draft.name ?? product.name ?? ''}
                onChange={(e) => setDraft({ ...draft, name: e.target.value })}
              />
            ) : (
              <h1 className="text-xl font-bold text-content">
                {product.name || <span className="text-content-muted italic">No name</span>}
              </h1>
            )}
          </div>

          {isPrivileged && (
            <div className="flex items-center gap-2 shrink-0">
              {editMode ? (
                <>
                  <button
                    className="btn-primary text-sm"
                    onClick={() => updateMut.mutate(draft)}
                    disabled={updateMut.isPending}
                  >
                    <Save size={14} /> Save
                  </button>
                  <button
                    className="btn-secondary text-sm"
                    onClick={() => { setEditMode(false); setDraft({}) }}
                  >
                    <X size={14} /> Cancel
                  </button>
                </>
              ) : (
                <button
                  className="btn-secondary text-sm"
                  onClick={() => setEditMode(true)}
                >
                  <Pencil size={14} /> Edit
                </button>
              )}
            </div>
          )}
        </div>
      </div>

      {/* Meta fields */}
      <div className="card p-5 mb-4">
        <h2 className="text-sm font-semibold text-content-secondary mb-3">Product Details</h2>
        <div className="grid grid-cols-2 gap-3">
          {META_FIELDS.map(({ key, label }) => (
            <div key={key}>
              <label className="block text-xs text-content-muted mb-0.5">{label}</label>
              {editMode ? (
                <input
                  className="w-full px-2 py-1.5 border border-border-default rounded text-sm focus:outline-none focus:ring-1 focus:ring-accent"
                  value={(draft[key] as string) ?? (product[key] as string) ?? ''}
                  onChange={(e) => setDraft({ ...draft, [key]: e.target.value || null })}
                />
              ) : (
                <p className="text-sm text-content">
                  {(product[key] as string) || <span className="text-content-muted">—</span>}
                </p>
              )}
            </div>
          ))}
          <div className="col-span-2">
            <label className="block text-xs text-content-muted mb-0.5">Notes</label>
            {editMode ? (
              <textarea
                rows={2}
                className="w-full px-2 py-1.5 border border-border-default rounded text-sm focus:outline-none focus:ring-1 focus:ring-accent"
                value={(draft.notes as string) ?? product.notes ?? ''}
                onChange={(e) => setDraft({ ...draft, notes: e.target.value || null })}
              />
            ) : (
              <p className="text-sm text-content">{product.notes || <span className="text-content-muted">—</span>}</p>
            )}
          </div>
          {product.cad_mesh_attributes?.dimensions_mm && (
            <div className="col-span-2 mt-1 pt-2 border-t border-border-light">
              <label className="block text-xs text-content-muted mb-0.5 flex items-center gap-1">
                <Ruler size={11} /> Dimensions <span className="text-content-muted/60 font-normal">(from CAD)</span>
              </label>
              <p className="text-sm text-content font-mono">
                {product.cad_mesh_attributes.dimensions_mm.x.toFixed(1)} × {product.cad_mesh_attributes.dimensions_mm.y.toFixed(1)} × {product.cad_mesh_attributes.dimensions_mm.z.toFixed(1)} mm
              </p>
            </div>
          )}
        </div>

        {editMode && isPrivileged && (
          <div className="mt-3 pt-3 border-t border-border-light flex items-center gap-2">
            <label className="text-sm text-content-secondary">Active</label>
            <input
              type="checkbox"
              checked={(draft.is_active ?? product.is_active)}
              onChange={(e) => setDraft({ ...draft, is_active: e.target.checked })}
            />
          </div>
        )}
      </div>

      {/* Excel Source Row (collapsible) */}
      <div className="card mb-4">
        <button
          className="w-full flex items-center gap-2 p-4 text-sm font-semibold text-content-secondary hover:bg-surface-hover rounded-lg"
          onClick={() => setShowExcelRow((v) => !v)}
        >
          {showExcelRow ? <ChevronDown size={15} /> : <ChevronRight size={15} />}
          Excel Source Row
        </button>
        {showExcelRow && (
          <div className="px-4 pb-4 overflow-x-auto">
            <table className="text-xs border-collapse min-w-max">
              <thead>
                <tr className="bg-surface-alt">
                  <th className="border border-border-default px-2 py-1 text-left font-medium text-content-muted whitespace-nowrap">Ebene 1</th>
                  <th className="border border-border-default px-2 py-1 text-left font-medium text-content-muted whitespace-nowrap">Ebene 2</th>
                  <th className="border border-border-default px-2 py-1 text-left font-medium text-content-muted whitespace-nowrap">Baureihe</th>
                  <th className="border border-border-default px-2 py-1 text-left font-medium text-content-muted whitespace-nowrap">PIM-ID</th>
                  <th className="border border-border-default px-2 py-1 text-left font-medium text-content-muted whitespace-nowrap">Produkt-Baureihe</th>
                  <th className="border border-border-default px-2 py-1 text-left font-medium text-content-muted whitespace-nowrap">Gew. Produkt</th>
                  <th className="border border-border-default px-2 py-1 text-left font-medium text-content-muted whitespace-nowrap">Name CAD-Modell</th>
                  <th className="border border-border-default px-2 py-1 text-left font-medium text-content-muted whitespace-nowrap">Bildnummer</th>
                  <th className="border border-border-default px-2 py-1 text-left font-medium text-content-muted whitespace-nowrap">Lagertyp</th>
                  <th className="border border-border-default px-2 py-1 text-left font-medium text-content-muted whitespace-nowrap">Medias</th>
                  {product.components.map((c: any, i: number) => (
                    <th key={i} className="border border-border-default px-2 py-1 text-left font-medium text-content-muted whitespace-nowrap" colSpan={2}>
                      {c.component_type || `Part ${i + 1}`}
                    </th>
                  ))}
                </tr>
                {product.components.length > 0 && (
                  <tr className="bg-surface-alt">
                    {/* Empty cells for the 10 fixed columns */}
                    {Array.from({ length: 10 }).map((_, i) => (
                      <th key={i} className="border border-border-default px-2 py-0.5" />
                    ))}
                    {product.components.map((_: any, i: number) => (
                      <Fragment key={i}>
                        <th className="border border-border-default px-2 py-0.5 text-left font-normal text-content-muted whitespace-nowrap">Part</th>
                        <th className="border border-border-default px-2 py-0.5 text-left font-normal text-content-muted whitespace-nowrap">Material</th>
                      </Fragment>
                    ))}
                  </tr>
                )}
              </thead>
              <tbody>
                <tr>
                  <td className="border border-border-default px-2 py-1 whitespace-nowrap">{product.ebene1 || '—'}</td>
                  <td className="border border-border-default px-2 py-1 whitespace-nowrap">{product.ebene2 || '—'}</td>
                  <td className="border border-border-default px-2 py-1 whitespace-nowrap">{product.baureihe || '—'}</td>
                  <td className="border border-border-default px-2 py-1 whitespace-nowrap font-mono">{product.pim_id}</td>
                  <td className="border border-border-default px-2 py-1 whitespace-nowrap">{product.produkt_baureihe || '—'}</td>
                  <td className="border border-border-default px-2 py-1 whitespace-nowrap">{product.name || '—'}</td>
                  <td className="border border-border-default px-2 py-1 whitespace-nowrap">{product.name_cad_modell || '—'}</td>
                  <td className="border border-border-default px-2 py-1 whitespace-nowrap">{product.gewuenschte_bildnummer || '—'}</td>
                  <td className="border border-border-default px-2 py-1 whitespace-nowrap">{product.lagertyp || '—'}</td>
                  <td className="border border-border-default px-2 py-1 whitespace-nowrap">{product.medias_rendering === true ? 'Ja' : product.medias_rendering === false ? 'Nein' : '—'}</td>
                  {product.components.map((c: any, i: number) => (
                    <Fragment key={i}>
                      <td className="border border-border-default px-2 py-1 whitespace-nowrap">{c.part_name || '—'}</td>
                      <td className="border border-border-default px-2 py-1 whitespace-nowrap">{c.material || '—'}</td>
                    </Fragment>
                  ))}
                </tr>
              </tbody>
            </table>
            {product.source_excel && (
              <p className="text-xs text-content-muted mt-2">Source: {product.source_excel}</p>
            )}
          </div>
        )}
      </div>

      {/* CAD File section */}
      <div className="card p-5 mb-4">
        <div className="flex items-center justify-between mb-3">
          <h2 className="text-sm font-semibold text-content-secondary">CAD File</h2>
          <CadStatusBadge status={product.processing_status} />
        </div>

        {product.cad_file_id ? (
          <div className="space-y-3">
            {/* Inline 3D Viewer */}
            <InlineCadViewer
              cadFileId={product.cad_file_id}
              thumbnailUrl={product.render_image_url || product.thumbnail_url}
            />

            {/* Action buttons */}
            <div className="flex flex-wrap gap-2">
              {isPrivileged && (
                <>
                  <div {...getRootProps()} className="cursor-pointer">
                    <input {...getInputProps()} />
                    <button className="btn-secondary text-xs" disabled={cadUploadMut.isPending}>
                      <Upload size={12} />
                      {cadUploadMut.isPending ? 'Uploading…' : 'Re-upload STEP'}
                    </button>
                  </div>
                  <button
                    className="btn-secondary text-xs"
                    onClick={() => regenerateMut.mutate()}
                    disabled={regenerateMut.isPending}
                    title="Re-render the thumbnail using the current part materials and the active thumbnail renderer — keeps the existing STEP parse data"
                  >
                    <RotateCcw size={12} />
                    {regenerateMut.isPending ? 'Queuing…' : 'Regenerate thumbnail'}
                  </button>
                  <button
                    className="btn-secondary text-xs"
                    onClick={() => reprocessMut.mutate()}
                    disabled={reprocessMut.isPending}
                    title="Re-run full STEP processing: re-parse part names, regenerate thumbnail and glTF. Use this after re-uploading a STEP file."
                  >
                    <RotateCcw size={12} />
                    {reprocessMut.isPending ? 'Queuing…' : 'Re-process STEP'}
                  </button>
                  <button
                    className="btn-secondary text-xs"
                    onClick={() => navigate(`/cad/${product.cad_file_id}`)}
                    title="Open interactive 3D viewer in full screen"
                  >
                    <Cuboid size={12} />
                    View Full Screen
                  </button>
                  <button
                    className="btn-secondary text-xs"
                    onClick={() =>
                      generateGltfGeometry(product.cad_file_id!)
                        .then(() => toast.info('GLB geometry export queued'))
                        .catch(() => toast.error('Failed to queue GLB export'))
                    }
                    title="Export geometry-only GLB from cached STL (trimesh, no Blender). Requires STL cache."
                  >
                    <Download size={12} />
                    Generate GLB
                  </button>
                  {product?.processing_status === 'completed' && (
                    <button
                      onClick={() => exportGltfColoredMut.mutate()}
                      disabled={exportGltfColoredMut.isPending}
                      className="btn-secondary flex items-center gap-2 disabled:opacity-40 text-xs"
                      title="Download GLB with PBR colors from material assignments"
                    >
                      <Download size={12} />
                      {exportGltfColoredMut.isPending ? 'Exporting…' : 'GLB + Colors'}
                    </button>
                  )}
                  <div className="flex items-center gap-1 pl-1 border-l border-border-light">
                    <p className="text-xs text-content-muted font-medium">STL:</p>
                    {(['low', 'high'] as const).map((q) =>
                      product.stl_cached.includes(q) ? (
                        <button
                          key={q}
                          className="btn-secondary text-xs"
                          onClick={() => downloadStl(product.cad_file_id!, q, product.name_cad_modell || product.name || undefined)}
                          title={q === 'low' ? 'Coarse mesh, tolerance 0.3 mm' : 'Fine mesh, tolerance 0.01 mm'}
                        >
                          <Download size={12} /> {q === 'low' ? 'Low' : 'High'}
                        </button>
                      ) : (
                        <button
                          key={q}
                          className="btn-secondary text-xs opacity-60"
                          onClick={() => generateStl(product.cad_file_id!, q).then(() => toast.info(`STL generation queued (${q} quality)`)).catch(() => toast.error('Failed to queue STL generation'))}
                          title={`${q === 'low' ? 'Low' : 'High'}-quality STL not cached — click to generate`}
                        >
                          <RefreshCw size={12} /> Gen {q === 'low' ? 'Low' : 'High'}
                        </button>
                      )
                    )}
                  </div>
                </>
              )}
              {!isPrivileged && product.cad_file_id && (
                <button
                  className="btn-secondary text-xs"
                  onClick={() => navigate(`/cad/${product.cad_file_id}`)}
                  title="Open interactive 3D viewer in full screen"
                >
                  <Cuboid size={12} />
                  View Full Screen
                </button>
              )}
            </div>

            {/* Mesh attributes */}
            {(() => {
              // Prefer cad_mesh_attributes (reliably populated by API) over cad_file.mesh_attributes
              const mesh_attrs: Record<string, unknown> = (product.cad_mesh_attributes ?? product.cad_file?.mesh_attributes) as Record<string, unknown> ?? {}
              if (Object.keys(mesh_attrs).length === 0) return null
              const dims = mesh_attrs.dimensions_mm as { x: number; y: number; z: number } | undefined
              const bbox = mesh_attrs.bbox as { x?: number; y?: number; z?: number } | undefined
              return (
                <div className="mt-3 p-3 rounded-md border border-border-default bg-surface-alt">
                  <p className="text-xs font-semibold text-content-muted mb-2 flex items-center gap-1">
                    <Ruler size={12} />
                    Geometry
                  </p>
                  <div className="grid grid-cols-2 gap-x-4 gap-y-1 text-xs">
                    {dims != null && (
                      <>
                        <span className="text-content-muted">Dimensions</span>
                        <span>{dims.x.toFixed(1)} × {dims.y.toFixed(1)} × {dims.z.toFixed(1)} mm</span>
                      </>
                    )}
                    {dims == null && bbox != null && (
                      <>
                        <span className="text-content-muted">BBox</span>
                        <span>
                          {bbox.x?.toFixed(1)} × {bbox.y?.toFixed(1)} × {bbox.z?.toFixed(1)} mm
                        </span>
                      </>
                    )}
                    {(mesh_attrs.volume_mm3 as number | undefined) != null && (
                      <>
                        <span className="text-content-muted">Volume</span>
                        <span>{((mesh_attrs.volume_mm3 as number) / 1000).toFixed(2)} cm³</span>
                      </>
                    )}
                    {(mesh_attrs.surface_area_mm2 as number | undefined) != null && (
                      <>
                        <span className="text-content-muted">Surface</span>
                        <span>{((mesh_attrs.surface_area_mm2 as number) / 100).toFixed(1)} cm²</span>
                      </>
                    )}
                    {mesh_attrs.suggested_smooth_angle !== undefined && (
                      <>
                        <span className="text-content-muted">Sharp angle</span>
                        <span>{mesh_attrs.suggested_smooth_angle as number}°</span>
                      </>
                    )}
                  </div>
                </div>
              )
            })()}

            {/* Material assignments */}
            {isPrivileged && (
              <div className="pt-3 border-t border-border-light">
                <div className="flex items-center justify-between mb-2">
                  <h3 className="text-xs font-semibold text-content-secondary">Part Materials</h3>
                  <div className="flex items-center gap-2">
                    {(product.cad_parsed_objects?.length ?? 0) > 0 && product.components.length > 0 && (
                      <button
                        className="btn-secondary text-xs"
                        onClick={() => reassignMut.mutate()}
                        disabled={reassignMut.isPending}
                        title="Map Excel component materials to CAD parts by position (index-based)"
                      >
                        <Wand2 size={11} />
                        {reassignMut.isPending ? 'Assigning…' : 'Populate from Excel'}
                      </button>
                    )}
                    {materialsDirty && (
                      <button
                        className="btn-primary text-xs"
                        onClick={() => saveMaterialsMut.mutate()}
                        disabled={saveMaterialsMut.isPending}
                      >
                        <Save size={11} />
                        {saveMaterialsMut.isPending ? 'Saving…' : 'Save & Regenerate'}
                      </button>
                    )}
                  </div>
                </div>
                {materialRows.length === 0 ? (
                  <p className="text-xs text-content-muted">
                    {product.processing_status === 'completed'
                      ? 'No parts found in STEP file.'
                      : product.processing_status === 'processing' || product.processing_status === 'pending'
                      ? 'STEP file is being processed — part list will appear when complete.'
                      : 'Click "Re-process STEP" to extract part names from the file.'}
                  </p>
                ) : (
                  <div className="space-y-1.5">
                    {materialRows.map((row, i) => (
                      <div key={i} className="flex items-center gap-2">
                        <span className="text-xs text-content-secondary w-40 truncate shrink-0" title={row.part_name}>
                          {row.part_name}
                        </span>
                        <div className="flex-1">
                          <MaterialInput
                            value={row.material}
                            onChange={(v) => {
                              const updated = [...materialRows]
                              updated[i] = { ...updated[i], material: v }
                              setMaterialRows(updated)
                              setMaterialsDirty(true)
                            }}
                            library={materialLibrary}
                            missing={!row.material.trim()}
                            onOpenWizard={() => {
                              setWizardTargetIdx(i)
                              setWizardOpen(true)
                            }}
                          />
                        </div>
                      </div>
                    ))}
                  </div>
                )}
              </div>
            )}
          </div>
        ) : (
          isPrivileged ? (
            <div
              {...getRootProps()}
              className={`border-2 border-dashed rounded-lg p-8 text-center cursor-pointer transition-colors ${
                isDragActive
                  ? ''
                  : 'border-border-default hover:border-accent'
              }`}
              style={isDragActive ? { borderColor: 'var(--color-accent)', backgroundColor: 'rgba(0,0,0,0.03)' } : undefined}
            >
              <input {...getInputProps()} />
              {cadUploadMut.isPending ? (
                <div className="text-content-secondary">
                  <div className="animate-spin w-6 h-6 border-2 border-accent border-t-transparent rounded-full mx-auto mb-2" />
                  Uploading…
                </div>
              ) : (
                <>
                  <Box size={32} className="text-content-muted mx-auto mb-2" />
                  <p className="text-content-secondary font-medium text-sm">
                    {isDragActive ? 'Drop the STEP file here' : 'Upload STEP file'}
                  </p>
                  <p className="text-content-muted text-xs mt-1">.stp / .step</p>
                </>
              )}
            </div>
          ) : (
            <p className="text-sm text-content-muted">No STEP file uploaded</p>
          )
        )}
      </div>

      {/* Renders gallery */}
      <div className="card p-5 mb-4">

        {/* ── Gallery header ──────────────────────────────────────── */}
        <div className="flex items-center gap-2 mb-3 min-h-[26px]">
          <h2 className="text-sm font-semibold text-content-secondary flex items-center gap-2">
            <Image size={15} /> Renders
            {renders.length > 0 && (
              <span className="text-xs font-normal text-content-muted">({renders.length})</span>
            )}
          </h2>

          {renders.length > 0 && (
            <div className="ml-auto flex items-center gap-2">
              {!selectMode ? (
                /* Normal mode: Download all + Select button */
                <>
                  <button
                    disabled={downloadLoading}
                    onClick={handleDownloadAll}
                    className="text-xs px-2.5 py-1 rounded border border-border-default text-content-muted hover:border-accent hover:text-accent transition-colors flex items-center gap-1 disabled:opacity-50"
                  >
                    {downloadLoading
                      ? <span className="w-3 h-3 border border-current border-t-transparent rounded-full animate-spin" />
                      : <Download size={11} />
                    }
                    {filterOutputType ? `Download (${filteredRenders.length})` : 'Download all'}
                  </button>
                  <button
                    onClick={() => setSelectMode(true)}
                    className="text-xs px-2.5 py-1 rounded border border-border-default text-content-muted hover:border-accent hover:text-accent transition-colors"
                  >
                    Select
                  </button>
                </>
              ) : !batchConfirm ? (
                /* Select mode: count + Download + Delete + Cancel */
                <>
                  <span className="text-xs text-content-muted">
                    {selectedIds.size} of {filteredRenders.length} selected
                  </span>
                  <button
                    onClick={() => {
                      if (selectedIds.size === filteredRenders.length) setSelectedIds(new Set())
                      else setSelectedIds(new Set(filteredRenders.map(r => r.order_line_id)))
                    }}
                    className="text-xs px-2 py-0.5 rounded border border-border-default text-content-muted hover:bg-surface-hover transition-colors"
                  >
                    {selectedIds.size === filteredRenders.length ? 'Deselect all' : 'Select all'}
                  </button>
                  {selectedIds.size > 0 && (
                    <button
                      disabled={downloadLoading}
                      onClick={handleDownloadSelected}
                      className="text-xs px-2.5 py-1 rounded bg-accent-light border border-border-default text-accent hover:bg-surface-hover transition-colors flex items-center gap-1 disabled:opacity-50"
                    >
                      {downloadLoading
                        ? <span className="w-3 h-3 border border-current border-t-transparent rounded-full animate-spin" />
                        : <Download size={11} />
                      }
                      Download ({selectedIds.size})
                    </button>
                  )}
                  {isPrivileged && selectedIds.size > 0 && (
                    <button
                      onClick={() => setBatchConfirm(true)}
                      className="text-xs px-2.5 py-1 rounded bg-red-50 border border-red-200 text-red-600 hover:bg-red-100 transition-colors flex items-center gap-1"
                    >
                      <Trash2 size={11} /> Delete ({selectedIds.size})
                    </button>
                  )}
                  <button
                    onClick={exitSelectMode}
                    className="text-xs px-2.5 py-1 rounded border border-border-default text-content-muted hover:bg-surface-hover transition-colors"
                  >
                    Cancel
                  </button>
                </>
              ) : (
                /* Confirm batch delete */
                <>
                  <span className="text-xs text-red-600 font-medium">
                    Delete {selectedIds.size} render{selectedIds.size > 1 ? 's' : ''} permanently?
                  </span>
                  <button
                    disabled={batchLoading}
                    onClick={() => setBatchConfirm(false)}
                    className="text-xs px-2.5 py-1 rounded border border-border-default text-content-muted hover:bg-surface-hover disabled:opacity-50 transition-colors"
                  >
                    Cancel
                  </button>
                  <button
                    disabled={batchLoading}
                    onClick={handleBatchDelete}
                    className="text-xs px-2.5 py-1 rounded bg-red-500 text-white hover:bg-red-600 disabled:opacity-50 transition-colors flex items-center gap-1"
                  >
                    {batchLoading && (
                      <span className="w-3 h-3 border border-white border-t-transparent rounded-full animate-spin" />
                    )}
                    <Trash2 size={11} /> Delete
                  </button>
                </>
              )}
            </div>
          )}
        </div>

        {/* ── Output-type filter pills ────────────────────────── */}
        {outputTypeNames.length >= 2 && (
          <div className="flex items-center gap-2 mb-3 flex-wrap">
            <Filter size={13} className="text-content-muted shrink-0" />
            <button
              onClick={() => setFilterOutputType(null)}
              className={`text-xs px-2.5 py-1 rounded-full border transition-colors ${
                filterOutputType === null
                  ? 'text-white'
                  : 'border-border-default text-content-muted hover:border-accent hover:text-accent'
              }`}
              style={filterOutputType === null ? { backgroundColor: 'var(--color-accent)', borderColor: 'var(--color-accent)' } : undefined}
            >
              All ({renders.length})
            </button>
            {outputTypeNames.map(name => (
              <button
                key={name}
                onClick={() => setFilterOutputType(filterOutputType === name ? null : name)}
                className={`text-xs px-2.5 py-1 rounded-full border transition-colors ${
                  filterOutputType === name
                    ? 'text-white'
                    : 'border-border-default text-content-muted hover:border-accent hover:text-accent'
                }`}
                style={filterOutputType === name ? { backgroundColor: 'var(--color-accent)', borderColor: 'var(--color-accent)' } : undefined}
              >
                {name} ({renders.filter(r => r.output_type_name === name).length})
              </button>
            ))}
          </div>
        )}

        {/* ── Grid ───────────────────────────────────────────────── */}
        {filteredRenders.length === 0 ? (
          <p className="text-sm text-content-muted">
            {filterOutputType ? 'No renders match the selected filter' : 'No renders yet'}
          </p>
        ) : (
          <div className="grid grid-cols-2 lg:grid-cols-3 gap-3">
            {filteredRenders.map((r) => {
              const isConfirming = pendingDelete === r.order_line_id
              const isDeleting = deleteRenderMut.isPending && isConfirming
              const isSelected = selectedIds.has(r.order_line_id)
              return (
                <div
                  key={r.order_line_id}
                  onClick={() => selectMode && toggleSelect(r.order_line_id)}
                  className={`border rounded-lg overflow-hidden bg-surface-alt flex flex-col transition-all ${
                    selectMode ? 'cursor-pointer' : ''
                  } ${
                    isSelected
                      ? 'border-blue-400 ring-2 ring-blue-300'
                      : 'border-border-default'
                  }`}
                >
                  {/* ── Media area ───────────────────────────────── */}
                  {r.is_video ? (
                    <div className="relative">
                      <video
                        src={r.render_url}
                        controls
                        className="w-full aspect-video object-contain bg-black"
                        onClick={(e) => selectMode && e.preventDefault()}
                      />
                      {/* Select mode checkbox overlay for videos */}
                      {selectMode && (
                        <div className="absolute top-2 left-2 pointer-events-none">
                          <div className={`w-5 h-5 rounded border-2 flex items-center justify-center ${
                            isSelected ? 'bg-blue-500 border-blue-500' : 'bg-surface border-border-default'
                          }`}>
                            {isSelected && <span className="text-white text-xs font-bold">✓</span>}
                          </div>
                        </div>
                      )}
                    </div>
                  ) : (
                    <div className="relative group">
                      <a
                        href={r.render_url}
                        target="_blank"
                        rel="noopener noreferrer"
                        onClick={(e) => selectMode && e.preventDefault()}
                      >
                        <img
                          src={r.render_url}
                          alt={r.output_type_name || 'Render'}
                          className={`w-full aspect-square object-contain transition-opacity ${
                            isConfirming ? 'opacity-30' : isSelected ? 'opacity-80' : 'hover:opacity-90'
                          }`}
                        />
                      </a>

                      {/* Select mode: checkbox top-left */}
                      {selectMode && (
                        <div className="absolute top-2 left-2 pointer-events-none">
                          <div className={`w-5 h-5 rounded border-2 flex items-center justify-center shadow-sm ${
                            isSelected ? 'bg-blue-500 border-blue-500' : 'bg-surface border-border-default'
                          }`}>
                            {isSelected && <span className="text-white text-xs font-bold">✓</span>}
                          </div>
                        </div>
                      )}

                      {/* Normal mode: hover delete trigger */}
                      {isPrivileged && !selectMode && !isConfirming && (
                        <button
                          className="absolute top-2 right-2 p-1.5 rounded-full bg-surface text-content-muted opacity-0 group-hover:opacity-100 hover:bg-red-50 hover:text-red-500 transition-all shadow-sm"
                          title="Delete render"
                          onClick={(e) => { e.stopPropagation(); setPendingDelete(r.order_line_id) }}
                        >
                          <Trash2 size={14} />
                        </button>
                      )}

                      {/* Confirmation overlay */}
                      {isPrivileged && !selectMode && isConfirming && (
                        <div
                          className="absolute inset-0 flex flex-col items-center justify-center gap-2 p-3"
                          onClick={(e) => e.stopPropagation()}
                        >
                          <Trash2 size={20} className="text-red-400" />
                          <p className="text-content text-xs font-semibold text-center">Delete this render?</p>
                          <p className="text-content-secondary text-xs text-center leading-tight">File will be permanently removed from disk.</p>
                          <div className="flex gap-2 mt-1">
                            <button
                              disabled={isDeleting}
                              onClick={() => setPendingDelete(null)}
                              className="px-3 py-1 text-xs rounded border border-border-default bg-surface text-content-secondary hover:bg-surface-hover disabled:opacity-50"
                            >
                              Cancel
                            </button>
                            <button
                              disabled={isDeleting}
                              onClick={() => deleteRenderMut.mutate(r.order_line_id)}
                              className="px-3 py-1 text-xs rounded bg-red-500 text-white hover:bg-red-600 disabled:opacity-50 flex items-center gap-1"
                            >
                              {isDeleting
                                ? <span className="w-3 h-3 border border-white border-t-transparent rounded-full animate-spin inline-block" />
                                : <Trash2 size={11} />
                              }
                              Delete
                            </button>
                          </div>
                        </div>
                      )}
                    </div>
                  )}

                  {/* ── Footer ───────────────────────────────────── */}
                  <div className="px-2.5 py-2 space-y-1.5 mt-auto">
                    <div className="flex items-center gap-1.5 flex-wrap">
                      {r.output_type_name && (
                        <span className="text-xs px-1.5 py-0.5 rounded bg-surface-muted text-content-secondary font-medium">
                          {r.output_type_name}
                        </span>
                      )}
                      {r.render_backend && (
                        <span className={`text-xs px-1.5 py-0.5 rounded font-medium ${
                          r.render_backend === 'flamenco' ? 'bg-status-warning-bg text-status-warning-text' : 'bg-status-info-bg text-status-info-text'
                        }`}>
                          {r.render_backend}
                        </span>
                      )}
                    </div>

                    <div className="flex items-center justify-between text-xs text-content-muted">
                      <span className="flex items-center gap-1.5">
                        {r.order_number && <span>{r.order_number}</span>}
                        {r.completed_at && <span>{new Date(r.completed_at).toLocaleDateString()}</span>}
                      </span>
                      {!selectMode && (
                        <span className="flex items-center gap-1" onClick={(e) => e.stopPropagation()}>
                          <a
                            href={r.render_url}
                            download
                            className="p-1 rounded text-content-muted hover:text-accent hover:bg-accent-light transition-colors"
                            title="Download"
                          >
                            <Download size={13} />
                          </a>
                          {isPrivileged && r.is_video && !isConfirming && (
                            <button
                              className="p-1 rounded text-content-muted hover:text-red-500 hover:bg-red-50 transition-colors"
                              title="Delete render"
                              onClick={() => setPendingDelete(r.order_line_id)}
                            >
                              <Trash2 size={13} />
                            </button>
                          )}
                        </span>
                      )}
                    </div>

                    {/* Video inline confirmation */}
                    {isPrivileged && !selectMode && r.is_video && isConfirming && (
                      <div
                        className="border border-red-200 rounded-md bg-red-50 px-2.5 py-2 flex items-center justify-between gap-2"
                        onClick={(e) => e.stopPropagation()}
                      >
                        <span className="text-xs text-red-700 font-medium">Delete permanently?</span>
                        <div className="flex gap-1.5">
                          <button
                            disabled={isDeleting}
                            onClick={() => setPendingDelete(null)}
                            className="px-2 py-0.5 text-xs rounded border border-border-default bg-surface text-content-secondary hover:bg-surface-hover disabled:opacity-50"
                          >
                            Cancel
                          </button>
                          <button
                            disabled={isDeleting}
                            onClick={() => deleteRenderMut.mutate(r.order_line_id)}
                            className="px-2 py-0.5 text-xs rounded bg-red-500 text-white hover:bg-red-600 disabled:opacity-50 flex items-center gap-1"
                          >
                            {isDeleting && <span className="w-3 h-3 border border-white border-t-transparent rounded-full animate-spin inline-block" />}
                            Delete
                          </button>
                        </div>
                      </div>
                    )}
                  </div>
                </div>
              )
            })}
          </div>
        )}
      </div>

      {/* Render Positions */}
      {isPrivileged && (
        <div className="card mb-4">
          <button
            className="w-full flex items-center gap-2 p-4 text-sm font-semibold text-content-secondary hover:bg-surface-hover rounded-lg"
            onClick={() => setShowPositions((v) => !v)}
          >
            {showPositions ? <ChevronDown size={15} /> : <ChevronRight size={15} />}
            Render Positions
            <span className="text-xs font-normal text-content-muted ml-1">
              ({product.render_positions?.length ?? 0})
            </span>
          </button>
          {showPositions && (
            <div className="px-4 pb-4 space-y-3">
              {/* Preset buttons */}
              <div className="flex items-center gap-2 pt-1">
                <span className="text-xs text-content-muted">Presets:</span>
                {POSITION_PRESETS.map((preset) => (
                  <button
                    key={preset.label}
                    className="text-xs px-2 py-1 rounded border border-border-default text-content-secondary hover:border-accent hover:text-accent transition-colors"
                    onClick={() => setPositionForm({ name: preset.label, rotation_x: preset.rx, rotation_y: preset.ry, rotation_z: preset.rz })}
                  >
                    {preset.label}
                  </button>
                ))}
                <button
                  className="ml-auto btn-secondary text-xs"
                  onClick={() => setPositionForm({ name: '', rotation_x: 0, rotation_y: 0, rotation_z: 0 })}
                >
                  <Plus size={12} /> Add Position
                </button>
              </div>

              {/* Existing positions list */}
              {(product.render_positions?.length ?? 0) === 0 && !positionForm && (
                <p className="text-xs text-content-muted py-2">No positions defined. Click "Add Position" or a preset above.</p>
              )}
              {(product.render_positions ?? []).map((pos) => (
                <div key={pos.id} className="border border-border-default rounded-lg p-3">
                  {editingPositionId === pos.id ? (
                    <div className="space-y-2">
                      <div className="flex items-center gap-2">
                        <input
                          className="flex-1 px-2 py-1 border border-border-default rounded text-sm focus:outline-none focus:ring-1 focus:ring-accent"
                          placeholder="Name"
                          value={editPositionDraft.name ?? pos.name}
                          onChange={(e) => setEditPositionDraft((d) => ({ ...d, name: e.target.value }))}
                        />
                        <label className="text-xs text-content-muted flex items-center gap-1">
                          <input
                            type="checkbox"
                            checked={editPositionDraft.is_default ?? pos.is_default}
                            onChange={(e) => setEditPositionDraft((d) => ({ ...d, is_default: e.target.checked }))}
                          />
                          Default
                        </label>
                      </div>
                      <div className="flex items-center gap-2">
                        {(['rotation_x', 'rotation_y', 'rotation_z'] as const).map((axis) => (
                          <label key={axis} className="flex items-center gap-1 text-xs text-content-secondary">
                            {axis.replace('rotation_', '').toUpperCase()}°
                            <input
                              type="number"
                              className="w-16 px-1.5 py-1 border border-border-default rounded text-xs focus:outline-none focus:ring-1 focus:ring-accent"
                              value={editPositionDraft[axis] ?? pos[axis]}
                              onChange={(e) => setEditPositionDraft((d) => ({ ...d, [axis]: parseFloat(e.target.value) || 0 }))}
                            />
                          </label>
                        ))}
                      </div>
                      <div className="flex gap-2">
                        <button
                          className="btn-primary text-xs"
                          onClick={() => updatePositionMut.mutate({ posId: pos.id, data: editPositionDraft })}
                          disabled={updatePositionMut.isPending}
                        >
                          <Save size={11} /> Save
                        </button>
                        <button className="btn-secondary text-xs" onClick={() => { setEditingPositionId(null); setEditPositionDraft({}) }}>
                          <X size={11} /> Cancel
                        </button>
                      </div>
                    </div>
                  ) : (
                    <div className="flex items-center gap-3">
                      <div className="flex-1 min-w-0">
                        <div className="flex items-center gap-2">
                          <span className="text-sm font-medium text-content">{pos.name}</span>
                          {pos.is_default && (
                            <span className="text-xs px-1.5 py-0.5 rounded-full bg-accent-light text-accent font-medium">default</span>
                          )}
                        </div>
                        <span className="text-xs text-content-muted">
                          X: {pos.rotation_x}° · Y: {pos.rotation_y}° · Z: {pos.rotation_z}°
                        </span>
                      </div>
                      <button
                        className="btn-secondary text-xs"
                        onClick={() => { setEditingPositionId(pos.id); setEditPositionDraft({}) }}
                      >
                        <Pencil size={11} /> Edit
                      </button>
                      <button
                        className="text-content-muted hover:text-red-500 transition-colors"
                        onClick={() => { if (confirm(`Delete position "${pos.name}"?`)) deletePositionMut.mutate(pos.id) }}
                        disabled={deletePositionMut.isPending}
                      >
                        <Trash2 size={14} />
                      </button>
                    </div>
                  )}
                </div>
              ))}

              {/* Add new position form */}
              {positionForm && (
                <div className="border border-accent rounded-lg p-3 bg-accent-light space-y-2">
                  <p className="text-xs font-semibold text-content-secondary">New Position</p>
                  <input
                    className="w-full px-2 py-1 border border-border-default rounded text-sm focus:outline-none focus:ring-1 focus:ring-accent bg-surface"
                    placeholder="Name (e.g. Beauty, 3/4 Front)"
                    value={positionForm.name}
                    onChange={(e) => setPositionForm((f) => f ? { ...f, name: e.target.value } : f)}
                  />
                  <div className="flex items-center gap-2">
                    {(['rotation_x', 'rotation_y', 'rotation_z'] as const).map((axis) => (
                      <label key={axis} className="flex items-center gap-1 text-xs text-content-secondary">
                        {axis.replace('rotation_', '').toUpperCase()}°
                        <input
                          type="number"
                          className="w-16 px-1.5 py-1 border border-border-default rounded text-xs focus:outline-none focus:ring-1 focus:ring-accent bg-surface"
                          value={positionForm[axis]}
                          onChange={(e) => setPositionForm((f) => f ? { ...f, [axis]: parseFloat(e.target.value) || 0 } : f)}
                        />
                      </label>
                    ))}
                  </div>
                  <div className="flex gap-2">
                    <button
                      className="btn-primary text-xs"
                      onClick={() => addPositionMut.mutate(positionForm)}
                      disabled={addPositionMut.isPending || !positionForm.name.trim()}
                    >
                      <Save size={11} /> {addPositionMut.isPending ? 'Saving…' : 'Save'}
                    </button>
                    <button className="btn-secondary text-xs" onClick={() => setPositionForm(null)}>
                      <X size={11} /> Cancel
                    </button>
                  </div>
                </div>
              )}
            </div>
          )}
        </div>
      )}

      {/* Components table */}
      {product.components.length > 0 && (
        <div className="card p-5 mb-4">
          <h2 className="text-sm font-semibold text-content-secondary mb-3">Excel Components</h2>
          <table className="w-full text-xs">
            <thead>
              <tr className="border-b border-border-light text-left">
                <th className="pb-1 font-medium text-content-muted">Part Name</th>
                <th className="pb-1 font-medium text-content-muted">Material</th>
                <th className="pb-1 font-medium text-content-muted">Type</th>
              </tr>
            </thead>
            <tbody>
              {product.components.map((c: any, i: number) => (
                <tr key={i} className="border-b border-border-light">
                  <td className="py-1 pr-3">{c.part_name || '—'}</td>
                  <td className="py-1 pr-3">{c.material || '—'}</td>
                  <td className="py-1 text-content-muted">{c.component_type || '—'}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {/* Order history */}
      <div className="card">
        <button
          className="w-full flex items-center gap-2 p-4 text-sm font-semibold text-content-secondary hover:bg-surface-hover rounded-lg"
          onClick={() => {
            if (!showOrders) fetchOrders()
            setShowOrders((v) => !v)
          }}
        >
          {showOrders ? <ChevronDown size={15} /> : <ChevronRight size={15} />}
          Order History
        </button>
        {showOrders && (
          <div className="px-4 pb-4">
            {!orders ? (
              <p className="text-sm text-content-muted">Loading…</p>
            ) : orders.length === 0 ? (
              <p className="text-sm text-content-muted">No orders reference this product.</p>
            ) : (
              <ul className="space-y-1">
                {orders.map((o: any) => (
                  <li key={o.id}>
                    <Link
                      to={`/orders/${o.id}`}
                      className="text-sm text-accent hover:underline"
                    >
                      {o.order_number}
                    </Link>
                    <span className="text-xs text-content-muted ml-2">{o.status}</span>
                  </li>
                ))}
              </ul>
            )}
          </div>
        )}
      </div>

      {/* Material Wizard (opened from MaterialInput) */}
      <MaterialWizard
        open={wizardOpen}
        onClose={() => { setWizardOpen(false); setWizardTargetIdx(null) }}
        onCreated={(name) => {
          if (wizardTargetIdx !== null) {
            const updated = [...materialRows]
            updated[wizardTargetIdx] = { ...updated[wizardTargetIdx], material: name }
            setMaterialRows(updated)
            setMaterialsDirty(true)
          }
          setWizardTargetIdx(null)
        }}
      />
    </div>
  )
}
