import React, { useState, useRef, useEffect } from 'react'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { Pencil, Trash2, Plus, Check, X, ChevronDown, Copy } from 'lucide-react'
import { toast } from 'sonner'
import {
  listOutputTypes, createOutputType, updateOutputType, deleteOutputType,
} from '../../api/outputTypes'
import type { OutputType } from '../../api/outputTypes'
import { listMaterials } from '../../api/materials'
import type { Material } from '../../api/materials'
import { listPricingTiers } from '../../api/pricing'
import type { PricingTier } from '../../api/pricing'
import { getWorkflows } from '../../api/workflows'
import type { WorkflowDefinition } from '../../api/workflows'

const RENDERERS = ['blender', 'pillow']
const FORMATS = ['png', 'jpg', 'gltf', 'stl', 'mp4', 'webm']
const ALL_CATEGORIES = [
  { key: 'TRB', label: 'TRB' },
  { key: 'Kugellager', label: 'Kugellager' },
  { key: 'CRB', label: 'CRB' },
  { key: 'Gleitlager', label: 'Gleitlager' },
  { key: 'SRB_TORB', label: 'SRB/TORB' },
  { key: 'Linear_schiene', label: 'Linear' },
  { key: 'Anschlagplatten', label: 'Anschlag' },
]
const EMPTY_FORM ={ name: '', description: '', renderer: 'threejs', output_format: 'png', sort_order: 0, compatible_categories: [] as string[], render_backend: 'auto', is_animation: false, transparent_bg: false, cycles_device: '' as string, pricing_tier_id: null as number | null, material_override: '' as string, width: '', height: '', engine: '', samples: '', frame_count: '', fps: '', turntable_axis: 'world_z', bg_color: '', noise_threshold: '', denoiser: '', denoising_input_passes: '', denoising_prefilter: '', denoising_quality: '', denoising_use_gpu: '' }

