import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { useState } from 'react'
import { toast } from 'sonner'
import { UserPlus, Trash2, Pencil, ChevronDown, ChevronUp, ChevronRight, Settings, RefreshCw, CheckCircle2, XCircle, Clock, DollarSign, Layers, Server, ExternalLink, AlertTriangle, Upload, FileBox, Plus, X } from 'lucide-react'
import { Link } from 'react-router-dom'
import api from '../api/client'
import TemplateEditor from '../components/admin/TemplateEditor'
import PricingTierTable from '../components/admin/PricingTierTable'
import OutputTypeTable from '../components/admin/OutputTypeTable'
import RenderTemplateTable from '../components/admin/RenderTemplateTable'
import { useAuthStore } from '../store/auth'
import { getMaterialLibraryInfo, uploadMaterialLibrary, deleteMaterialLibrary } from '../api/renderTemplates'
import type { MaterialLibraryInfo } from '../api/renderTemplates'
import { listPricingTiers } from '../api/pricing'
import { listOutputTypes } from '../api/outputTypes'

export default function AdminPage() {
  const qc = useQueryClient()
  const user = useAuthStore((s) => s.user)
  const isAdmin = user?.role === 'admin'
  const [showNewUser, setShowNewUser] = useState(false)
  const [newUser, setNewUser] = useState({ email: '', password: '', full_name: '', role: 'client' })
  const [editingTemplateId, setEditingTemplateId] = useState<string | null>(null)
  const [showFlamencoAdvanced, setShowFlamencoAdvanced] = useState(false)
  const [flamencoUrlDraft, setFlamencoUrlDraft] = useState('')
  const [workerCountDraft, setWorkerCountDraft] = useState(1)
  const [priorityNewEntry, setPriorityNewEntry] = useState<string>('')

  const { data: users } = useQuery({
    queryKey: ['admin-users'],
    queryFn: async () => {
      const res = await api.get('/admin/users')
      return res.data as any[]
    },
  })

  const { data: templates } = useQuery({
    queryKey: ['admin-templates'],
    queryFn: async () => {
      const res = await api.get('/templates?include_inactive=true')
      return res.data as any[]
    },
  })

  const createUserMut = useMutation({
    mutationFn: (data: typeof newUser) => api.post('/admin/users', data),
    onSuccess: () => {
      toast.success('User created')
      qc.invalidateQueries({ queryKey: ['admin-users'] })
      setShowNewUser(false)
      setNewUser({ email: '', password: '', full_name: '', role: 'client' })
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed'),
  })

  const deleteUserMut = useMutation({
    mutationFn: (id: string) => api.delete(`/admin/users/${id}`),
    onSuccess: () => {
      toast.success('User deleted')
      qc.invalidateQueries({ queryKey: ['admin-users'] })
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed'),
  })

  type Settings = {
    thumbnail_renderer: string
    blender_engine: string
    blender_cycles_samples: number
    blender_eevee_samples: number
    threejs_render_size: number
    thumbnail_format: string
    stl_quality: string
    blender_smooth_angle: number
    cycles_device: string
    blender_max_concurrent_renders: number
    render_stall_timeout_minutes: number
    product_thumbnail_priority: string  // JSON array
  }

  const { data: settings } = useQuery({
    queryKey: ['admin-settings'],
    queryFn: async () => {
      const res = await api.get('/admin/settings')
      return res.data as Settings
    },
  })

  const { data: outputTypes } = useQuery({
    queryKey: ['output-types-all'],
    queryFn: () => listOutputTypes(false),
    enabled: isAdmin,
  })

  // Local draft for Blender options so the user can change multiple fields before saving
  const [blenderDraft, setBlenderDraft] = useState<Partial<Settings>>({})
  const blender = { ...settings, ...blenderDraft } as Settings

  const { data: rendererStatus, refetch: refetchStatus } = useQuery({
    queryKey: ['renderer-status'],
    queryFn: async () => {
      const res = await api.get('/admin/settings/renderer-status')
      return res.data as Record<string, { available: boolean; note: string; url: string | null }>
    },
    refetchInterval: 30000,
  })

  const updateSettingsMut = useMutation({
    mutationFn: (data: Partial<Settings>) => api.put('/admin/settings', data),
    onSuccess: () => {
      toast.success('Settings saved')
      qc.invalidateQueries({ queryKey: ['admin-settings'] })
      setBlenderDraft({})
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed'),
  })

  const processUnprocessedMut = useMutation({
    mutationFn: () => api.post('/admin/settings/process-unprocessed'),
    onSuccess: (res) => {
      toast.success(res.data.message || 'Processing queued')
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed'),
  })

  const regenerateMut = useMutation({
    mutationFn: () => api.post('/admin/settings/regenerate-thumbnails'),
    onSuccess: (res) => {
      toast.success(res.data.message || 'Thumbnails re-queued')
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed'),
  })

  const generateMissingStlsMut = useMutation({
    mutationFn: () => api.post('/admin/settings/generate-missing-stls'),
    onSuccess: (res) => {
      toast.success(res.data.message || 'STL generation queued')
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed'),
  })

  type FlamencoStatus = {
    manager: { available: boolean; version: string | null; name: string | null; error?: string }
    workers: any[]
    manager_url: string
  }

  const { data: flamencoStatus, refetch: refetchFlamenco } = useQuery({
    queryKey: ['flamenco-status'],
    queryFn: async () => {
      const res = await api.get('/admin/settings/flamenco-status')
      return res.data as FlamencoStatus
    },
    refetchInterval: 30000,
    enabled: isAdmin,
  })

  const { data: actualWorkers, refetch: refetchActualWorkers } = useQuery({
    queryKey: ['flamenco-worker-actual'],
    queryFn: () => api.get('/admin/settings/flamenco-worker-actual').then(r => r.data as { running: number; available: boolean }),
    refetchInterval: 10000,
    enabled: isAdmin,
  })

  const setWorkerCountMut = useMutation({
    mutationFn: (count: number) => api.post('/admin/settings/flamenco-worker-count', { count }),
    onSuccess: (res) => {
      const d = res.data
      if (d.current >= 0) {
        toast.success(`Workers scaled: ${d.previous} → ${d.current}`)
      } else {
        toast.warning(d.message || 'Setting saved — manual scaling may be needed')
      }
      qc.invalidateQueries({ queryKey: ['admin-settings'] })
      refetchActualWorkers()
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Failed'),
  })

  return (
    <div className="p-8 space-y-8">
      <h1 className="text-2xl font-bold text-content">Admin</h1>

      {/* ------------------------------------------------------------------ */}
      {/* Pricing Summary                                                      */}
      {/* ------------------------------------------------------------------ */}
      <PricingSummaryCard />

      {/* ------------------------------------------------------------------ */}
      {/* Pricing Tiers                                                        */}
      {/* ------------------------------------------------------------------ */}
      <div className="card">
        <div className="p-4 border-b border-border-default flex items-center gap-2">
          <DollarSign size={16} className="text-content-muted" />
          <div>
            <h2 className="font-semibold text-content">Pricing Tiers</h2>
            <p className="text-xs text-content-muted mt-0.5">
              Configure price per rendering item by category and quality level.
            </p>
          </div>
        </div>
        <PricingTierTable />
      </div>

      {/* ------------------------------------------------------------------ */}
      {/* Output Types                                                          */}
      {/* ------------------------------------------------------------------ */}
      <div className="card">
        <div className="p-4 border-b border-border-light flex items-center gap-2">
          <Layers size={16} className="text-content-muted" />
          <div>
            <h2 className="font-semibold text-content">Output Types</h2>
            <p className="text-xs text-content-muted mt-0.5">
              Define what kinds of outputs orders can request (thumbnails, views, formats).
            </p>
          </div>
        </div>
        <OutputTypeTable />
      </div>

      {/* ------------------------------------------------------------------ */}
      {/* Render Templates (admin/PM)                                          */}
      {/* ------------------------------------------------------------------ */}
      <div className="card">
        <div className="p-4 border-b border-border-light flex items-center gap-2">
          <FileBox size={16} className="text-content-muted" />
          <div>
            <h2 className="font-semibold text-content">Render Templates</h2>
            <p className="text-xs text-content-muted mt-0.5">
              Upload .blend studio setups matched by Category + Output Type. Geometry is imported into the template at render time.
            </p>
          </div>
        </div>
        <div className="p-4">
          <RenderTemplateTable />
        </div>

        {/* Material Library sub-section */}
        <div className="border-t border-border-light p-4">
          <MaterialLibraryPanel />
        </div>
      </div>

      {/* ------------------------------------------------------------------ */}
      {/* Render Farm (admin only)                                             */}
      {/* ------------------------------------------------------------------ */}
      {isAdmin && <div className="card">
        <div className="p-4 border-b border-border-default flex items-center justify-between">
          <div className="flex items-center gap-2">
            <Server size={16} className="text-content-muted" />
            <div>
              <h2 className="font-semibold text-content">Render Farm</h2>
              <p className="text-xs text-content-muted mt-0.5">
                Route render jobs to Celery (stills) or Flamenco (animations).
              </p>
            </div>
          </div>
          <button
            onClick={() => refetchFlamenco()}
            className="text-content-muted hover:text-content-secondary transition-colors"
            title="Refresh Flamenco status"
          >
            <RefreshCw size={15} />
          </button>
        </div>

        <div className="p-6 space-y-5">
          {/* Global backend selector */}
          <div className="flex items-center gap-4 flex-wrap">
            <label className="text-sm font-medium text-content-secondary shrink-0">Render backend:</label>
            {(['celery', 'flamenco', 'auto'] as const).map((b) => (
              <button
                key={b}
                onClick={() => updateSettingsMut.mutate({ render_backend: b })}
                disabled={updateSettingsMut.isPending}
                title={
                  b === 'celery'
                    ? 'Celery — local Celery worker handles all render jobs (stills + animations)'
                    : b === 'flamenco'
                    ? 'Flamenco — all jobs routed to the Flamenco render farm'
                    : 'Auto — still images use Celery, animations use Flamenco'
                }
                className={`px-4 py-1.5 rounded-full border text-sm font-medium transition-colors ${
                  settings?.render_backend === b
                    ? 'text-white'
                    : 'bg-surface text-content-secondary border-border-default hover:border-accent hover:text-accent'
                }`}
                style={settings?.render_backend === b ? { backgroundColor: 'var(--color-accent)', borderColor: 'var(--color-accent)' } : undefined}
              >
                {b === 'celery' ? 'Celery' : b === 'flamenco' ? 'Flamenco' : 'Auto'}
              </button>
            ))}
            {settings?.render_backend === 'auto' && (
              <p className="text-xs text-content-muted">Stills via Celery, animations via Flamenco</p>
            )}
          </div>

          {/* Flamenco status panel */}
          <div className="rounded-lg border border-border-default bg-surface-alt p-4 space-y-3">
            <div className="flex items-center justify-between">
              <p className="text-xs font-semibold text-content-secondary uppercase tracking-wide">Flamenco Status</p>
              {flamencoStatus?.manager?.available && (
                <a
                  href="http://localhost:8080"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="flex items-center gap-1 text-xs text-accent hover:text-accent-hover"
                >
                  Open Flamenco Web UI <ExternalLink size={11} />
                </a>
              )}
            </div>

            <div className="grid grid-cols-1 md:grid-cols-2 gap-3">
              {/* Manager health */}
              <div className={`rounded-lg border p-3 flex items-start gap-2.5 ${
                flamencoStatus?.manager?.available
                  ? 'border-border-default bg-status-success-bg'
                  : 'border-border-default bg-surface-alt'
              }`}>
                {flamencoStatus?.manager?.available
                  ? <CheckCircle2 size={16} className="text-green-500 shrink-0 mt-0.5" />
                  : <XCircle size={16} className="text-content-muted shrink-0 mt-0.5" />}
                <div className="min-w-0">
                  <p className="text-sm font-semibold text-content">Manager</p>
                  <p className="text-xs text-content-muted truncate">
                    {flamencoStatus?.manager?.available
                      ? `v${flamencoStatus.manager.version || '?'}`
                      : flamencoStatus?.manager?.error || 'Offline'}
                  </p>
                </div>
              </div>

              {/* Workers */}
              <div className="rounded-lg border border-border-default bg-surface p-3">
                <p className="text-sm font-semibold text-content">
                  Workers: {flamencoStatus?.workers?.length ?? 0}
                </p>
                {flamencoStatus?.workers && flamencoStatus.workers.length > 0 && (
                  <div className="mt-1 space-y-1">
                    {flamencoStatus.workers.slice(0, 5).map((w: any, i: number) => (
                      <div key={i} className="flex items-center gap-2 text-xs">
                        <span className={`w-1.5 h-1.5 rounded-full ${
                          w.status === 'awake' || w.status === 'active' ? 'bg-green-500' : 'bg-gray-300'
                        }`} />
                        <span className="text-content-secondary">{w.name || `worker-${i + 1}`}</span>
                        <span className="text-content-muted">{w.status || '—'}</span>
                      </div>
                    ))}
                  </div>
                )}
              </div>
            </div>

            {/* Worker count control */}
            <div className="flex items-center gap-3 flex-wrap">
              <span className="text-sm font-medium text-content-secondary">Worker count:</span>
              <input
                type="number"
                min={1} max={16}
                value={workerCountDraft || settings?.flamenco_worker_count || 1}
                onChange={(e) => setWorkerCountDraft(Number(e.target.value))}
                title="Number of Flamenco worker containers to run (1–16). Each worker handles one render job at a time."
                className="w-20 px-3 py-1.5 border border-border-default rounded-md text-sm focus:outline-none focus:border-accent"
              />
              <button
                onClick={() => setWorkerCountMut.mutate(workerCountDraft || settings?.flamenco_worker_count || 1)}
                disabled={setWorkerCountMut.isPending}
                className="px-3 py-1.5 rounded-md border border-border-default bg-surface text-content-secondary text-sm font-medium hover:bg-surface-hover transition-colors"
              >
                {setWorkerCountMut.isPending ? 'Scaling…' : 'Apply'}
              </button>
              {actualWorkers?.available ? (
                <span className={`text-xs font-medium px-2 py-0.5 rounded-full ${
                  actualWorkers.running === (settings?.flamenco_worker_count || 1)
                    ? 'bg-status-success-bg text-status-success-text'
                    : 'bg-status-warning-bg text-status-warning-text'
                }`}>
                  {actualWorkers.running} running
                </span>
              ) : (
                <span className="text-xs text-content-muted">Docker socket unavailable</span>
              )}
            </div>

            {/* Advanced: Manager URL */}
            <div>
              <button
                onClick={() => setShowFlamencoAdvanced(!showFlamencoAdvanced)}
                className="flex items-center gap-1 text-xs text-content-muted hover:text-content-secondary"
              >
                {showFlamencoAdvanced ? <ChevronDown size={12} /> : <ChevronRight size={12} />}
                Advanced
              </button>
              {showFlamencoAdvanced && (
                <div className="mt-2 flex items-center gap-2">
                  <label className="text-xs text-content-muted shrink-0">Manager URL:</label>
                  <input
                    value={flamencoUrlDraft || settings?.flamenco_manager_url || ''}
                    onChange={(e) => setFlamencoUrlDraft(e.target.value)}
                    className="flex-1 px-3 py-1.5 border border-border-default rounded-md text-sm focus:outline-none focus:border-accent"
                    placeholder="http://flamenco-manager:8080"
                  />
                  <button
                    onClick={() => {
                      if (flamencoUrlDraft) updateSettingsMut.mutate({ flamenco_manager_url: flamencoUrlDraft } as any)
                    }}
                    disabled={!flamencoUrlDraft || updateSettingsMut.isPending}
                    className="px-3 py-1.5 rounded-md border border-border-default bg-surface text-content-secondary text-sm hover:bg-surface-hover"
                  >
                    Save
                  </button>
                </div>
              )}
            </div>
          </div>
        </div>
      </div>}

      {/* ------------------------------------------------------------------ */}
      {/* Users (admin only)                                                   */}
      {/* ------------------------------------------------------------------ */}
      {isAdmin && <div className="card">
        <div className="p-4 border-b border-border-default flex items-center justify-between">
          <h2 className="font-semibold text-content">Users</h2>
          <button onClick={() => setShowNewUser(!showNewUser)} className="btn-primary">
            <UserPlus size={16} />New User
          </button>
        </div>

        {showNewUser && (
          <div className="p-4 border-b border-border-light bg-surface-alt">
            <div className="grid grid-cols-2 gap-3 mb-3">
              <input
                placeholder="Full name"
                value={newUser.full_name}
                onChange={(e) => setNewUser({ ...newUser, full_name: e.target.value })}
                className="px-3 py-2 border border-border-default rounded-md text-sm"
              />
              <input
                placeholder="Email"
                type="email"
                value={newUser.email}
                onChange={(e) => setNewUser({ ...newUser, email: e.target.value })}
                className="px-3 py-2 border border-border-default rounded-md text-sm"
              />
              <input
                placeholder="Password"
                type="password"
                value={newUser.password}
                onChange={(e) => setNewUser({ ...newUser, password: e.target.value })}
                className="px-3 py-2 border border-border-default rounded-md text-sm"
              />
              <select
                value={newUser.role}
                onChange={(e) => setNewUser({ ...newUser, role: e.target.value })}
                className="px-3 py-2 border border-border-default rounded-md text-sm"
              >
                <option value="client">Client</option>
                <option value="project_manager">Project Manager</option>
                <option value="admin">Admin</option>
              </select>
            </div>
            <button
              onClick={() => createUserMut.mutate(newUser)}
              disabled={createUserMut.isPending}
              className="btn-primary"
            >
              {createUserMut.isPending ? 'Creating...' : 'Create User'}
            </button>
          </div>
        )}

        <div className="divide-y divide-border-light">
          {users?.map((user) => (
            <div key={user.id} className="flex items-center px-6 py-3">
              <div className="flex-1">
                <p className="text-sm font-medium text-content">{user.full_name}</p>
                <p className="text-xs text-content-muted">{user.email}</p>
              </div>
              <span className={`badge mr-4 ${user.role === 'admin' ? 'badge-green' : 'badge-gray'}`}>
                {user.role}
              </span>
              <span className={`badge mr-4 ${user.is_active ? 'badge-green' : 'badge-red'}`}>
                {user.is_active ? 'active' : 'inactive'}
              </span>
              <button
                onClick={() => { if (confirm('Delete user?')) deleteUserMut.mutate(user.id) }}
                className="text-content-muted hover:text-red-500 transition-colors"
                title="Delete user"
              >
                <Trash2 size={16} />
              </button>
            </div>
          ))}
        </div>
      </div>}

      {/* ------------------------------------------------------------------ */}
      {/* Renderer Settings (admin only)                                       */}
      {/* ------------------------------------------------------------------ */}
      {isAdmin && <div className="card">
        <div className="p-4 border-b border-border-default flex items-center justify-between">
          <div className="flex items-center gap-2">
            <Settings size={16} className="text-content-muted" />
            <h2 className="font-semibold text-content">Thumbnail Renderer</h2>
          </div>
          <button
            onClick={() => refetchStatus()}
            className="text-content-muted hover:text-content-secondary transition-colors"
            title="Refresh service status"
          >
            <RefreshCw size={15} />
          </button>
        </div>

        <div className="p-6 space-y-4">
          {/* Renderer picker */}
          <div className="flex items-center gap-4 flex-wrap">
            <label className="text-sm font-medium text-content-secondary shrink-0">Active renderer:</label>
            {(['pillow', 'blender', 'threejs'] as const).map((r) => (
              <button
                key={r}
                onClick={() => updateSettingsMut.mutate({ thumbnail_renderer: r })}
                disabled={updateSettingsMut.isPending}
                title={
                  r === 'pillow'
                    ? 'Python Pillow — generates a placeholder grey image (no 3D rendering)'
                    : r === 'blender'
                    ? 'Blender 5 — full ray-traced thumbnail via headless Blender (Cycles or EEVEE)'
                    : 'Three.js — WebGL render in a headless Chromium browser (fast, no GPU required)'
                }
                className={`px-4 py-1.5 rounded-full border text-sm font-medium transition-colors ${
                  settings?.thumbnail_renderer === r
                    ? 'text-white'
                    : 'bg-surface text-content-secondary border-border-default hover:border-accent hover:text-accent'
                }`}
                style={settings?.thumbnail_renderer === r ? { backgroundColor: 'var(--color-accent)', borderColor: 'var(--color-accent)' } : undefined}
              >
                {r === 'pillow' ? 'Pillow (placeholder)' : r === 'blender' ? 'Blender 5' : 'Three.js (WebGL)'}
              </button>
            ))}
          </div>

          {/* Blender options — shown only when blender is the active renderer */}
          {settings?.thumbnail_renderer === 'blender' && (
            <div className="rounded-lg border border-border-default bg-surface-alt p-4 space-y-4">
              <p className="text-xs font-semibold text-content-secondary uppercase tracking-wide">Blender 5 Options</p>

              {/* Engine */}
              <div className="flex items-center gap-6 flex-wrap">
                <span className="text-sm font-medium text-content-secondary w-28 shrink-0">Render engine</span>
                {(['cycles', 'eevee'] as const).map((eng) => (
                  <button
                    key={eng}
                    onClick={() => setBlenderDraft((d) => ({ ...d, blender_engine: eng }))}
                    title={
                      eng === 'cycles'
                        ? 'Cycles — path-tracing engine; photorealistic results but slower (affected by sample count)'
                        : 'EEVEE Next — real-time rasteriser; very fast but less physically accurate'
                    }
                    className={`px-4 py-1.5 rounded-full border text-sm font-medium transition-colors ${
                      blender.blender_engine === eng
                        ? 'bg-blue-600 text-white border-blue-600'
                        : 'bg-surface text-content-secondary border-border-default hover:border-blue-400 hover:text-blue-600'
                    }`}
                  >
                    {eng === 'cycles' ? 'Cycles (ray tracing)' : 'EEVEE Next (real-time)'}
                  </button>
                ))}
              </div>

              {/* Cycles device — only relevant for Cycles */}
              {blender.blender_engine === 'cycles' && (
                <div className="flex items-center gap-6 flex-wrap">
                  <span className="text-sm font-medium text-content-secondary w-28 shrink-0">Cycles device</span>
                  {(['auto', 'gpu', 'cpu'] as const).map((dev) => (
                    <button
                      key={dev}
                      onClick={() => setBlenderDraft((d) => ({ ...d, cycles_device: dev }))}
                      title={
                        dev === 'auto'
                          ? 'Auto — tries OptiX / CUDA / HIP first; falls back to CPU if no compatible GPU is found'
                          : dev === 'gpu'
                          ? 'GPU only — always render on GPU; logs a warning if no compatible GPU is available'
                          : 'CPU only — always render on CPU; useful for debugging or when the GPU is busy'
                      }
                      className={`px-4 py-1.5 rounded-full border text-sm font-medium transition-colors ${
                        blender.cycles_device === dev
                          ? 'bg-blue-600 text-white border-blue-600'
                          : 'bg-surface text-content-secondary border-border-default hover:border-blue-400 hover:text-blue-600'
                      }`}
                    >
                      {dev === 'auto' ? 'Auto (GPU → CPU)' : dev === 'gpu' ? 'GPU only' : 'CPU only'}
                    </button>
                  ))}
                  <p className="text-xs text-content-muted">
                    {blender.cycles_device === 'auto'
                      ? 'Tries OptiX / CUDA / HIP, falls back to CPU if no GPU is available.'
                      : blender.cycles_device === 'gpu'
                        ? 'Always use GPU. Logs a warning if no compatible GPU is found.'
                        : 'Always use CPU — useful for debugging or when GPU is busy.'}
                  </p>
                </div>
              )}

              {/* Sample counts */}
              <div className="grid grid-cols-2 gap-4 max-w-sm">
                <div>
                  <label className="block text-xs font-medium text-content-secondary mb-1">
                    Cycles samples
                  </label>
                  <input
                    type="number"
                    min={1} max={4096} step={32}
                    value={blender.blender_cycles_samples ?? 256}
                    onChange={(e) => setBlenderDraft((d) => ({ ...d, blender_cycles_samples: Number(e.target.value) }))}
                    title="Number of Cycles path-tracing samples (1–4096). Higher values = better quality + longer render time. Default: 256"
                    className="w-full px-3 py-1.5 border border-border-default rounded-md text-sm focus:outline-none focus:border-blue-400"
                  />
                  <p className="text-xs text-content-muted mt-0.5">Higher = better quality, slower</p>
                </div>
                <div>
                  <label className="block text-xs font-medium text-content-secondary mb-1">
                    EEVEE samples
                  </label>
                  <input
                    type="number"
                    min={1} max={1024} step={16}
                    value={blender.blender_eevee_samples ?? 64}
                    onChange={(e) => setBlenderDraft((d) => ({ ...d, blender_eevee_samples: Number(e.target.value) }))}
                    title="EEVEE anti-aliasing sample count (1–1024). Higher values = smoother edges + longer render time. Default: 64"
                    className="w-full px-3 py-1.5 border border-border-default rounded-md text-sm focus:outline-none focus:border-blue-400"
                  />
                  <p className="text-xs text-content-muted mt-0.5">Higher = better AA, slower</p>
                </div>
              </div>

              {/* STL quality */}
              <div className="flex items-center gap-6 flex-wrap">
                <span className="text-sm font-medium text-content-secondary w-28 shrink-0">STL quality</span>
                {(['low', 'high'] as const).map((q) => (
                  <button
                    key={q}
                    onClick={() => setBlenderDraft((d) => ({ ...d, stl_quality: q }))}
                    className={`px-4 py-1.5 rounded-full border text-sm font-medium transition-colors ${
                      blender.stl_quality === q
                        ? 'bg-blue-600 text-white border-blue-600'
                        : 'bg-surface text-content-secondary border-border-default hover:border-blue-400 hover:text-blue-600'
                    }`}
                  >
                    {q === 'low' ? 'Low (fast)' : 'High (detailed)'}
                  </button>
                ))}
                <p className="text-xs text-content-muted">
                  {blender.stl_quality === 'high'
                    ? 'Fine mesh (tol=0.01) — slower STEP→STL, sharper edges.'
                    : 'Coarse mesh (tol=0.3) — faster, good for previews.'}
                </p>
              </div>

              {/* Smooth by angle */}
              <div className="flex items-center gap-4 flex-wrap">
                <span className="text-sm font-medium text-content-secondary w-28 shrink-0">Smooth angle</span>
                <input
                  type="number"
                  min={0} max={180} step={5}
                  value={blender.blender_smooth_angle ?? 30}
                  onChange={(e) => setBlenderDraft((d) => ({ ...d, blender_smooth_angle: Number(e.target.value) }))}
                  title="Auto-smooth angle in degrees (0–180°). Faces with dihedral angles below this threshold are shaded smooth; sharper edges stay hard. 30° works well for most mechanical parts."
                  className="w-24 px-3 py-1.5 border border-border-default rounded-md text-sm focus:outline-none focus:border-blue-400"
                />
                <span className="text-sm text-content-muted">°</span>
                <p className="text-xs text-content-muted">
                  {(blender.blender_smooth_angle ?? 30) === 0
                    ? '0° = flat shading on all faces.'
                    : `Faces with edges sharper than ${blender.blender_smooth_angle ?? 30}° stay hard; others smooth. 30° works well for most mechanical parts.`}
                </p>
              </div>

              {/* Max concurrent renders */}
              <div className="flex items-center gap-4 flex-wrap">
                <span className="text-sm font-medium text-content-secondary w-28 shrink-0">Max concurrent</span>
                <input
                  type="number"
                  min={1} max={16} step={1}
                  value={blender.blender_max_concurrent_renders ?? 3}
                  onChange={(e) => setBlenderDraft((d) => ({ ...d, blender_max_concurrent_renders: Number(e.target.value) }))}
                  title="Maximum parallel Blender render jobs (1–16). Each job uses ~400 MB RAM. Applied live without restart. Default: 3"
                  className="w-24 px-3 py-1.5 border border-border-default rounded-md text-sm focus:outline-none focus:border-blue-400"
                />
                <p className="text-xs text-content-muted">
                  Max parallel Blender render jobs (1–16). Higher values use more RAM (~400 MB each). Applied live without restart.
                </p>
              </div>

              <div className="flex items-center gap-4 flex-wrap">
                <span className="text-sm font-medium text-content-secondary w-28 shrink-0">Stall timeout</span>
                <input
                  type="number"
                  min={10} max={10080} step={10}
                  value={blender.render_stall_timeout_minutes ?? 120}
                  onChange={(e) => setBlenderDraft((d) => ({ ...d, render_stall_timeout_minutes: Number(e.target.value) }))}
                  title="Minutes before a stuck render job is automatically restarted (10–10080). The watchdog checks every 5 minutes. Default: 120"
                  className="w-24 px-3 py-1.5 border border-border-default rounded-md text-sm focus:outline-none focus:border-blue-400"
                />
                <p className="text-xs text-content-muted">
                  Minutes before a stuck render job is auto-restarted (10–10080). Checked every 5 min by the watchdog.
                </p>
              </div>

              {/* Save blender options */}
              {Object.keys(blenderDraft).length > 0 && (
                <button
                  onClick={() => updateSettingsMut.mutate(blenderDraft)}
                  disabled={updateSettingsMut.isPending}
                  className="btn-primary text-sm"
                >
                  {updateSettingsMut.isPending ? 'Saving…' : 'Save Blender Options'}
                </button>
              )}
            </div>
          )}

          {/* Three.js options — shown only when threejs is the active renderer */}
          {settings?.thumbnail_renderer === 'threejs' && (
            <div className="rounded-lg border border-purple-100 bg-purple-50 p-4 space-y-3">
              <p className="text-xs font-semibold text-purple-700 uppercase tracking-wide">Three.js (WebGL) Options</p>
              <div className="flex items-center gap-4 flex-wrap">
                <span className="text-sm font-medium text-content-secondary w-28 shrink-0">Render size</span>
                {([512, 1024, 2048] as const).map((size) => (
                  <button
                    key={size}
                    onClick={() => updateSettingsMut.mutate({ threejs_render_size: size })}
                    disabled={updateSettingsMut.isPending}
                    className={`px-4 py-1.5 rounded-full border text-sm font-medium transition-colors ${
                      settings?.threejs_render_size === size
                        ? 'bg-purple-600 text-white border-purple-600'
                        : 'bg-surface text-content-secondary border-border-default hover:border-purple-400 hover:text-purple-600'
                    }`}
                  >
                    {size}px{size === 512 ? ' (1×)' : size === 1024 ? ' (2×)' : ' (4×)'}
                  </button>
                ))}
              </div>
              <p className="text-xs text-content-muted">
                Higher resolution = larger PNG thumbnails. 1024px recommended for most screens.
              </p>
            </div>
          )}

          {/* Output format — always visible, applies to all renderers */}
          <div className="flex items-center gap-4 flex-wrap pt-1">
            <label className="text-sm font-medium text-content-secondary shrink-0 w-28">Output format:</label>
            {(['jpg', 'png'] as const).map((fmt) => (
              <button
                key={fmt}
                onClick={() => updateSettingsMut.mutate({ thumbnail_format: fmt })}
                disabled={updateSettingsMut.isPending}
                className={`px-4 py-1.5 rounded-full border text-sm font-medium transition-colors ${
                  settings?.thumbnail_format === fmt
                    ? 'text-white'
                    : 'bg-surface text-content-secondary border-border-default hover:border-accent hover:text-accent'
                }`}
                style={settings?.thumbnail_format === fmt ? { backgroundColor: 'var(--color-accent)', borderColor: 'var(--color-accent)' } : undefined}
              >
                {fmt === 'jpg' ? 'JPEG (smaller)' : 'PNG (lossless)'}
              </button>
            ))}
            <p className="text-xs text-content-muted">
              {settings?.thumbnail_format === 'jpg'
                ? 'JPEG — ~3–5× smaller files, minimal quality loss at 92% quality.'
                : 'PNG — lossless, larger files.'}
            </p>
          </div>

          {/* Product thumbnail priority chain */}
          {(() => {
            let priorityList: string[] = ['latest_render', 'cad_thumbnail']
            try {
              const parsed = JSON.parse(settings?.product_thumbnail_priority ?? '["latest_render","cad_thumbnail"]')
              if (Array.isArray(parsed)) priorityList = parsed
            } catch {}

            const savePriority = (list: string[]) => {
              updateSettingsMut.mutate({ product_thumbnail_priority: JSON.stringify(list) } as any)
            }

            const moveUp = (i: number) => {
              if (i === 0) return
              const next = [...priorityList]
              ;[next[i - 1], next[i]] = [next[i], next[i - 1]]
              savePriority(next)
            }
            const moveDown = (i: number) => {
              if (i === priorityList.length - 1) return
              const next = [...priorityList]
              ;[next[i], next[i + 1]] = [next[i + 1], next[i]]
              savePriority(next)
            }
            const remove = (i: number) => savePriority(priorityList.filter((_, j) => j !== i))
            const addEntry = () => {
              if (!priorityNewEntry || priorityList.includes(priorityNewEntry)) return
              savePriority([...priorityList, priorityNewEntry])
              setPriorityNewEntry('')
            }

            const entryLabel = (e: string) =>
              e === 'cad_thumbnail' ? 'CAD Thumbnail'
              : e === 'latest_render' ? 'Latest Render (any type)'
              : outputTypes?.find((ot) => ot.id === e)?.name ?? `Output type …${e.slice(-8)}`

            const entryColor = (e: string) =>
              e === 'cad_thumbnail' ? 'bg-surface-alt border-border-default text-content-muted'
              : e === 'latest_render' ? 'bg-status-info-bg border-border-default text-status-info-text'
              : 'bg-status-success-bg border-border-default text-status-success-text'

            // Options not yet in the list
            const addableOptions = [
              ...(['latest_render', 'cad_thumbnail'] as string[]).filter((v) => !priorityList.includes(v)),
              ...(outputTypes ?? []).filter((ot) => !priorityList.includes(ot.id)).map((ot) => ot.id),
            ]

            return (
              <div className="flex items-start gap-4 pt-1">
                <label className="text-sm font-medium text-content-secondary shrink-0 w-28 pt-1">Product thumbnail:</label>
                <div className="flex flex-col gap-2 min-w-[280px]">
                  {priorityList.map((entry, i) => (
                    <div
                      key={entry + i}
                      className={`flex items-center gap-2 border rounded-lg px-3 py-2 ${entryColor(entry)}`}
                    >
                      <span className="text-xs font-mono text-content-muted w-4 shrink-0">{i + 1}</span>
                      <div className="flex-1 min-w-0">
                        <span className="text-sm font-medium truncate block">{entryLabel(entry)}</span>
                        {entry !== 'cad_thumbnail' && entry !== 'latest_render' && (
                          <span className="text-xs text-content-muted">newest completed render</span>
                        )}
                      </div>
                      <button
                        disabled={i === 0 || updateSettingsMut.isPending}
                        onClick={() => moveUp(i)}
                        className="p-0.5 rounded hover:bg-surface-hover disabled:opacity-30 text-content-muted"
                        title="Move up"
                      >
                        <ChevronUp size={14} />
                      </button>
                      <button
                        disabled={i === priorityList.length - 1 || updateSettingsMut.isPending}
                        onClick={() => moveDown(i)}
                        className="p-0.5 rounded hover:bg-surface-hover disabled:opacity-30 text-content-muted"
                        title="Move down"
                      >
                        <ChevronDown size={14} />
                      </button>
                      <button
                        disabled={updateSettingsMut.isPending}
                        onClick={() => remove(i)}
                        className="p-0.5 rounded hover:bg-status-error-bg text-content-muted hover:text-red-600"
                        title="Remove"
                      >
                        <X size={14} />
                      </button>
                    </div>
                  ))}

                  {addableOptions.length > 0 && (
                    <div className="flex items-center gap-2">
                      <select
                        value={priorityNewEntry}
                        onChange={(e) => setPriorityNewEntry(e.target.value)}
                        className="flex-1 px-2 py-1.5 border border-border-default rounded-md text-sm focus:outline-none focus:border-accent"
                      >
                        <option value="">Add entry…</option>
                        {addableOptions.map((v) => (
                          <option key={v} value={v}>{entryLabel(v)}</option>
                        ))}
                      </select>
                      <button
                        disabled={!priorityNewEntry || updateSettingsMut.isPending}
                        onClick={addEntry}
                        className="btn-secondary py-1.5 px-3 text-sm flex items-center gap-1 disabled:opacity-40"
                      >
                        <Plus size={13} /> Add
                      </button>
                    </div>
                  )}

                  <p className="text-xs text-content-muted">
                    Sources are tried top to bottom. For specific output types, the <span className="font-medium">newest completed render</span> of that type is used. "CAD Thumbnail" always matches and stops the search.
                  </p>
                </div>
              </div>
            )
          })()}

          {/* Service health */}
          <div className="grid grid-cols-1 md:grid-cols-3 gap-3">
            {rendererStatus && Object.entries(rendererStatus).map(([name, info]) => (
              <div
                key={name}
                className={`rounded-lg border p-3 flex items-start gap-2.5 ${
                  info.available ? 'border-border-default bg-status-success-bg' : 'border-border-default bg-surface-alt'
                }`}
              >
                {info.available
                  ? <CheckCircle2 size={16} className="text-green-500 shrink-0 mt-0.5" />
                  : info.url === null
                    ? <CheckCircle2 size={16} className="text-green-500 shrink-0 mt-0.5" />
                    : <XCircle size={16} className="text-content-muted shrink-0 mt-0.5" />
                }
                <div className="min-w-0">
                  <p className="text-sm font-semibold text-content capitalize">{name}</p>
                  <p className="text-xs text-content-muted truncate">{info.note || (info.available ? 'Online' : 'Offline')}</p>
                </div>
              </div>
            ))}
            {!rendererStatus && (
              <div className="col-span-3 flex items-center gap-2 text-xs text-content-muted p-2">
                <Clock size={13} /> Checking service status…
              </div>
            )}
          </div>

          {/* Process unprocessed / Regenerate thumbnails */}
          <div className="pt-2 border-t border-border-light space-y-2">
            <div className="flex items-center gap-3">
              <button
                onClick={() => processUnprocessedMut.mutate()}
                disabled={processUnprocessedMut.isPending}
                className="btn-secondary text-sm"
                title="Queue all pending and failed STEP files that have never been successfully processed"
              >
                <RefreshCw size={14} className={processUnprocessedMut.isPending ? 'animate-spin' : ''} />
                {processUnprocessedMut.isPending ? 'Queueing…' : 'Process Unprocessed'}
              </button>
              <p className="text-xs text-content-muted">
                Queues all pending and failed STEP files for initial processing.
              </p>
            </div>
            <div className="flex items-center gap-3">
              <button
                onClick={() => regenerateMut.mutate()}
                disabled={regenerateMut.isPending}
                className="btn-secondary text-sm"
                title="Re-process all existing STEP files to regenerate thumbnails using the currently selected renderer"
              >
                <RefreshCw size={14} className={regenerateMut.isPending ? 'animate-spin' : ''} />
                {regenerateMut.isPending ? 'Re-queuing…' : 'Regenerate All Thumbnails'}
              </button>
              <p className="text-xs text-content-muted">
                Re-processes all existing STEP files with the currently selected renderer.
              </p>
            </div>
            <div className="flex items-center gap-3">
              <button
                onClick={() => generateMissingStlsMut.mutate()}
                disabled={generateMissingStlsMut.isPending}
                className="btn-secondary text-sm"
                title="Queue STL conversion for every low/high quality that is not yet cached on disk"
              >
                <RefreshCw size={14} className={generateMissingStlsMut.isPending ? 'animate-spin' : ''} />
                {generateMissingStlsMut.isPending ? 'Queueing…' : 'Generate Missing STLs'}
              </button>
              <p className="text-xs text-content-muted">
                Generates low + high STL files for any completed STEP file that is missing them.
              </p>
            </div>
          </div>
        </div>
      </div>}

      {/* ------------------------------------------------------------------ */}
      {/* Templates                                                            */}
      {/* ------------------------------------------------------------------ */}
      <div className="card">
        <div className="p-4 border-b border-border-default">
          <h2 className="font-semibold text-content">Templates</h2>
          <p className="text-xs text-content-muted mt-0.5">
            Click Edit to configure standard fields and component schema for each template.
          </p>
        </div>
        <div className="divide-y divide-border-light">
          {templates?.map((t) => {
            const isEditing = editingTemplateId === t.id
            return (
              <div key={t.id}>
                {/* Row */}
                <div className="flex items-center px-6 py-3 gap-3">
                  <button
                    onClick={() => setEditingTemplateId(isEditing ? null : t.id)}
                    className="text-content-muted hover:text-content-secondary transition-colors shrink-0"
                    aria-label={isEditing ? 'Collapse editor' : 'Expand editor'}
                    title={isEditing ? 'Collapse template editor' : 'Expand template editor'}
                  >
                    {isEditing ? <ChevronDown size={16} /> : <ChevronRight size={16} />}
                  </button>
                  <div className="flex-1 min-w-0">
                    <p className="text-sm font-medium text-content">{t.name}</p>
                    <p className="text-xs text-content-muted font-mono">{t.category_key}</p>
                  </div>
                  <span className={`badge ${t.is_active ? 'badge-green' : 'badge-gray'}`}>
                    {t.is_active ? 'active' : 'inactive'}
                  </span>
                  <button
                    onClick={() => setEditingTemplateId(isEditing ? null : t.id)}
                    className="flex items-center gap-1.5 px-3 py-1 rounded-md border border-border-default text-xs text-content-secondary hover:bg-surface-hover hover:border-accent hover:text-accent transition-colors"
                  >
                    <Pencil size={12} />
                    {isEditing ? 'Close' : 'Edit'}
                  </button>
                </div>

                {/* Inline editor panel */}
                {isEditing && (
                  <div className="px-6 pb-6">
                    <TemplateEditor
                      template={t}
                      onClose={() => setEditingTemplateId(null)}
                    />
                  </div>
                )}
              </div>
            )
          })}
        </div>
      </div>

      {/* ------------------------------------------------------------------ */}
      {/* Material Library link                                               */}
      {/* ------------------------------------------------------------------ */}
      <div className="card p-5 flex items-center justify-between">
        <div>
          <h2 className="font-semibold text-content">Material Library</h2>
          <p className="text-xs text-content-muted mt-0.5">
            Manage shared materials for CAD part assignments.
          </p>
        </div>
        <Link to="/materials" className="btn-secondary text-sm">
          Open Material Library →
        </Link>
      </div>
    </div>
  )
}


function MaterialLibraryPanel() {
  const qc = useQueryClient()

  const { data: info } = useQuery({
    queryKey: ['material-library-info'],
    queryFn: getMaterialLibraryInfo,
  })

  const uploadMut = useMutation({
    mutationFn: (file: File) => uploadMaterialLibrary(file),
    onSuccess: () => {
      toast.success('Material library uploaded')
      qc.invalidateQueries({ queryKey: ['material-library-info'] })
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Upload failed'),
  })

  const deleteMut = useMutation({
    mutationFn: deleteMaterialLibrary,
    onSuccess: () => {
      toast.success('Material library removed')
      qc.invalidateQueries({ queryKey: ['material-library-info'] })
    },
    onError: (e: any) => toast.error(e.response?.data?.detail || 'Delete failed'),
  })

  function handleFileChange(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0]
    if (file) uploadMut.mutate(file)
    e.target.value = ''
  }

  return (
    <div className="space-y-3">
      <h4 className="text-sm font-semibold text-content-secondary">Material Library (.blend)</h4>
      <p className="text-xs text-content-muted">
        Materials in this file can be assigned to product parts when "Material Replace" is enabled on a template.
      </p>

      {info?.exists ? (
        <div className="flex items-center gap-3 p-3 rounded-lg border border-border-default bg-status-success-bg">
          <CheckCircle2 size={16} className="text-green-500 shrink-0" />
          <div className="flex-1 min-w-0">
            <p className="text-sm font-medium text-content">{info.filename}</p>
            <p className="text-xs text-content-muted">
              {info.size_bytes ? `${(info.size_bytes / 1024 / 1024).toFixed(1)} MB` : ''}
            </p>
          </div>
          <label className="flex items-center gap-1 px-3 py-1.5 text-sm border border-border-default rounded-md bg-surface text-content-secondary hover:bg-surface-hover cursor-pointer">
            <Upload size={14} /> Replace
            <input type="file" accept=".blend" className="hidden" onChange={handleFileChange} />
          </label>
          <button
            onClick={() => { if (confirm('Remove material library?')) deleteMut.mutate() }}
            disabled={deleteMut.isPending}
            className="p-1.5 text-red-500 hover:bg-red-50 rounded"
            title="Remove library"
          >
            <Trash2 size={16} />
          </button>
        </div>
      ) : (
        <label className="flex items-center gap-2 px-4 py-3 border-2 border-dashed border-border-default rounded-lg text-sm text-content-muted hover:border-blue-400 hover:text-blue-600 cursor-pointer transition-colors">
          <Upload size={16} />
          {uploadMut.isPending ? 'Uploading...' : 'Click to upload material library .blend file'}
          <input type="file" accept=".blend" className="hidden" onChange={handleFileChange} />
        </label>
      )}
    </div>
  )
}


function PricingSummaryCard() {
  const { data: tiers } = useQuery({
    queryKey: ['pricing-tiers'],
    queryFn: listPricingTiers,
  })
  const { data: outputTypes } = useQuery({
    queryKey: ['output-types-admin'],
    queryFn: () => listOutputTypes(true),
  })

  const defaultTier = tiers?.find((t) => t.category_key === 'default' && t.is_active)
  const activeTiers = tiers?.filter((t) => t.is_active).length ?? 0
  const totalOTs = outputTypes?.length ?? 0
  const otsWithTier = outputTypes?.filter((ot) => ot.pricing_tier_id != null).length ?? 0

  return (
    <div className="card">
      <div className="p-4 border-b border-border-default flex items-center gap-2">
        <DollarSign size={16} className="text-content-muted" />
        <h2 className="font-semibold text-content">Pricing Overview</h2>
      </div>
      <div className="p-4 grid grid-cols-2 md:grid-cols-4 gap-4">
        <div className="text-center">
          <p className="text-2xl font-bold text-content">
            {defaultTier ? `${Number(defaultTier.price_per_item).toFixed(2)}` : '—'}
          </p>
          <p className="text-xs text-content-muted">Global default price</p>
          {!defaultTier && (
            <p className="text-xs text-amber-600 flex items-center justify-center gap-1 mt-1">
              <AlertTriangle size={10} /> Not configured
            </p>
          )}
        </div>
        <div className="text-center">
          <p className="text-2xl font-bold text-content">{activeTiers}</p>
          <p className="text-xs text-content-muted">Active pricing tiers</p>
        </div>
        <div className="text-center">
          <p className="text-2xl font-bold text-content">{otsWithTier} / {totalOTs}</p>
          <p className="text-xs text-content-muted">Output types with explicit tier</p>
        </div>
        <div className="text-center">
          <p className="text-2xl font-bold text-content">{totalOTs - otsWithTier}</p>
          <p className="text-xs text-content-muted">Using category default</p>
        </div>
      </div>
    </div>
  )
}