export default function OutputTypeTable() {
  const qc = useQueryClient()
  const [showAdd, setShowAdd] = useState(false)
  const [form, setForm] = useState(EMPTY_FORM)
  const [editingId, setEditingId] = useState<string | null>(null)
  const [editDraft, setEditDraft] = useState<Partial<OutputType>>({})

  const { data: types, isLoading } = useQuery({
    queryKey: ['output-types-admin'],
    queryFn: () => listOutputTypes(true),
  })

  const { data: pricingTiers } = useQuery({
    queryKey: ['pricing-tiers'],
    queryFn: listPricingTiers,
  })

  const { data: allMaterials } = useQuery({
    queryKey: ['materials'],
    queryFn: listMaterials,
  })
  const libraryMaterials = (allMaterials ?? []).filter((m: Material) => m.schaeffler_code !== null).sort((a: Material, b: Material) => a.name.localeCompare(b.name))

  const { data: workflows } = useQuery({
    queryKey: ['workflows'],
    queryFn: getWorkflows,
  })

  const updateWorkflowMut = useMutation({
    mutationFn: ({ id, workflow_definition_id }: { id: string; workflow_definition_id: string | null }) =>
      updateOutputType(id, { workflow_definition_id }),
    onSuccess: () => {
      toast.success('Workflow updated')
      qc.invalidateQueries({ queryKey: ['output-types-admin'] })
      qc.invalidateQueries({ queryKey: ['output-types'] })
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed to update workflow'),
  })

  const createMut = useMutation({
    mutationFn: () => {
      const rs: Record<string, unknown> = {}
      if (form.width) rs.width = Number(form.width)
      if (form.height) rs.height = Number(form.height)
      if (form.engine) rs.engine = form.engine
      if (form.samples) rs.samples = Number(form.samples)
      if (form.is_animation) {
        if (form.frame_count) rs.frame_count = Number(form.frame_count)
        if (form.fps) rs.fps = Number(form.fps)
        if (form.turntable_axis) rs.turntable_axis = form.turntable_axis
        if (form.bg_color) rs.bg_color = form.bg_color
      }
      if (form.noise_threshold) rs.noise_threshold = form.noise_threshold
      if (form.denoiser) rs.denoiser = form.denoiser
      if (form.denoising_input_passes) rs.denoising_input_passes = form.denoising_input_passes
      if (form.denoising_prefilter) rs.denoising_prefilter = form.denoising_prefilter
      if (form.denoising_quality) rs.denoising_quality = form.denoising_quality
      if (form.denoising_use_gpu) rs.denoising_use_gpu = form.denoising_use_gpu
      return createOutputType({
        name: form.name.trim(),
        description: form.description.trim() || undefined,
        renderer: form.renderer,
        output_format: form.output_format,
        sort_order: Number(form.sort_order),
        compatible_categories: form.compatible_categories,
        render_backend: form.render_backend,
        is_animation: form.is_animation,
        transparent_bg: form.transparent_bg,
        cycles_device: form.cycles_device || null,
        pricing_tier_id: form.pricing_tier_id,
        material_override: form.material_override || null,
        render_settings: Object.keys(rs).length > 0 ? rs : {},
      } as Partial<OutputType>)
    },
    onSuccess: () => {
      toast.success('Output type created')
      qc.invalidateQueries({ queryKey: ['output-types-admin'] })
      qc.invalidateQueries({ queryKey: ['output-types'] })
      setForm(EMPTY_FORM)
      setShowAdd(false)
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed to create output type'),
  })

  const updateMut = useMutation({
    mutationFn: ({ id, data }: { id: string; data: Partial<OutputType> & { _width?: string; _height?: string; _engine?: string; _samples?: string; _frame_count?: string; _fps?: string; _turntable_axis?: string; _bg_color?: string; _noise_threshold?: string; _denoiser?: string; _denoising_input_passes?: string; _denoising_prefilter?: string; _denoising_quality?: string; _denoising_use_gpu?: string } }) => {
      const { _width, _height, _engine, _samples, _frame_count, _fps, _turntable_axis, _bg_color, _noise_threshold, _denoiser, _denoising_input_passes, _denoising_prefilter, _denoising_quality, _denoising_use_gpu, ...rest } = data
      if (_width !== undefined || _height !== undefined || _engine !== undefined || _samples !== undefined || _frame_count !== undefined || _fps !== undefined || _turntable_axis !== undefined || _bg_color !== undefined || _noise_threshold !== undefined || _denoiser !== undefined || _denoising_input_passes !== undefined || _denoising_prefilter !== undefined || _denoising_quality !== undefined || _denoising_use_gpu !== undefined) {
        const ot = types?.find((t) => t.id === id)
        const existing = ot?.render_settings || {}
        const rs = { ...existing }
        if (_width !== undefined) {
          if (_width) rs.width = Number(_width); else delete rs.width
        }
        if (_height !== undefined) {
          if (_height) rs.height = Number(_height); else delete rs.height
        }
        if (_engine !== undefined) {
          if (_engine) rs.engine = _engine; else delete rs.engine
        }
        if (_samples !== undefined) {
          if (_samples) rs.samples = Number(_samples); else delete rs.samples
        }
        if (_frame_count !== undefined) {
          if (_frame_count) rs.frame_count = Number(_frame_count); else delete rs.frame_count
        }
        if (_fps !== undefined) {
          if (_fps) rs.fps = Number(_fps); else delete rs.fps
        }
        if (_turntable_axis !== undefined) {
          if (_turntable_axis) rs.turntable_axis = _turntable_axis; else delete rs.turntable_axis
        }
        if (_bg_color !== undefined) {
          if (_bg_color) rs.bg_color = _bg_color; else delete rs.bg_color
        }
        if (_noise_threshold !== undefined) {
          if (_noise_threshold) rs.noise_threshold = _noise_threshold; else delete rs.noise_threshold
        }
        if (_denoiser !== undefined) {
          if (_denoiser) rs.denoiser = _denoiser; else delete rs.denoiser
        }
        if (_denoising_input_passes !== undefined) {
          if (_denoising_input_passes) rs.denoising_input_passes = _denoising_input_passes; else delete rs.denoising_input_passes
        }
        if (_denoising_prefilter !== undefined) {
          if (_denoising_prefilter) rs.denoising_prefilter = _denoising_prefilter; else delete rs.denoising_prefilter
        }
        if (_denoising_quality !== undefined) {
          if (_denoising_quality) rs.denoising_quality = _denoising_quality; else delete rs.denoising_quality
        }
        if (_denoising_use_gpu !== undefined) {
          if (_denoising_use_gpu) rs.denoising_use_gpu = _denoising_use_gpu; else delete rs.denoising_use_gpu
        }
        rest.render_settings = rs
      }
      return updateOutputType(id, rest)
    },
    onSuccess: () => {
      toast.success('Output type updated')
      qc.invalidateQueries({ queryKey: ['output-types-admin'] })
      qc.invalidateQueries({ queryKey: ['output-types'] })
      setEditingId(null)
      setEditDraft({})
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed to update'),
  })

  const deleteMut = useMutation({
    mutationFn: (id: string) => deleteOutputType(id),
    onSuccess: () => {
      toast.success('Output type deleted')
      qc.invalidateQueries({ queryKey: ['output-types-admin'] })
      qc.invalidateQueries({ queryKey: ['output-types'] })
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed to delete'),
  })

  const duplicateMut = useMutation({
    mutationFn: (ot: OutputType) => createOutputType({
      name: `${ot.name} (copy)`,
      description: ot.description,
      renderer: ot.renderer,
      render_settings: ot.render_settings,
      output_format: ot.output_format,
      sort_order: ot.sort_order,
      compatible_categories: ot.compatible_categories,
      render_backend: ot.render_backend,
      is_animation: ot.is_animation,
      transparent_bg: ot.transparent_bg,
      cycles_device: ot.cycles_device,
      pricing_tier_id: ot.pricing_tier_id,
      workflow_definition_id: ot.workflow_definition_id,
      is_active: ot.is_active,
    }),
    onSuccess: () => {
      toast.success('Output type duplicated')
      qc.invalidateQueries({ queryKey: ['output-types-admin'] })
      qc.invalidateQueries({ queryKey: ['output-types'] })
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed to duplicate'),
  })

  // Check if transparent_bg / bg_color controls should be visible
  function showTransparentBg(renderer: string, _format: string) {
    return renderer === 'blender'
  }

  // Check if blender-specific engine/samples columns should be visible
  function showBlenderSettings(renderer: string) {
    return renderer === 'blender'
  }

  // Render the edit form grid (shared between edit-row and add-row)
  function renderEditFormGrid(
    mode: 'edit' | 'add',
    ot: OutputType | null,
  ) {
    // For edit mode, use editDraft + ot fallback. For add mode, use form state.
    const isEdit = mode === 'edit' && ot !== null

    // Getter helpers
    const val = (field: keyof typeof form) => {
      if (isEdit) {
        if (field === 'name') return editDraft.name ?? ot!.name
        if (field === 'renderer') return editDraft.renderer ?? ot!.renderer
        if (field === 'output_format') return editDraft.output_format ?? ot!.output_format
        if (field === 'is_animation') return editDraft.is_animation ?? ot!.is_animation
        if (field === 'transparent_bg') return editDraft.transparent_bg ?? ot!.transparent_bg
        if (field === 'cycles_device') return editDraft.cycles_device ?? (ot!.cycles_device || '')
        if (field === 'sort_order') return editDraft.sort_order ?? ot!.sort_order
        if (field === 'pricing_tier_id') return editDraft.pricing_tier_id ?? ot!.pricing_tier_id ?? ''
        if (field === 'material_override') return editDraft.material_override ?? ot!.material_override ?? ''
        // render_settings fields (prefixed with _)
        if (field === 'width') return (editDraft as any)._width ?? (ot!.render_settings?.width || '')
        if (field === 'height') return (editDraft as any)._height ?? (ot!.render_settings?.height || '')
        if (field === 'engine') return (editDraft as any)._engine ?? (ot!.render_settings?.engine || '')
        if (field === 'samples') return (editDraft as any)._samples ?? (ot!.render_settings?.samples || '')
        if (field === 'frame_count') return (editDraft as any)._frame_count ?? (ot!.render_settings?.frame_count || '')
        if (field === 'fps') return (editDraft as any)._fps ?? (ot!.render_settings?.fps || '')
        if (field === 'turntable_axis') return (editDraft as any)._turntable_axis ?? (ot!.render_settings?.turntable_axis || 'world_z')
        if (field === 'bg_color') {
          return (editDraft as any)._bg_color !== undefined
            ? (editDraft as any)._bg_color as string
            : (ot!.render_settings?.bg_color as string || '')
        }
        if (field === 'noise_threshold') return (editDraft as any)._noise_threshold ?? (ot!.render_settings?.noise_threshold as string || '')
        if (field === 'denoiser') return (editDraft as any)._denoiser ?? (ot!.render_settings?.denoiser as string || '')
        if (field === 'denoising_input_passes') return (editDraft as any)._denoising_input_passes ?? (ot!.render_settings?.denoising_input_passes as string || '')
        if (field === 'denoising_prefilter') return (editDraft as any)._denoising_prefilter ?? (ot!.render_settings?.denoising_prefilter as string || '')
        if (field === 'denoising_quality') return (editDraft as any)._denoising_quality ?? (ot!.render_settings?.denoising_quality as string || '')
        if (field === 'denoising_use_gpu') return (editDraft as any)._denoising_use_gpu ?? (ot!.render_settings?.denoising_use_gpu as string || '')
        return (form as any)[field]
      }
      return (form as any)[field]
    }

    const set = (field: string, value: any) => {
      if (isEdit) {
        // render_settings fields get _ prefix in editDraft
        const rsFields = ['width', 'height', 'engine', 'samples', 'frame_count', 'fps', 'turntable_axis', 'bg_color', 'noise_threshold', 'denoiser', 'denoising_input_passes', 'denoising_prefilter', 'denoising_quality', 'denoising_use_gpu']
        if (rsFields.includes(field)) {
          setEditDraft({ ...editDraft, [`_${field}`]: value } as any)
        } else {
          setEditDraft({ ...editDraft, [field]: value } as any)
        }
      } else {
        setForm({ ...form, [field]: value })
      }
    }

    const currentRenderer = val('renderer') as string
    const currentFormat = val('output_format') as string
    const currentIsAnimation = val('is_animation') as boolean
    const isBlender = showBlenderSettings(currentRenderer)
    const showBg = showTransparentBg(currentRenderer, currentFormat)
    const bgColor = val('bg_color') as string
    const bgEnabled = bgColor !== ''

    const categoriesValue = isEdit
      ? (editDraft.compatible_categories ?? ot!.compatible_categories) || []
      : form.compatible_categories

    return (
      <>
        {/* Row 1: Name | Renderer | Format | Animation */}
        <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Name</label>
            <input
              className="input-sm w-full"
              placeholder="e.g. 3D Thumbnail"
              value={val('name') as string}
              onChange={(e) => set('name', e.target.value)}
            />
          </div>
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Renderer</label>
            <select
              className="input-sm w-full"
              value={currentRenderer}
              onChange={(e) => set('renderer', e.target.value)}
            >
              {RENDERERS.map((r) => <option key={r}>{r}</option>)}
            </select>
          </div>
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Format</label>
            <select
              className="input-sm w-full"
              value={currentFormat}
              onChange={(e) => set('output_format', e.target.value)}
            >
              {FORMATS.map((f) => <option key={f}>{f}</option>)}
            </select>
          </div>
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Animation</label>
            <label className="flex items-center gap-2 mt-1">
              <input
                type="checkbox"
                checked={currentIsAnimation}
                onChange={(e) => set('is_animation', e.target.checked)}
              />
              <span className="text-sm text-content-secondary">Video output</span>
            </label>
          </div>
        </div>

        {/* Row 2: Turntable | Background | Device | Engine */}
        <div className="grid grid-cols-2 md:grid-cols-4 gap-4 mt-4">
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Turntable</label>
            {currentIsAnimation ? (
              <div className="flex flex-col gap-1.5">
                <div className="flex items-center gap-1">
                  <input
                    type="number" min={1} max={3600}
                    className="input-sm w-16" placeholder="120"
                    value={val('frame_count')}
                    onChange={(e) => set('frame_count', e.target.value)}
                    title="Frame count"
                  />
                  <span className="text-content-muted text-xs">f</span>
                  <input
                    type="number" min={1} max={120}
                    className="input-sm w-14" placeholder="30"
                    value={val('fps')}
                    onChange={(e) => set('fps', e.target.value)}
                    title="FPS"
                  />
                  <span className="text-content-muted text-xs">fps</span>
                </div>
                <select
                  className="input-sm w-full"
                  value={val('turntable_axis') as string}
                  onChange={(e) => set('turntable_axis', e.target.value)}
                  title="Rotation axis"
                >
                  <option value="world_z">World Z</option>
                  <option value="world_x">World X</option>
                  <option value="world_y">World Y</option>
                </select>
              </div>
            ) : (
              <span className="text-content-muted text-sm">N/A (not animation)</span>
            )}
          </div>
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Background</label>
            {showBg ? (
              <div className="flex flex-col gap-1.5">
                <label className="flex items-center gap-1.5 text-xs text-content-secondary">
                  <input
                    type="checkbox"
                    checked={val('transparent_bg') as boolean}
                    onChange={(e) => set('transparent_bg', e.target.checked)}
                    title="Transparent background (PNG alpha)"
                  />
                  Transparent (alpha)
                </label>
                <label className="flex items-center gap-1.5 text-xs text-content-secondary">
                  <input
                    type="checkbox"
                    checked={bgEnabled}
                    onChange={(e) => set('bg_color', e.target.checked ? (bgColor || '#000000') : '')}
                    title="Composite over solid background color"
                  />
                  BG color
                </label>
                {bgEnabled && (
                  <div className="flex items-center gap-1">
                    <input
                      type="color"
                      className="w-7 h-6 rounded border border-border-default cursor-pointer p-0"
                      value={bgColor}
                      onChange={(e) => set('bg_color', e.target.value)}
                    />
                    <input
                      type="text"
                      className="input-sm w-20 font-mono text-xs"
                      placeholder="#rrggbb"
                      value={bgColor}
                      onChange={(e) => set('bg_color', e.target.value)}
                    />
                  </div>
                )}
              </div>
            ) : (
              <span className="text-content-muted text-sm">N/A (not Blender)</span>
            )}
          </div>
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Device</label>
            {isBlender ? (
              <select
                className="input-sm w-full"
                value={val('cycles_device') as string}
                onChange={(e) => set('cycles_device', e.target.value || null)}
              >
                <option value="">System default</option>
                <option value="auto">Auto</option>
                <option value="gpu">GPU</option>
                <option value="cpu">CPU</option>
              </select>
            ) : (
              <span className="text-content-muted text-sm">N/A (not Blender)</span>
            )}
          </div>
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Engine</label>
            {isBlender ? (
              <select
                className="input-sm w-full"
                value={val('engine') as string}
                onChange={(e) => set('engine', e.target.value)}
              >
                <option value="">System default</option>
                <option value="cycles">Cycles</option>
                <option value="eevee">EEVEE</option>
              </select>
            ) : (
              <span className="text-content-muted text-sm">N/A (not Blender)</span>
            )}
          </div>
        </div>

        {/* Row 3: Samples | Resolution | Pricing Tier | Workflow */}
        <div className="grid grid-cols-2 md:grid-cols-4 gap-4 mt-4">
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Samples</label>
            {isBlender ? (
              <input
                type="number"
                min={1}
                max={4096}
                className="input-sm w-full"
                placeholder="default"
                value={val('samples')}
                onChange={(e) => set('samples', e.target.value)}
              />
            ) : (
              <span className="text-content-muted text-sm">N/A (not Blender)</span>
            )}
          </div>
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Resolution (W x H)</label>
            <div className="flex items-center gap-1">
              <input
                type="number"
                className="input-sm w-20"
                placeholder="W"
                value={val('width')}
                onChange={(e) => set('width', e.target.value)}
              />
              <span className="text-content-muted text-xs">x</span>
              <input
                type="number"
                className="input-sm w-20"
                placeholder="H"
                value={val('height')}
                onChange={(e) => set('height', e.target.value)}
              />
            </div>
          </div>
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Pricing Tier</label>
            <select
              className="input-sm w-full"
              value={val('pricing_tier_id') as string | number}
              onChange={(e) => set('pricing_tier_id', e.target.value ? Number(e.target.value) : null)}
            >
              <option value="">Category default</option>
              {pricingTiers?.map((t) => (
                <option key={t.id} value={t.id}>
                  {t.category_key}/{t.quality_level} — {t.price_per_item.toFixed(2)}
                </option>
              ))}
            </select>
          </div>
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Workflow</label>
            {isEdit ? (
              <select
                className="input-sm w-full"
                value={(editDraft.workflow_definition_id ?? ot!.workflow_definition_id) ?? ''}
                onChange={(e) => set('workflow_definition_id', e.target.value || null)}
              >
                <option value="">— Legacy —</option>
                {workflows?.filter((w) => w.is_active).map((w) => (
                  <option key={w.id} value={w.id}>{w.name}</option>
                ))}
              </select>
            ) : (
              <span className="text-content-muted text-sm">— (set after creation)</span>
            )}
          </div>
        </div>

        {/* Row 4: Categories | Material Override | Sort Order | Active */}
        <div className="grid grid-cols-2 md:grid-cols-4 gap-4 mt-4">
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Categories</label>
            <CategoryMultiSelect
              value={categoriesValue}
              onChange={(cats) => set('compatible_categories', cats)}
            />
          </div>
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Material Override</label>
            <select
              className="input-sm w-full text-xs"
              value={val('material_override') as string}
              onChange={(e) => set('material_override', e.target.value || null)}
            >
              <option value="">— None —</option>
              {libraryMaterials.map((m: Material) => (
                <option key={m.id} value={m.name}>{m.name}</option>
              ))}
            </select>
          </div>
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Sort Order</label>
            <input
              type="number"
              className="input-sm w-20"
              value={val('sort_order') as number}
              onChange={(e) => set('sort_order', Number(e.target.value))}
            />
          </div>
          <div>
            <label className="block text-xs font-medium text-content-muted mb-1">Active</label>
            {isEdit ? (
              <label className="flex items-center gap-2 mt-1">
                <input
                  type="checkbox"
                  checked={editDraft.is_active ?? ot!.is_active}
                  onChange={(e) => set('is_active', e.target.checked)}
                />
                <span className="text-sm text-content-secondary">Visible in wizard</span>
              </label>
            ) : (
              <span className="text-content-muted text-sm">— (active by default)</span>
            )}
          </div>
        </div>

        {/* Row 5: Denoising settings (only for Blender) */}
        {isBlender && (
          <div className="mt-4 pt-3 border-t border-border-light">
            <label className="block text-xs font-medium text-content-muted mb-2">Denoising Settings (Blender)</label>
            <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-3">
              <div>
                <label className="block text-xs text-content-muted mb-0.5">Denoiser</label>
                <select
                  className="input-sm w-full"
                  value={val('denoiser') as string}
                  onChange={(e) => set('denoiser', e.target.value)}
                  title="Denoiser"
                >
                  <option value="">Auto</option>
                  <option value="OPTIX">OptiX</option>
                  <option value="OPENIMAGEDENOISE">OIDN</option>
                </select>
              </div>
              <div>
                <label className="block text-xs text-content-muted mb-0.5">Noise Threshold</label>
                <input
                  type="number"
                  step="0.001" min="0.001" max="1"
                  className="input-sm w-full"
                  placeholder="auto"
                  value={val('noise_threshold')}
                  onChange={(e) => set('noise_threshold', e.target.value)}
                  title="Noise threshold (adaptive sampling)"
                />
              </div>
              <div>
                <label className="block text-xs text-content-muted mb-0.5">Input Passes</label>
                <select
                  className="input-sm w-full"
                  value={val('denoising_input_passes') as string}
                  onChange={(e) => set('denoising_input_passes', e.target.value)}
                  title="Input passes"
                >
                  <option value="">Default</option>
                  <option value="RGB">RGB</option>
                  <option value="RGB_ALBEDO">RGB+Albedo</option>
                  <option value="RGB_ALBEDO_NORMAL">RGB+Albedo+Normal</option>
                </select>
              </div>
              <div>
                <label className="block text-xs text-content-muted mb-0.5">Prefilter</label>
                <select
                  className="input-sm w-full"
                  value={val('denoising_prefilter') as string}
                  onChange={(e) => set('denoising_prefilter', e.target.value)}
                  title="Prefilter"
                >
                  <option value="">Default</option>
                  <option value="NONE">None</option>
                  <option value="FAST">Fast</option>
                  <option value="ACCURATE">Accurate</option>
                </select>
              </div>
              <div>
                <label className="block text-xs text-content-muted mb-0.5">Quality</label>
                <select
                  className="input-sm w-full"
                  value={val('denoising_quality') as string}
                  onChange={(e) => set('denoising_quality', e.target.value)}
                  title="Quality (Blender 4.2+)"
                >
                  <option value="">Default</option>
                  <option value="HIGH">High</option>
                  <option value="BALANCED">Balanced</option>
                  <option value="FAST">Fast</option>
                </select>
              </div>
              <div>
                <label className="block text-xs text-content-muted mb-0.5">GPU Routing</label>
                <select
                  className="input-sm w-full"
                  value={val('denoising_use_gpu') as string}
                  onChange={(e) => set('denoising_use_gpu', e.target.value)}
                  title="OIDN GPU routing"
                >
                  <option value="">Auto</option>
                  <option value="1">GPU</option>
                  <option value="0">CPU</option>
                </select>
              </div>
            </div>
          </div>
        )}
      </>
    )
  }

  return (
    <div>
      <div className="overflow-x-auto">
      <table className="w-full text-sm min-w-[900px]">
        <thead>
          <tr className="border-b border-border-light text-left">
            <th className="px-4 py-2 font-medium text-content-secondary">Name</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Renderer used to produce this output (blender / pillow)">Renderer</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Output file format (jpg, png, mp4, webm)">Format</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Animation — output is a video (mp4/webm turntable)">Anim</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Turntable animation settings: frame count, FPS, and rotation axis (animation output types only)">Turntable</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Transparent Background — render with alpha channel (PNG only; Blender film_transparent)">BG</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Cycles compute device override — auto, gpu, or cpu (Blender/Cycles only)">Device</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Blender render engine override — cycles or eevee (overrides global setting for this output type)">Engine</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Sample count override for this output type (overrides global Cycles/EEVEE sample settings)">Samples</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Cycles denoising settings: denoiser, noise threshold, input passes, prefilter, quality, GPU routing">Denoise</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Compatible product categories — empty means compatible with all categories">Categories</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Output resolution in pixels (width x height); leave empty to use global default">Resolution</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Pricing tier used to calculate the per-item cost for this output type">Pricing</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Workflow definition assigned to this output type">Workflow</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Material override — apply a single material to ALL product parts (e.g. x-ray, clay render)">Mat Override</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Sort order — lower numbers appear first in the wizard output-type picker">Sort</th>
            <th className="px-4 py-2 font-medium text-content-secondary" title="Active — inactive types are hidden from the order wizard">Active</th>
            <th className="px-4 py-2 font-medium text-content-secondary">Actions</th>
          </tr>
        </thead>
        <tbody>
          {isLoading && (
            <tr>
              <td colSpan={18} className="px-4 py-4 text-center text-content-muted">Loading...</td>
            </tr>
          )}
          {types?.map((ot) => (
            <React.Fragment key={ot.id}>
              {/* Display row — always visible */}
              <tr className={`border-b border-border-light hover:bg-surface-hover ${editingId === ot.id ? 'bg-surface-hover' : ''}`}>
                <td className="px-4 py-2 font-medium">{ot.name}</td>
                <td className="px-4 py-2 text-content-muted">{ot.renderer}</td>
                <td className="px-4 py-2 text-content-muted">{ot.output_format}</td>
                <td className="px-4 py-2">
                  {ot.is_animation && (
                    <span className="text-xs px-1.5 py-0.5 rounded bg-purple-50 text-purple-700">video</span>
                  )}
                </td>
                <td className="px-4 py-2">
                  {ot.is_animation ? (
                    <div className="flex flex-col gap-0.5">
                      <span className="text-xs text-content-secondary">
                        {(ot.render_settings?.frame_count as number) || 120}f / {(ot.render_settings?.fps as number) || 30}fps
                      </span>
                      <span className="text-xs text-content-muted">
                        360° {({'world_z': 'World Z', 'world_x': 'World X', 'world_y': 'World Y'} as Record<string, string>)[ot.render_settings?.turntable_axis as string] ?? 'World Z'}
                      </span>
                    </div>
                  ) : (
                    <span className="text-content-muted">—</span>
                  )}
                </td>
                <td className="px-4 py-2">
                  {showTransparentBg(ot.renderer, ot.output_format) && (
                    <div className="flex flex-col gap-1">
                      {ot.transparent_bg && (
                        <span className="text-xs px-1.5 py-0.5 rounded bg-sky-50 text-sky-700" title="Transparent background">alpha</span>
                      )}
                      {!!ot.render_settings?.bg_color && (
                        <div className="flex items-center gap-1" title={`BG color: ${ot.render_settings.bg_color}`}>
                          <span
                            className="inline-block w-4 h-4 rounded border border-border-default"
                            style={{ backgroundColor: ot.render_settings.bg_color as string }}
                          />
                          <span className="text-xs text-content-muted font-mono">{ot.render_settings.bg_color as string}</span>
                        </div>
                      )}
                    </div>
                  )}
                </td>
                <td className="px-4 py-2">
                  {showBlenderSettings(ot.renderer) ? (
                    ot.cycles_device ? (
                      <span className={`text-xs px-1.5 py-0.5 rounded font-medium ${
                        ot.cycles_device === 'gpu' ? 'bg-violet-50 text-violet-700' :
                        ot.cycles_device === 'cpu' ? 'bg-status-warning-bg text-status-warning-text' :
                        'bg-surface-muted text-content-muted'
                      }`}>
                        {ot.cycles_device.toUpperCase()}
                      </span>
                    ) : (
                      <span className="text-xs text-content-muted">system</span>
                    )
                  ) : (
                    <span className="text-content-muted">—</span>
                  )}
                </td>
                <td className="px-4 py-2">
                  {showBlenderSettings(ot.renderer) ? (
                    ot.render_settings?.engine ? (
                      <span className={`text-xs px-1.5 py-0.5 rounded font-medium ${
                        ot.render_settings.engine === 'cycles' ? 'bg-status-success-bg text-status-success-text' : 'bg-status-info-bg text-status-info-text'
                      }`}>
                        {ot.render_settings.engine === 'cycles' ? 'Cycles' : 'EEVEE'}
                      </span>
                    ) : (
                      <span className="text-xs text-content-muted">default</span>
                    )
                  ) : (
                    <span className="text-content-muted">—</span>
                  )}
                </td>
                <td className="px-4 py-2">
                  {showBlenderSettings(ot.renderer) ? (
                    ot.render_settings?.samples ? (
                      <span className="text-xs font-medium text-content-secondary">{ot.render_settings.samples as number}</span>
                    ) : (
                      <span className="text-xs text-content-muted">default</span>
                    )
                  ) : (
                    <span className="text-content-muted">—</span>
                  )}
                </td>
                <td className="px-4 py-2">
                  {showBlenderSettings(ot.renderer) ? (
                    <div className="flex flex-col gap-0.5">
                      {ot.render_settings?.denoiser ? (
                        <span className="text-xs px-1.5 py-0.5 rounded bg-indigo-50 text-indigo-700 font-medium">
                          {ot.render_settings.denoiser === 'OPTIX' ? 'OptiX' : 'OIDN'}
                        </span>
                      ) : null}
                      {ot.render_settings?.noise_threshold ? (
                        <span className="text-xs text-content-muted">t={ot.render_settings.noise_threshold as string}</span>
                      ) : null}
                      {ot.render_settings?.denoising_prefilter ? (
                        <span className="text-xs text-content-muted">{ot.render_settings.denoising_prefilter as string}</span>
                      ) : null}
                      {!ot.render_settings?.denoiser && !ot.render_settings?.noise_threshold && !ot.render_settings?.denoising_prefilter && (
                        <span className="text-xs text-content-muted">default</span>
                      )}
                    </div>
                  ) : (
                    <span className="text-content-muted">—</span>
                  )}
                </td>
                <td className="px-4 py-2">
                  {(!ot.compatible_categories || ot.compatible_categories.length === 0) ? (
                    <span className="text-xs text-content-muted">All</span>
                  ) : (
                    <div className="flex flex-wrap gap-1">
                      {ot.compatible_categories.map((c: string) => (
                        <span key={c} className="text-xs px-1.5 py-0.5 rounded bg-status-info-bg text-status-info-text">
                          {ALL_CATEGORIES.find((ac) => ac.key === c)?.label || c}
                        </span>
                      ))}
                    </div>
                  )}
                </td>
                <td className="px-4 py-2 text-content-muted text-xs">
                  {ot.render_settings?.width || ot.render_settings?.height
                    ? `${ot.render_settings.width || '?'}x${ot.render_settings.height || '?'}`
                    : <span className="text-content-muted">default</span>}
                </td>
                <td className="px-4 py-2">
                  {ot.pricing_tier_name ? (
                    <div className="flex items-center gap-1">
                      <span className="text-xs text-content-secondary truncate max-w-[80px]" title={ot.pricing_tier_name}>
                        {ot.pricing_tier_name}
                      </span>
                      {ot.price_per_item != null && (
                        <span className="text-xs px-1.5 py-0.5 rounded bg-emerald-50 text-emerald-700 font-medium">
                          {ot.price_per_item.toFixed(2)}
                        </span>
                      )}
                    </div>
                  ) : (
                    <span className="text-xs text-content-muted">Category default</span>
                  )}
                </td>
                <td className="px-4 py-2">
                  {(() => {
                    const wf = workflows?.find((w) => w.id === ot.workflow_definition_id)
                    return wf ? (
                      <span className="text-xs px-2 py-0.5 rounded-full bg-status-success-bg text-status-success-text font-medium">
                        {wf.name}
                      </span>
                    ) : (
                      <span className="text-xs px-2 py-0.5 rounded-full bg-surface-muted text-content-muted">
                        Legacy
                      </span>
                    )
                  })()}
                </td>
                <td className="px-4 py-2">
                  {ot.material_override ? (
                    <span className="text-xs px-1.5 py-0.5 rounded bg-amber-50 text-amber-700 font-mono truncate block max-w-[140px]" title={ot.material_override}>
                      {ot.material_override.replace('SCHAEFFLER_', '').replace(/_/g, ' ')}
                    </span>
                  ) : (
                    <span className="text-xs text-content-muted">—</span>
                  )}
                </td>
                <td className="px-4 py-2 text-content-muted">{ot.sort_order}</td>
                <td className="px-4 py-2">
                  <span className={`text-xs px-2 py-0.5 rounded-full font-medium ${
                    ot.is_active ? 'bg-status-success-bg text-status-success-text' : 'bg-surface-muted text-content-muted'
                  }`}>
                    {ot.is_active ? 'active' : 'inactive'}
                  </span>
                </td>
                <td className="px-4 py-2 flex items-center gap-2">
                  <button
                    className="btn-icon text-content-muted hover:text-accent"
                    onClick={() => {
                      if (editingId === ot.id) {
                        setEditingId(null); setEditDraft({})
                      } else {
                        setEditingId(ot.id); setEditDraft({})
                      }
                    }}
                    title={editingId === ot.id ? 'Collapse edit form' : 'Edit output type'}
                  >
                    <Pencil size={14} />
                  </button>
                  <button
                    className="btn-icon text-content-muted hover:text-blue-500"
                    onClick={() => duplicateMut.mutate(ot)}
                    disabled={duplicateMut.isPending}
                    title="Duplicate output type"
                  >
                    <Copy size={14} />
                  </button>
                  <button
                    className="btn-icon text-content-muted hover:text-red-500"
                    onClick={() => {
                      if (confirm(`Delete output type "${ot.name}"?`)) deleteMut.mutate(ot.id)
                    }}
                    title="Delete output type"
                  >
                    <Trash2 size={14} />
                  </button>
                </td>
              </tr>

              {/* Expandable edit form row */}
              {editingId === ot.id && (
                <tr>
                  <td colSpan={18} className="px-6 py-5 bg-surface-alt border-l-4 border-accent border-b-2 border-b-border-light">
                    {renderEditFormGrid('edit', ot)}
                    <div className="flex justify-end gap-2 mt-4 pt-3 border-t border-border-light">
                      <button
                        className="btn-secondary text-sm"
                        onClick={() => { setEditingId(null); setEditDraft({}) }}
                      >
                        Cancel
                      </button>
                      <button
                        className="btn-primary text-sm"
                        onClick={() => updateMut.mutate({ id: ot.id, data: editDraft })}
                      >
                        Save Changes
                      </button>
                    </div>
                  </td>
                </tr>
              )}
            </React.Fragment>
          ))}

          {/* Add new — expandable form */}
          {showAdd && (
            <>
              <tr className="border-b border-border-light bg-status-success-bg">
                <td colSpan={18} className="px-6 py-5 border-l-4 border-status-success-text">
                  <div className="text-sm font-medium text-content-secondary mb-3">New Output Type</div>
                  {renderEditFormGrid('add', null)}
                  <div className="flex justify-end gap-2 mt-4 pt-3 border-t border-border-light">
                    <button
                      className="btn-secondary text-sm"
                      onClick={() => { setShowAdd(false); setForm(EMPTY_FORM) }}
                    >
                      Cancel
                    </button>
                    <button
                      className="btn-primary text-sm"
                      disabled={!form.name.trim() || createMut.isPending}
                      onClick={() => createMut.mutate()}
                    >
                      Create Output Type
                    </button>
                  </div>
                </td>
              </tr>
            </>
          )}
        </tbody>
      </table>
      </div>

      {!showAdd && (
        <div className="px-4 py-3">
          <button
            className="btn-secondary text-sm"
            onClick={() => setShowAdd(true)}
          >
            <Plus size={14} /> Add Output Type
          </button>
        </div>
      )}
    </div>
  )
}


function CategoryMultiSelect({
  value,
  onChange,
}: {
  value: string[]
  onChange: (cats: string[]) => void
}) {
  const [open, setOpen] = useState(false)
  const ref = useRef<HTMLDivElement>(null)

  useEffect(() => {
    function handleClick(e: MouseEvent) {
      if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false)
    }
    document.addEventListener('mousedown', handleClick)
    return () => document.removeEventListener('mousedown', handleClick)
  }, [])

  function toggle(key: string) {
    if (value.includes(key)) {
      onChange(value.filter((k) => k !== key))
    } else {
      onChange([...value, key])
    }
  }

  return (
    <div className="relative" ref={ref}>
      <button
        type="button"
        onClick={() => setOpen(!open)}
        className="input-sm flex items-center gap-1 min-w-[100px] text-left"
      >
        <span className="flex-1 truncate text-xs">
          {value.length === 0 ? 'All' : value.map((k) => ALL_CATEGORIES.find((c) => c.key === k)?.label || k).join(', ')}
        </span>
        <ChevronDown size={12} className="text-content-muted shrink-0" />
      </button>
      {open && (
        <div className="absolute z-50 mt-1 left-0 bg-surface border border-border-default rounded-lg shadow-lg py-1 min-w-[160px]">
          {ALL_CATEGORIES.map((cat) => (
            <label
              key={cat.key}
              className="flex items-center gap-2 px-3 py-1.5 hover:bg-surface-hover cursor-pointer text-xs"
            >
              <input
                type="checkbox"
                checked={value.includes(cat.key)}
                onChange={() => toggle(cat.key)}
                className=""
              />
              {cat.label}
            </label>
          ))}
          {value.length > 0 && (
            <button
              type="button"
              onClick={() => onChange([])}
              className="w-full text-left px-3 py-1.5 text-xs text-content-muted hover:text-content-secondary border-t border-border-light"
            >
              Clear (= All)
            </button>
          )}
        </div>
      )}
    </div>
  )
}
