import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import type { ComponentType, ReactNode } from 'react'
import {
  AlertTriangle,
  Archive,
  ArrowDownToLine,
  ArrowLeft,
  ArrowRight,
  Box,
  Check,
  CheckCircle2,
  ChevronDown,
  ChevronRight,
  Circle,
  CircleDot,
  Clock3,
  Code2,
  Command,
  Copy,
  Download,
  FileBox,
  FilePlus2,
  FileText,
  FolderOpen,
  HardDrive,
  HelpCircle,
  Layers3,
  LayoutGrid,
  ListTree,
  Menu,
  MoreHorizontal,
  PanelBottom,
  PanelLeft,
  PanelRight,
  Pause,
  Pencil,
  Plus,
  Rotate3D,
  Save,
  Search,
  Settings2,
  SlidersHorizontal,
  Sparkles,
  SquareStack,
  Trash2,
  Undo2,
  Redo2,
  RefreshCw,
  Upload,
  UserRound,
  WandSparkles,
  X,
  ZoomIn,
  ZoomOut,
} from 'lucide-react'
import { menuDefinitions, pinnedWorkbenches, workbenchDefinitions, type MenuName, type WorkbenchId } from './freecadManifest'
import { createMockFacade, type BitBybitViewportAdapter, type BitBybitWebCadFacade, type DiagnosticTreeNode, type DocumentSnapshot, type FcstdInspection, type ModelTreeItem, type ObjectPropertySnapshot, type PlacementValue, type ProjectSummary, type PropertyValue, type ShapeHandle } from './facade'

type Page = 'start' | 'projects' | 'workspace' | 'import' | 'export' | 'settings' | 'help' | 'diagnostics' | 'sync'
type Workbench = WorkbenchId

type Icon = ComponentType<{ size?: string | number; strokeWidth?: string | number; className?: string }>

const pageFromPath = (): Page => {
  const path = window.location.pathname
  if (path.startsWith('/projects')) return 'projects'
  if (path.startsWith('/workspace')) return 'workspace'
  if (path.startsWith('/import')) return 'import'
  if (path.startsWith('/export')) return 'export'
  if (path.startsWith('/settings')) return 'settings'
  if (path.startsWith('/help')) return 'help'
  if (path.startsWith('/diagnostics')) return 'diagnostics'
  if (path.startsWith('/sync')) return 'sync'
  return 'start'
}

const iconMap: Record<string, Icon> = {
  box: Box, 'circle-dot': CircleDot, 'square-stack': SquareStack, 'file-text': FileText, 'layout-grid': LayoutGrid,
  layers: Layers3, archive: Archive, pencil: Pencil, copy: Copy, 'arrow-up': ArrowDownToLine, 'arrow-down': ArrowDownToLine,
  rotate: Rotate3D, 'sliders-horizontal': SlidersHorizontal, search: Search, upload: Upload, download: Download, 'file-plus': FilePlus2,
  'code-2': Code2, 'settings-2': Settings2, 'circle-check': CheckCircle2, 'triangle-alert': AlertTriangle, eye: CircleDot,
  'zoom-in': ZoomIn, 'grid-3x3': LayoutGrid, play: Check, plus: Plus, minus: X, circle: Circle, route: Rotate3D, 'git-branch': Layers3,
  'layers-2': Layers3, 'flip-horizontal': ArrowLeft, repeat: Rotate3D, 'refresh-cw': Rotate3D, shuffle: MoreHorizontal,
  'corner-down-right': SlidersHorizontal, scissors: X, triangle: Box, paperclip: Copy, 'move-horizontal': ArrowRight, 'move-vertical': ArrowDownToLine,
  magnet: CircleDot, move: ArrowRight, type: FileText, 'panels-top-left': LayoutGrid, maximize: PanelRight, table: LayoutGrid, tag: FileText,
  'rows-3': ListTree, link: Copy, paintbrush: WandSparkles, pin: PanelLeft, anchor: CircleDot, split: ArrowRight, target: CircleDot,
  protractor: SlidersHorizontal, activity: Rotate3D, lock: Circle, spline: Rotate3D, crosshair: CircleDot, 'file-box': FileBox,
}

const workbenchIconKeys: Record<Workbench, string> = {
  'Part Design': 'box', Part: 'box', Sketcher: 'circle-dot', Draft: 'square-stack', BIM: 'layers', TechDraw: 'file-text', Spreadsheet: 'layout-grid', Assembly: 'layers', CAM: 'settings-2', FEM: 'activity', Mesh: 'archive', Surface: 'spline', Inspection: 'search',
}

const workbenchMeta: Record<Workbench, { icon: Icon; accent: string; description: string }> = Object.fromEntries(
  Object.entries(workbenchDefinitions).map(([id, definition]) => [id, { icon: iconMap[workbenchIconKeys[id as Workbench]] || MoreHorizontal, accent: id === 'Sketcher' ? 'violet' : id === 'Part' ? 'amber' : 'cyan', description: definition.description }]),
) as Record<Workbench, { icon: Icon; accent: string; description: string }>

function CuboidIcon({ size = 18, strokeWidth = 1.8, className }: { size?: string | number; strokeWidth?: string | number; className?: string }) {
  return <Box size={size} strokeWidth={strokeWidth} className={className} />
}

const projects = [
  { name: 'Pump Housing', path: 'Local / Mechanical / Pump Housing', modified: 'Just now', objects: 18, state: 'Unsaved' },
  { name: 'Mounting Bracket', path: 'Local / Concepts / Mounting Bracket', modified: 'Yesterday', objects: 9, state: 'Saved' },
  { name: 'Motor Assembly', path: 'Local / Assemblies / Motor Assembly', modified: '28 Jul 2026', objects: 142, state: 'Saved' },
  { name: 'Valve Body Study', path: 'Shared / Review / Valve Body Study', modified: '22 Jul 2026', objects: 31, state: 'Read only' },
]

const IconButton = ({ icon: IconComponent, label, onClick, active = false, disabled = false }: { icon: Icon; label: string; onClick?: () => void; active?: boolean; disabled?: boolean }) => (
  <button className={`icon-button ${active ? 'is-active' : ''}`} title={label} aria-label={label} onClick={onClick} disabled={disabled}>
    <IconComponent size={16} strokeWidth={1.8} />
  </button>
)

const Badge = ({ tone, children }: { tone: 'cyan' | 'green' | 'amber' | 'red' | 'muted'; children: ReactNode }) => (
  <span className={`badge badge-${tone}`}>
    <span className="badge-dot" />
    {children}
  </span>
)

function App() {
  const [page, setPage] = useState<Page>(pageFromPath)
  const [leftTab, setLeftTab] = useState<'model' | 'tasks'>('model')
  const [rightTab, setRightTab] = useState<'data' | 'view'>('data')
  const [bottomOpen, setBottomOpen] = useState(true)
  const [notice, setNotice] = useState('')
  const facade = useMemo(() => createMockFacade(), [])
  const [facadeState, setFacadeState] = useState(() => facade.getState())

  useEffect(() => facade.subscribe((event) => {
    if (event.type === 'state.changed') setFacadeState(event.state)
    if (event.type === 'notice') {
      setNotice(event.message)
      window.setTimeout(() => setNotice(''), 2600)
    }
  }), [facade])

  useEffect(() => facade.project.subscribeExternalChanges((notice) => {
    setNotice(`Project saved in another tab · v${notice.documentVersion}`)
    window.setTimeout(() => setNotice(''), 2600)
  }), [facade])

  useEffect(() => () => facade.geometry.dispose(), [facade])

  useEffect(() => {
    const handlePopState = () => setPage(pageFromPath())
    window.addEventListener('popstate', handlePopState)
    return () => window.removeEventListener('popstate', handlePopState)
  }, [])

  const navigate = (next: Page, replace = false) => {
    const paths: Record<Page, string> = {
      start: '/start',
      projects: '/projects',
      workspace: '/workspace/pump-housing',
      import: '/import',
      export: '/export',
      settings: '/settings',
      help: '/help',
      diagnostics: '/diagnostics',
      sync: '/sync',
    }
    window.history[replace ? 'replaceState' : 'pushState']({}, '', paths[next])
    setPage(next)
  }

  const openWorkspace = () => navigate('workspace')
  const workbench = facadeState.activeWorkbench
  const selectedObject = facadeState.selectedObjectId
  const currentWorkbench = workbenchMeta[workbench]
  const CurrentIcon = currentWorkbench.icon

  const showNotice = useCallback((message: string) => facade.notify(message), [facade])
  const setWorkbench = useCallback((value: Workbench) => facade.gui.workbench.setActive(value), [facade])
  const setSelectedObject = useCallback((id: string) => id ? facade.selection.select(id) : facade.selection.clear(), [facade])

  return (
    <div className="app-shell" data-persistence-mode={facadeState.persistence.mode}>
      <TopBar page={page} workbench={workbench} facade={facade} onNavigate={navigate} onOpenWorkspace={openWorkspace} />
      {page === 'workspace' ? (
        <Workspace
          workbench={workbench}
          onNavigate={navigate}
          setWorkbench={(value) => { setWorkbench(value); setLeftTab('tasks') }}
          leftTab={leftTab}
          setLeftTab={setLeftTab}
          rightTab={rightTab}
          setRightTab={setRightTab}
          bottomOpen={bottomOpen}
          setBottomOpen={setBottomOpen}
          selectedObject={selectedObject}
          setSelectedObject={setSelectedObject}
          document={facadeState.document}
          facade={facade}
          workbenchIcon={CurrentIcon}
          showNotice={showNotice}
        />
      ) : (
        <PageFrame page={page} onNavigate={navigate} onOpenWorkspace={openWorkspace} showNotice={showNotice} facade={facade} />
      )}
      {notice && <div className="toast"><CheckCircle2 size={16} />{notice}</div>}
    </div>
  )
}

function TopBar({ page, workbench, facade, onNavigate, onOpenWorkspace }: { page: Page; workbench: Workbench; facade: BitBybitWebCadFacade; onNavigate: (page: Page) => void; onOpenWorkspace: () => void }) {
  const [openMenu, setOpenMenu] = useState<MenuName | null>(null)
  const document = facade.getState().document
  const handleMenuCommand = (command: string) => {
    setOpenMenu(null)
    if (command === 'help' || command === 'shortcuts') onNavigate('help')
    else if (command === 'diagnostics') onNavigate('diagnostics')
    else if (command === 'preferences' || command === 'project-settings' || command === 'parameters') onNavigate('settings')
    else if (command === 'import') onNavigate('import')
    else if (command === 'export') onNavigate('export')
    else if (command === 'open') onNavigate('projects')
    else onOpenWorkspace()
  }
  return (
    <header className="topbar">
      <div className="brand-lockup" onClick={() => onNavigate('start')} role="button" tabIndex={0}>
        <div className="brand-mark"><span /><span /><span /></div>
        <div><div className="brand-name">BitBybit</div><div className="brand-product">CAD studio</div></div>
      </div>
      <nav className="top-menu" aria-label="Application menu">
        {(Object.keys(menuDefinitions) as MenuName[]).map((menu) => <div className="menu-wrapper" key={menu}><button className={openMenu === menu ? 'is-open' : ''} onClick={() => setOpenMenu(openMenu === menu ? null : menu)} aria-expanded={openMenu === menu}>{menu}</button>{openMenu === menu && <div className="menu-popover">{menuDefinitions[menu].map((item) => <button key={item.command} onClick={() => handleMenuCommand(item.command)}><span>{item.label}</span>{'shortcut' in item && <kbd>{item.shortcut}</kbd>}</button>)}</div>}</div>)}
      </nav>
      <div className="topbar-spacer" />
      <div className="topbar-context">
        <div className="context-document"><span className="context-dot" />{document.label} <span className="context-separator">/</span> {workbench}</div>
        <span className="save-state"><span className="save-dot" />{document.dirty ? 'Unsaved changes' : 'Saved locally'}</span>
      </div>
      <IconButton icon={Undo2} label="Undo" onClick={() => facade.history.undo()} disabled={!facade.history.canUndo()} />
      <IconButton icon={Redo2} label="Redo" onClick={() => facade.history.redo()} disabled={!facade.history.canRedo()} />
      <div className="topbar-divider" />
      <button className="command-search" onClick={() => onNavigate('help')}><Search size={15} /><span>Search commands</span><kbd>⌘ K</kbd></button>
      <IconButton icon={HelpCircle} label="Help" onClick={() => onNavigate('help')} />
      <button className="avatar-button" title="Account and sync" onClick={() => onNavigate('sync')}><UserRound size={16} /><span>MS</span></button>
    </header>
  )
}

function Workspace({ workbench, onNavigate, setWorkbench, leftTab, setLeftTab, rightTab, setRightTab, bottomOpen, setBottomOpen, selectedObject, setSelectedObject, document, facade, workbenchIcon: WorkbenchIcon, showNotice }: {
  workbench: Workbench
  onNavigate: (page: Page) => void
  setWorkbench: (value: Workbench) => void
  leftTab: 'model' | 'tasks'
  setLeftTab: (tab: 'model' | 'tasks') => void
  rightTab: 'data' | 'view'
  setRightTab: (tab: 'data' | 'view') => void
  bottomOpen: boolean
  setBottomOpen: (open: boolean) => void
  selectedObject: string
  setSelectedObject: (id: string) => void
  document: DocumentSnapshot
  facade: BitBybitWebCadFacade
  workbenchIcon: Icon
  showNotice: (message: string) => void
}) {
  return (
    <main className="workspace-page">
      <div className="workspace-toolbar">
        <div className="workbench-picker"><WorkbenchIcon size={17} /><select value={workbench} onChange={(event) => setWorkbench(event.target.value as Workbench)} aria-label="Workbench">{Object.keys(workbenchDefinitions).map((option) => <option key={option}>{option}</option>)}</select><ChevronDown size={14} /></div>
        <div className="toolbar-divider" />
        <IconButton icon={FilePlus2} label="New document" onClick={() => { facade.gui.command.execute({ commandId: 'new-document' }); showNotice('New document prepared') }} />
        <IconButton icon={FolderOpen} label="Open project" onClick={() => onNavigate('projects')} />
        <IconButton icon={Save} label="Save project" onClick={() => { facade.gui.command.execute({ commandId: 'save' }); showNotice('Saved to local workspace') }} />
        <IconButton icon={RefreshCw} label="Recompute document" disabled={document.readOnly} onClick={() => { void facade.app.document.recomputeAsync().then((result) => showNotice(result.status === 'completed' ? 'Recompute completed' : `Recompute ${result.status}`)) }} />
        <div className="toolbar-divider" />
        <IconButton icon={Box} label="Create body" onClick={() => { facade.gui.command.execute({ commandId: 'create-body' }); showNotice('Create Body task opened') }} active={workbench === 'Part Design'} />
        <IconButton icon={CircleDot} label="Create sketch" onClick={() => { facade.gui.command.execute({ commandId: 'create-sketch' }); showNotice('Select a plane to create a sketch') }} />
        <IconButton icon={Rotate3D} label="Transform" />
        <IconButton icon={SlidersHorizontal} label="Measure" />
        <div className="toolbar-spacer" />
        <div className="toolbar-status"><span className="status-pulse" />Local workspace</div>
        <IconButton icon={PanelLeft} label="Toggle left panel" />
        <IconButton icon={PanelRight} label="Toggle right panel" />
      </div>
      <WorkbenchNavBar workbench={workbench} setWorkbench={setWorkbench} showNotice={showNotice} />
      <div className="document-tabs">
        <button className="doc-tab is-active"><FileBox size={15} /><span>{document.label}</span>{document.dirty && <span className="doc-unsaved" />}<X size={13} /></button>
        <button className="doc-tab" onClick={() => showNotice('Open Mounting Bracket') }><FileBox size={15} /><span>Mounting Bracket</span><X size={13} /></button>
        <button className="new-tab" title="New document"><Plus size={16} /></button>
        <div className="document-tab-spacer" />
        <span className="document-meta">{document.units} · {document.objects.length} objects · v{document.version}</span>
      </div>
      <div className="workspace-content">
        <aside className="combo-panel left-panel">
          <div className="panel-tabs"><button className={leftTab === 'model' ? 'is-active' : ''} onClick={() => setLeftTab('model')}><ListTree size={14} />Model</button><button className={leftTab === 'tasks' ? 'is-active' : ''} onClick={() => setLeftTab('tasks')}><SlidersHorizontal size={14} />Tasks <span className="tab-count">1</span></button></div>
          {leftTab === 'model' ? <div className="combo-model"><ModelTree document={document} selectedObject={selectedObject} setSelectedObject={setSelectedObject} showNotice={showNotice} /><div className="combo-property"><div className="property-heading"><div><span className="eyebrow">Property view</span><h2>{document.tree.find((item) => item.id === selectedObject)?.label || 'No selection'}</h2></div><IconButton icon={MoreHorizontal} label="More object actions" /></div><div className="panel-tabs property-tabs"><button className={rightTab === 'data' ? 'is-active' : ''} onClick={() => setRightTab('data')}>Data</button><button className={rightTab === 'view' ? 'is-active' : ''} onClick={() => setRightTab('view')}>View</button></div><PropertyPanel key={rightTab} facade={facade} objectId={selectedObject} scope={rightTab} showNotice={showNotice} /></div></div> : <div className="model-task-summary"><span className="eyebrow">Combo View task tab</span><p>Use the right Task panel for command parameters. This tab stays available for selection and dependency context.</p><button className="button button-outline" onClick={() => showNotice('Selection filter enabled')}><Search size={14} />Selection filter</button></div>}
        </aside>
        <section className="viewport-region">
          <Viewport selectedObject={selectedObject} setSelectedObject={setSelectedObject} workbench={workbench} facade={facade} documentVersion={document.version} recomputeGeneration={document.recompute?.generation ?? 0} showNotice={showNotice} />
          <div className="viewport-bottom-left"><div className="view-chip"><Circle size={8} fill="currentColor" /> Perspective</div><div className="view-chip">Grid 10 mm</div></div>
          <div className="viewport-bottom-right"><div className="axis-widget"><span className="axis-x">X</span><span className="axis-y">Y</span><span className="axis-z">Z</span><div className="axis-origin" /></div></div>
        </section>
        <aside className="task-dock right-panel"><div className="task-dock-title"><div><span className="eyebrow">Task panel</span><h2>{workbenchDefinitions[workbench].taskTitle}</h2></div><IconButton icon={MoreHorizontal} label="Task panel actions" /></div><TaskPanel workbench={workbench} facade={facade} showNotice={showNotice} /></aside>
        <FunctionRail workbench={workbench} facade={facade} showNotice={showNotice} />
      </div>
      <div className={`bottom-drawer ${bottomOpen ? 'is-open' : ''}`}>
        <div className="bottom-drawer-header"><div className="drawer-tabs"><button className="is-active"><PanelBottom size={14} />Report view <span className="tab-count">2</span></button><button><Clock3 size={14} />Jobs <span className="tab-count tab-count-green">1</span></button><button><Code2 size={14} />Diagnostics</button></div><button className="drawer-toggle" onClick={() => setBottomOpen(!bottomOpen)} title={bottomOpen ? 'Collapse bottom panel' : 'Expand bottom panel'}>{bottomOpen ? <ChevronDown size={15} /> : <ChevronRight size={15} />}</button></div>
        {bottomOpen && <div className="bottom-drawer-content"><div className="report-line">{document.recompute?.status === 'failed' ? <AlertTriangle size={14} className="icon-amber" /> : <CheckCircle2 size={14} className="icon-green" />}<span>Recompute {document.recompute?.status || 'idle'}</span><span className="report-context">{document.recompute?.order.length || 0} objects in plan</span><span className="report-time">generation {document.recompute?.generation || 0}</span></div>{(document.recompute?.errors || []).slice(0, 2).map((error) => <div className="report-line" key={`${error.objectId}-${error.code}`}><AlertTriangle size={14} className="icon-amber" /><span>{error.message}</span><button onClick={() => showNotice(`Dependency review: ${error.objectId}`)}>Review dependency</button><span className="report-time">{error.code}</span></div>)}</div>}
      </div>
    </main>
  )
}

function WorkbenchNavBar({ workbench, setWorkbench, showNotice }: { workbench: Workbench; setWorkbench: (value: Workbench) => void; showNotice: (message: string) => void }) {
  return <div className="workbench-nav" aria-label="Workbench navigation"><span className="nav-caption">Workbench</span>{pinnedWorkbenches.map((item) => { const IconComponent = workbenchMeta[item].icon; return <button key={item} className={workbench === item ? 'is-active' : ''} onClick={() => { setWorkbench(item); showNotice(`${item} workbench loaded`) }}><IconComponent size={13} /><span>{item}</span></button> })}<button className="nav-more" onClick={() => showNotice('All workbenches available from the picker')}><MoreHorizontal size={14} /><span>More workbenches</span></button></div>
}

function FunctionRail({ workbench, facade, showNotice }: { workbench: Workbench; facade: BitBybitWebCadFacade; showNotice: (message: string) => void }) {
  const groups = workbenchDefinitions[workbench].groups
  return <aside className="function-rail" aria-label={`${workbench} commands`}>{groups.map((group) => <div className="rail-group" key={group.label}><span className="rail-group-label">{group.label}</span>{group.commands.slice(0, 5).map((item) => { const IconComponent = iconMap[item.icon] || MoreHorizontal; const state = facade.gui.command.getState(item.id); const title = state.status === 'disabled' && state.reason ? `${item.label}: ${state.reason}` : `${item.label}${item.shortcut ? ` (${item.shortcut})` : ''}`; return <button key={item.id} title={title} aria-label={title} disabled={state.status === 'disabled'} onClick={() => { facade.gui.command.execute({ commandId: item.id }); showNotice(`${item.label} command staged`) }}><IconComponent size={15} /></button> })}</div>)}</aside>
}

function ModelTree({ document, selectedObject, setSelectedObject, showNotice }: { document: DocumentSnapshot; selectedObject: string; setSelectedObject: (id: string) => void; showNotice: (message: string) => void }) {
  const [expanded, setExpanded] = useState<Record<string, boolean>>({ origin: false, body: true, reference: false })
  const itemsById = new Map(document.tree.map((item) => [item.id, item]))
  const childIds = new Set(document.tree.flatMap((item) => item.children || []))
  return <div className="model-tree">
    <div className="tree-toolbar"><div className="tree-search"><Search size={14} /><input placeholder="Filter objects" /></div><IconButton icon={MoreHorizontal} label="Model tree actions" /></div>
    <div className="tree-root"><div className="tree-document-row"><ChevronDown size={14} /><FileBox size={15} className="icon-cyan" /><span>{document.label}</span><span className="tree-version">v{document.version}</span></div>
      {document.tree.filter((item) => !childIds.has(item.id)).map((item) => <TreeItem key={item.id} item={item} level={1} expanded={expanded[item.id]} onToggle={() => setExpanded((current) => ({ ...current, [item.id]: !current[item.id] }))} itemsById={itemsById} selectedObject={selectedObject} setSelectedObject={setSelectedObject} showNotice={showNotice} />)}
    </div>
    <div className="tree-footer"><span><span className="legend-dot valid" />Valid</span><span><span className="legend-dot warning" />Needs review</span></div>
  </div>
}

function TreeItem({ item, level, expanded, onToggle, itemsById, selectedObject, setSelectedObject, showNotice }: { item: ModelTreeItem; level: number; expanded?: boolean; onToggle: () => void; itemsById: Map<string, ModelTreeItem>; selectedObject: string; setSelectedObject: (id: string) => void; showNotice: (message: string) => void }) {
  const hasChildren = item.children && item.children.length > 0
  const itemIcon = item.type === 'body' ? Box : item.type === 'sketch' ? CircleDot : item.type === 'feature' ? SquareStack : Layers3
  const ItemIcon = itemIcon
  return <>
    <button className={`tree-row ${selectedObject === item.id ? 'is-selected' : ''} ${item.state === 'active' ? 'is-active' : ''}`} style={{ paddingLeft: `${level * 14}px` }} onClick={() => { setSelectedObject(item.id); if (item.state === 'warning') showNotice('This feature has a reference warning') }} onDoubleClick={() => showNotice(`Editing ${item.label}`)}>
      {hasChildren ? <span onClick={(event) => { event.stopPropagation(); onToggle() }}>{expanded ? <ChevronDown size={13} /> : <ChevronRight size={13} />}</span> : <span className="tree-spacer" />}
      <ItemIcon size={15} className={item.type === 'body' ? 'icon-cyan' : item.state === 'warning' ? 'icon-amber' : 'icon-muted'} />
      <span className="tree-label">{item.label}</span>
      {item.state === 'warning' && <AlertTriangle size={13} className="icon-amber" />}
      {item.state === 'active' && <span className="active-marker" />}
    </button>
    {expanded && hasChildren && <div className="tree-children">{item.children?.map((childId) => { const child = itemsById.get(childId); const ChildIcon = child?.type === 'sketch' ? CircleDot : child?.type === 'feature' ? SquareStack : Circle; return child ? <button className={`tree-row tree-child ${selectedObject === child.id ? 'is-selected' : ''}`} key={child.id} onClick={() => { setSelectedObject(child.id); if (child.state === 'warning') showNotice('This feature has a reference warning') }} onDoubleClick={() => showNotice(`Editing ${child.label}`)}><span className="tree-spacer" /><ChildIcon size={child.type === 'feature' ? 15 : 13} className={child.state === 'warning' ? 'icon-amber' : 'icon-muted'} /><span className="tree-label">{child.label}</span>{child.state === 'warning' && <AlertTriangle size={13} className="icon-amber" />}</button> : <div className="tree-row tree-child" key={childId}><span className="tree-spacer" /><Circle size={8} className="icon-muted" /><span className="tree-label">{childId}</span></div> })}</div>}
  </>
}

function TaskPanel({ workbench, facade, showNotice }: { workbench: Workbench; facade: BitBybitWebCadFacade; showNotice: (message: string) => void }) {
  const definition = workbenchDefinitions[workbench]
  const isSketch = workbench === 'Sketcher'
  const activeTask = facade.task.getActive()
  const primitiveType = activeTask?.commandId === 'primitive' && typeof activeTask.draft.primitiveType === 'string' ? activeTask.draft.primitiveType : 'Box'
  const primitiveFields = primitiveType === 'Box' ? ['width', 'length', 'height'] : primitiveType === 'Cylinder' ? ['radius', 'height', 'angle'] : primitiveType === 'Sphere' ? ['radius'] : ['radius1', 'radius2', 'height', 'angle']
  const primitiveUnits: Record<string, string> = { width: 'mm', length: 'mm', height: 'mm', radius: 'mm', radius1: 'mm', radius2: 'mm', angle: 'deg' }
  const primitiveFallbacks: Record<string, number> = { width: 10, length: 10, height: 10, radius: 5, radius1: 5, radius2: 0, angle: 360 }
  const primitiveLabel = (field: string) => field === 'radius1' ? 'Bottom radius' : field === 'radius2' ? 'Top radius' : field[0].toUpperCase() + field.slice(1)
  const featureFields: Record<string, { key: string; label: string; unit: string; fallback: number }> = {
    pad: { key: 'length', label: 'Length', unit: 'mm', fallback: 42 },
    pocket: { key: 'length', label: 'Length', unit: 'mm', fallback: 18 },
    revolution: { key: 'angle', label: 'Angle', unit: 'deg', fallback: 360 },
    fillet: { key: 'radius', label: 'Radius', unit: 'mm', fallback: 3 },
    chamfer: { key: 'distance', label: 'Distance', unit: 'mm', fallback: 2 },
  }
  const currentFeatureField = activeTask?.commandId ? featureFields[activeTask.commandId] : undefined
  const activeCommand = activeTask?.commandId
  const activeDocument = facade.app.document.getActive()
  const booleanCommand = activeCommand === 'union' || activeCommand === 'cut' || activeCommand === 'intersection'
  const shapeObjects = activeDocument.objects.filter((object) => object.typeId.startsWith('Part::') || ['PartDesign::Feature', 'PartDesign::Pad', 'PartDesign::Pocket', 'PartDesign::Revolution', 'PartDesign::Fillet', 'PartDesign::Chamfer', 'PartDesign::Mirrored', 'PartDesign::LinearPattern', 'PartDesign::PolarPattern', 'PartDesign::Hole'].includes(object.typeId))
  const objectLabel = (object: DocumentSnapshot['objects'][number]) => { const value = object.properties.find((property) => property.name === 'Label')?.value; return typeof value === 'string' || typeof value === 'number' ? String(value) : object.id }
  const draftLink = (name: string) => typeof activeTask?.draft[name] === 'string' ? String(activeTask.draft[name]) : ''
  const acceptTask = () => {
    if (!activeTask || activeTask.status !== 'preview') { showNotice('No active task'); return }
    facade.task.apply()
    void facade.app.document.recomputeAsync().then((result) => showNotice(result.status === 'completed' ? 'Task accepted and recompute completed' : `Task accepted; recompute ${result.status}`))
  }
  return <div className="task-panel">
    <div className="task-actions-top">
      <button className="button button-primary" onClick={acceptTask}>OK</button>
      <button className="button button-outline" onClick={() => { facade.task.update({ preview: true }); showNotice('Preview applied') }}>Apply</button>
      <button className="button button-quiet" onClick={() => { facade.task.cancel(); showNotice('Task cancelled') }}>Cancel</button>
    </div>
    <div className="task-header">
      <div className="task-icon"><Pencil size={16} /></div>
      <div><span className="eyebrow">Active command</span><h2>{isSketch ? 'Edit Sketch' : definition.taskTitle}</h2></div>
      <Badge tone="cyan">Preview</Badge>
    </div>
    <div className="task-body">
      <div className="task-step"><span className="step-index">1</span><div><strong>{isSketch ? 'Geometry and constraints' : definition.objectType}</strong><span>{definition.taskSummary}</span></div></div>
      {activeCommand === 'primitive' && <>
        <label className="field-label">Primitive type<select className="field-input" value={primitiveType} onChange={(event) => facade.task.update({ primitiveType: event.target.value })}><option>Box</option><option>Cylinder</option><option>Sphere</option><option>Cone</option></select></label>
        {primitiveFields.map((field) => <label className="field-label" key={field}>{primitiveLabel(field)} <span className="field-unit">{primitiveUnits[field]}</span><input className="field-input" type="number" min={field === 'radius2' ? 0 : 0.001} max={primitiveUnits[field] === 'deg' ? 360 : undefined} step={primitiveUnits[field] === 'deg' ? 1 : 0.1} value={typeof activeTask?.draft[field] === 'number' ? Number(activeTask.draft[field]) : primitiveFallbacks[field]} onChange={(event) => facade.task.update({ [field]: Number(event.target.value) })} /></label>)}
      </>}
      {booleanCommand && <>
        <label className="field-label">Base<select className="field-input" value={draftLink('base')} onChange={(event) => facade.task.update({ base: event.target.value })}><option value="">Select base</option>{shapeObjects.map((object) => <option value={object.id} key={object.id}>{objectLabel(object)}</option>)}</select></label>
        <label className="field-label">Tool<select className="field-input" value={draftLink('tool')} onChange={(event) => facade.task.update({ tool: event.target.value })}><option value="">Select tool</option>{shapeObjects.map((object) => <option value={object.id} key={object.id}>{objectLabel(object)}</option>)}</select></label>
      </>}
      {activeCommand === 'mirrored' && <>
        <label className="field-label">Mirror plane<select className="field-input" value={typeof activeTask?.draft.plane === 'string' ? activeTask.draft.plane : 'YZ plane'} onChange={(event) => facade.task.update({ plane: event.target.value })}><option>XY plane</option><option>XZ plane</option><option>YZ plane</option></select></label>
        <label className="check-row"><input type="checkbox" checked={activeTask?.draft.fuse !== false} onChange={(event) => facade.task.update({ fuse: event.target.checked })} /><span>Fuse result</span></label>
      </>}
      {currentFeatureField && <label className="field-label">{currentFeatureField.label} <span className="field-unit">{currentFeatureField.unit}</span><input className="field-input" type="number" min={0.001} max={currentFeatureField.unit === 'deg' ? 360 : undefined} step={currentFeatureField.unit === 'deg' ? 1 : 0.1} value={typeof activeTask?.draft[currentFeatureField.key] === 'number' ? Number(activeTask.draft[currentFeatureField.key]) : currentFeatureField.fallback} onChange={(event) => facade.task.update({ [currentFeatureField.key]: Number(event.target.value) })} /></label>}
      {activeCommand === 'linear-pattern' && <>
        <label className="field-label">Occurrences<input className="field-input" type="number" min={2} max={100} step={1} value={typeof activeTask?.draft.occurrences === 'number' ? Number(activeTask.draft.occurrences) : 2} onChange={(event) => facade.task.update({ occurrences: Number(event.target.value) })} /></label>
        <label className="field-label">Length <span className="field-unit">mm</span><input className="field-input" type="number" min={0.001} step={0.1} value={typeof activeTask?.draft.length === 'number' ? Number(activeTask.draft.length) : 20} onChange={(event) => facade.task.update({ length: Number(event.target.value) })} /></label>
        <label className="field-label">Direction<select className="field-input" value={typeof activeTask?.draft.direction === 'string' ? activeTask.draft.direction : 'Horizontal'} onChange={(event) => facade.task.update({ direction: event.target.value })}><option>Horizontal</option><option>Vertical</option><option>Normal</option></select></label>
      </>}
      {activeCommand === 'polar-pattern' && <>
        <label className="field-label">Occurrences<input className="field-input" type="number" min={2} max={100} step={1} value={typeof activeTask?.draft.occurrences === 'number' ? Number(activeTask.draft.occurrences) : 3} onChange={(event) => facade.task.update({ occurrences: Number(event.target.value) })} /></label>
        <label className="field-label">Angle <span className="field-unit">deg</span><input className="field-input" type="number" min={0.001} max={360} step={1} value={typeof activeTask?.draft.angle === 'number' ? Number(activeTask.draft.angle) : 360} onChange={(event) => facade.task.update({ angle: Number(event.target.value) })} /></label>
        <label className="field-label">Axis<select className="field-input" value={typeof activeTask?.draft.axis === 'string' ? activeTask.draft.axis : 'Normal'} onChange={(event) => facade.task.update({ axis: event.target.value })}><option>Normal</option><option>Horizontal</option><option>Vertical</option></select></label>
      </>}
      {activeCommand === 'hole' && <>
        <label className="field-label">Diameter <span className="field-unit">mm</span><input className="field-input" type="number" min={0.001} step={0.1} value={typeof activeTask?.draft.diameter === 'number' ? Number(activeTask.draft.diameter) : 5} onChange={(event) => facade.task.update({ diameter: Number(event.target.value) })} /></label>
        <label className="field-label">Depth <span className="field-unit">mm</span><input className="field-input" type="number" min={0.001} step={0.1} value={typeof activeTask?.draft.depth === 'number' ? Number(activeTask.draft.depth) : 10} onChange={(event) => facade.task.update({ depth: Number(event.target.value) })} /></label>
        <label className="field-label">Type<select className="field-input" value={typeof activeTask?.draft.type === 'string' ? activeTask.draft.type : 'Dimension'} onChange={(event) => facade.task.update({ type: event.target.value })}><option>Dimension</option><option>Through all</option></select></label>
      </>}
      {activeCommand === 'pocket' && <label className="field-label">Type<select className="field-input" value={typeof activeTask?.draft.type === 'string' ? activeTask.draft.type : 'Through all'} onChange={(event) => facade.task.update({ type: event.target.value })}><option>Dimension</option><option>Through all</option><option>Up to face</option></select></label>}
      {['pad', 'pocket', 'revolution'].includes(activeCommand || '') && <label className="check-row"><input type="checkbox" checked={activeTask?.draft.reversed === true} onChange={(event) => facade.task.update({ reversed: event.target.checked })} /><span>Reversed</span></label>}
      {activeCommand === 'pad' && <label className="check-row"><input type="checkbox" checked={activeTask?.draft.midplane === true} onChange={(event) => facade.task.update({ midplane: event.target.checked })} /><span>Symmetric to plane</span></label>}
      {!activeCommand || activeCommand === 'create-sketch' ? <>
        <label className="field-label">Primary value <span className="field-unit">mm</span><input className="field-input" value={isSketch ? 'Fully constrained' : '42.00'} readOnly /></label>
        <label className="field-label">Operation<select className="field-input"><option>{workbench === 'Part Design' ? 'Dimension' : 'Contextual preview'}</option><option>Through all</option><option>Up to face</option></select></label>
      </> : null}
      <label className="check-row"><input type="checkbox" defaultChecked /><span>Preview result in viewport</span></label>
      <div className="task-note"><AlertTriangle size={14} /><span>Changes remain local until the document is recomputed.</span></div>
    </div>
  </div>
}

function PropertyPanel({ facade, objectId, scope, showNotice }: { facade: BitBybitWebCadFacade; objectId: string; scope: 'data' | 'view'; showNotice: (message: string) => void }) {
  const object = facade.app.document.getObject(objectId)
  if (!object) return <div className="properties-empty">No object selected</div>
  const properties = object.properties.filter((property) => property.scope === scope && !property.hidden)
  const groups = new Map<string, ObjectPropertySnapshot[]>()
  properties.forEach((property) => groups.set(property.group, [...(groups.get(property.group) ?? []), property]))
  return <div className="properties-scroll">{[...groups].map(([group, entries]) => <div className="property-group" key={group}><div className="property-group-title">{group}<ChevronDown size={14} /></div>{entries.map((property) => <PropertyEditor key={`${objectId}-${property.name}-${String(property.value)}`} facade={facade} objectId={objectId} property={property} showNotice={showNotice} />)}</div>)}</div>
}

function PropertyEditor({ facade, objectId, property, showNotice }: { facade: BitBybitWebCadFacade; objectId: string; property: ObjectPropertySnapshot; showNotice: (message: string) => void }) {
  const commit = (value: PropertyValue) => {
    try {
      facade.app.document.setProperty({ objectId, propertyName: property.name, value })
      return true
    } catch (error) {
      showNotice(error instanceof Error ? error.message : String(error))
      return false
    }
  }
  const formatted = `${String(property.value ?? '')}${property.unit ? ` ${property.unit}` : ''}`
  let editor: ReactNode
  if (property.readOnly) editor = <span className="property-readonly">{formatted}</span>
  else if (property.type === 'App::PropertyBool') editor = <input className="property-checkbox" type="checkbox" checked={Boolean(property.value)} aria-label={property.label} onChange={(event) => commit(event.target.checked)} />
  else if (property.type === 'App::PropertyEnumeration') editor = <select className="property-control" value={String(property.value)} aria-label={property.label} onChange={(event) => commit(event.target.value)}>{property.options?.map((option) => <option key={option}>{option}</option>)}</select>
  else if (property.type === 'App::PropertyLink') {
    const document = facade.app.document.getActive()
    const ids = [...new Set(document.tree.flatMap((item) => [item.id, ...(item.children ?? [])]))]
    editor = <select className="property-control property-link-control" value={String(property.value ?? '')} aria-label={property.label} onChange={(event) => commit(event.target.value || null)}><option value="">None</option>{ids.filter((id) => id !== objectId).map((id) => <option value={id} key={id}>{document.tree.find((item) => item.id === id)?.label ?? id}</option>)}</select>
  } else if (property.type === 'App::PropertyLinkSub') {
    const ref = property.value && typeof property.value === 'object' && !Array.isArray(property.value) && 'schemaVersion' in property.value ? property.value : null
    const source = ref ? facade.app.document.getObject(ref.objectId) : null
    const candidates = ref ? (ref.candidates?.length ? ref.candidates : source?.topology?.entries.filter((entry) => entry.ref.kind === ref.kind && entry.ref.status !== 'deleted').map((entry) => entry.ref.persistentId) ?? []) : []
    const replace = (candidatePersistentId: string) => {
      if (!candidatePersistentId) return
      try {
        facade.app.document.resolveTopologyReference({ ownerObjectId: objectId, referenceName: property.name, candidatePersistentId })
        void facade.app.document.recomputeAsync().then((result) => showNotice(result.status === 'completed' ? `${property.label} reference replaced` : `Reference replaced; recompute ${result.status}`))
      } catch (error) { showNotice(error instanceof Error ? error.message : String(error)) }
    }
    editor = ref ? <div className="property-link-sub"><span title={ref.persistentId}>{ref.objectId} / {ref.kind} · {ref.status}</span>{(ref.status === 'ambiguous' || ref.status === 'deleted') && candidates.length > 0 ? <select className="property-control property-topology-candidates" aria-label={`${property.label} replacement`} defaultValue="" onChange={(event) => replace(event.target.value)}><option value="">Replace</option>{candidates.map((candidate) => <option value={candidate} key={candidate}>{candidate}</option>)}</select> : null}<IconButton icon={X} label="Clear subshape reference" onClick={() => commit(null)} /></div> : <span className="property-readonly">None</span>
  } else if (property.type === 'App::PropertyPlacement') {
    const placement = property.value as PlacementValue
    const updatePlacement = (path: 'position' | 'axis' | 'angle', key: 'x' | 'y' | 'z' | null, next: number) => {
      const value: PlacementValue = { position: { ...placement.position }, rotation: { axis: { ...placement.rotation.axis }, angle: placement.rotation.angle } }
      if (path === 'position' && key) value.position[key] = next
      else if (path === 'axis' && key) value.rotation.axis[key] = next
      else value.rotation.angle = next
      return commit(value)
    }
    editor = <details className="property-placement"><summary>{placement.position.x}, {placement.position.y}, {placement.position.z}</summary><div className="property-placement-grid"><span>Position</span>{(['x', 'y', 'z'] as const).map((key) => <input key={`p-${key}`} type="number" aria-label={`${property.label} position ${key}`} defaultValue={placement.position[key]} onBlur={(event) => updatePlacement('position', key, Number(event.target.value))} />)}<span>Axis</span>{(['x', 'y', 'z'] as const).map((key) => <input key={`a-${key}`} type="number" aria-label={`${property.label} axis ${key}`} defaultValue={placement.rotation.axis[key]} onBlur={(event) => updatePlacement('axis', key, Number(event.target.value))} />)}<span>Angle</span><input type="number" aria-label={`${property.label} angle`} defaultValue={placement.rotation.angle} onBlur={(event) => updatePlacement('angle', null, Number(event.target.value))} /><span /><span /></div></details>
  } else if (property.type === 'App::PropertyVector') {
    const vector = property.value as { x: number; y: number; z: number }
    editor = <div className="property-vector">{(['x', 'y', 'z'] as const).map((key) => <input key={key} type="number" aria-label={`${property.label} ${key}`} defaultValue={vector[key]} onBlur={(event) => commit({ ...vector, [key]: Number(event.target.value) })} />)}</div>
  } else if (property.type === 'App::PropertyLinkList' || property.type === 'App::PropertyStringList') editor = <input className="property-control" defaultValue={(property.value as string[]).join(', ')} aria-label={property.label} onBlur={(event) => commit(event.target.value.split(',').map((entry) => entry.trim()).filter(Boolean))} />
  else if (property.type === 'App::PropertyColor') editor = <label className="property-color"><input type="color" value={String(property.value)} aria-label={property.label} onChange={(event) => commit(event.target.value)} /><span>{String(property.value).toUpperCase()}</span></label>
  else if (property.type === 'App::PropertyLength' || property.type === 'App::PropertyAngle' || property.type === 'App::PropertyPercent' || property.type === 'App::PropertyFloat' || property.type === 'App::PropertyInteger') editor = <label className="property-number"><input className="property-control" type="number" defaultValue={Number(property.value)} min={property.name === 'Occurrences' ? 2 : property.type === 'App::PropertyLength' || property.type === 'App::PropertyAngle' || property.type === 'App::PropertyPercent' ? 0 : undefined} max={property.name === 'Occurrences' ? 100 : property.type === 'App::PropertyAngle' ? 360 : property.type === 'App::PropertyPercent' ? 100 : undefined} step={property.type === 'App::PropertyLength' ? 0.1 : 1} aria-label={property.label} onBlur={(event) => { if (!commit(Number(event.target.value))) event.target.value = String(property.value) }} onKeyDown={(event) => { if (event.key === 'Enter') event.currentTarget.blur() }} /><span>{property.unit}</span></label>
  else editor = <input className="property-control" defaultValue={String(property.value ?? '')} aria-label={property.label} onBlur={(event) => { if (!commit(event.target.value)) event.target.value = String(property.value ?? '') }} onKeyDown={(event) => { if (event.key === 'Enter') event.currentTarget.blur() }} />
  return <><div className="property-row"><span className="property-label">{property.label}</span><div className="property-editor">{editor}</div></div>{property.expression && <div className="property-expression"><Code2 size={12} /><span>{property.expression}</span></div>}</>
}

function Viewport({ selectedObject, setSelectedObject, workbench, facade, documentVersion, recomputeGeneration, showNotice }: { selectedObject: string; setSelectedObject: (id: string) => void; workbench: Workbench; facade: BitBybitWebCadFacade; documentVersion: number; recomputeGeneration: number; showNotice: (message: string) => void }) {
  const hostRef = useRef<HTMLDivElement>(null)
  const adapterRef = useRef<BitBybitViewportAdapter | null>(null)
  useEffect(() => {
    const host = hostRef.current
    if (!host) return
    const adapter = facade.viewport.createAdapter()
    adapterRef.current = adapter
    let cancelled = false
    const shapes: ShapeHandle[] = []
    let ownsShapes = false
    try {
      adapter.mount(host)
    } catch (error) {
      showNotice(`WebGL viewport unavailable: ${error instanceof Error ? error.message : 'unknown error'}`)
      adapter.dispose()
      adapterRef.current = null
      return
    }
    const loadGeometry = async () => {
      const capabilities = await facade.geometry.initialize()
      if (capabilities.status !== 'ready') throw new Error(capabilities.reason || 'OCCT geometry runtime unavailable')
      const document = facade.app.document.getActive()
      const featureIds = [selectedObject, 'fillet', 'chamfer', 'revolution', 'intersection', 'cut', 'union', 'pocket', 'pad', 'box', 'cylinder', 'sphere', 'cone'].filter(Boolean)
      const storedShape = featureIds.map((objectId) => facade.geometry.getObjectShape(objectId)).find((shape): shape is ShapeHandle => Boolean(shape))
      if (storedShape) {
        const mesh = await facade.geometry.mesh(storedShape, 0.05)
        if (!cancelled) adapter.setMesh(mesh)
        return
      }
      ownsShapes = true
      const profile = { outer: [[-1.35, -0.7, 0], [1.35, -0.7, 0], [1.35, 0.7, 0], [-1.35, 0.7, 0]] as [number, number, number][] }
      const pad = await facade.geometry.pad({ profile, length: 1.6, direction: [0, 0, 1], documentId: document.id, documentVersion: document.version })
      shapes.push(pad)
      const pocketProfile = { outer: [[-0.55, -0.32, 0], [0.55, -0.32, 0], [0.55, 0.32, 0], [-0.55, 0.32, 0]] as [number, number, number][] }
      const pocket = await facade.geometry.pocket({ base: pad, profile: pocketProfile, length: 1.8, direction: [0, 0, 1], documentId: document.id, documentVersion: document.version })
      shapes.push(pocket)
      if (cancelled) {
        await Promise.all(shapes.map((entry) => facade.geometry.release(entry)))
        return
      }
      const mesh = await facade.geometry.mesh(pocket, 0.05)
      if (!cancelled) adapter.setMesh(mesh)
    }
    void loadGeometry().catch((error: unknown) => {
      if (!cancelled) showNotice(`Geometry preview unavailable: ${error instanceof Error ? error.message : String(error)}`)
    })
    return () => {
      cancelled = true
      if (ownsShapes) void Promise.all(shapes.map((entry) => facade.geometry.release(entry)))
      adapter.dispose()
      adapterRef.current = null
    }
  }, [facade, showNotice, selectedObject, documentVersion, recomputeGeneration])

  useEffect(() => adapterRef.current?.setSelection(selectedObject), [selectedObject])
  return <div className="viewport"><div className="viewport-header"><div className="viewport-title"><span className="eyebrow">{workbench}</span><strong>Body / Fillet</strong></div><div className="viewport-actions"><IconButton icon={ZoomOut} label="Zoom out" /><IconButton icon={ZoomIn} label="Zoom in" /><IconButton icon={Rotate3D} label="Orbit view" active /></div></div><div className="viewport-grid" onClick={() => setSelectedObject('')}><div className="three-viewport-host" ref={hostRef} aria-label="Three.js viewport" /></div><div className="viewport-legend"><span><span className="legend-swatch selected" />Selected</span><span><span className="legend-swatch edge" />Edges</span><span><span className="legend-swatch datum" />Datum</span></div></div>
}

function PageFrame({ page, onNavigate, onOpenWorkspace, showNotice, facade }: { page: Page; onNavigate: (page: Page) => void; onOpenWorkspace: () => void; showNotice: (message: string) => void; facade: BitBybitWebCadFacade }) {
  const pages: Record<Exclude<Page, 'workspace'>, ReactNode> = {
    start: <StartPage onNavigate={onNavigate} onOpenWorkspace={onOpenWorkspace} showNotice={showNotice} />,
    projects: <ProjectsPage onNavigate={onNavigate} onOpenWorkspace={onOpenWorkspace} showNotice={showNotice} facade={facade} />,
    import: <FileFlowPage mode="import" onNavigate={onNavigate} showNotice={showNotice} facade={facade} />,
    export: <FileFlowPage mode="export" onNavigate={onNavigate} showNotice={showNotice} facade={facade} />,
    settings: <SettingsPage onNavigate={onNavigate} showNotice={showNotice} />,
    help: <HelpPage onNavigate={onNavigate} showNotice={showNotice} />,
    diagnostics: <DiagnosticsPage onNavigate={onNavigate} showNotice={showNotice} facade={facade} />,
    sync: <SyncPage onNavigate={onNavigate} showNotice={showNotice} />,
  }
  return <div className="page-shell"><div className="page-content">{pages[page as Exclude<Page, 'workspace'>]}</div></div>
}

function PageHeader({ eyebrow, title, description, actions, onBack }: { eyebrow: string; title: string; description: string; actions?: ReactNode; onBack?: () => void }) {
  return <div className="page-header"><div className="page-heading"><div className="page-eyebrow">{onBack && <button className="back-button" onClick={onBack} title="Back"><ArrowLeft size={15} /></button>}<span>{eyebrow}</span></div><h1>{title}</h1><p>{description}</p></div>{actions && <div className="page-actions">{actions}</div>}</div>
}

function StartPage({ onNavigate, onOpenWorkspace, showNotice }: { onNavigate: (page: Page) => void; onOpenWorkspace: () => void; showNotice: (message: string) => void }) {
  return <div className="start-page">
    <PageHeader eyebrow="Local-first workspace" title="Start a new design." description="A focused CAD workspace for parametric parts, drawings and assemblies." actions={<><button className="button button-outline" onClick={() => onNavigate('projects')}><FolderOpen size={16} />Open project</button><button className="button button-primary" onClick={onOpenWorkspace}><Plus size={16} />New document</button></>} />
    <div className="start-grid"><section className="start-hero panel-surface"><div className="hero-copy"><span className="section-kicker"><Sparkles size={14} />FreeCAD-compatible workspace</span><h2>Model with a clear history.</h2><p>Build parts through ordered features, inspect every dependency and keep your project local by default.</p><div className="hero-actions"><button className="button button-primary" onClick={onOpenWorkspace}><FilePlus2 size={16} />Create blank document</button><button className="text-button" onClick={() => showNotice('Example gallery opened')}>Browse examples <ArrowRight size={14} /></button></div></div><div className="hero-schematic"><div className="schematic-axis axis-x-line" /><div className="schematic-axis axis-y-line" /><div className="schematic-block block-a" /><div className="schematic-block block-b" /><div className="schematic-ring" /><span className="schematic-label label-a">Feature history</span><span className="schematic-label label-b">Parametric part</span></div></section><section className="quick-panel panel-surface"><div className="section-title"><div><span className="section-kicker">Quick access</span><h3>Keep moving</h3></div><MoreHorizontal size={16} /></div><QuickAction icon={FolderOpen} title="Open a project" detail="Browse local files" onClick={() => onNavigate('projects')} /><QuickAction icon={Upload} title="Import a model" detail="STEP, IGES, STL and mesh" onClick={() => onNavigate('import')} /><QuickAction icon={WandSparkles} title="Start from an example" detail="Parametric reference models" onClick={() => showNotice('Example gallery opened')} /></section></div>
    <section className="recent-section"><div className="section-title"><div><span className="section-kicker">Recent projects</span><h3>Your local workspace</h3></div><button className="text-button" onClick={() => onNavigate('projects')}>View all <ArrowRight size={14} /></button></div><div className="recent-grid">{projects.slice(0, 3).map((project, index) => <ProjectCard project={project} key={project.name} index={index} onClick={onOpenWorkspace} />)}</div></section>
    <div className="start-footer"><div><HardDrive size={15} /><span>Local storage capability</span><Badge tone="cyan">Probe on open</Badge></div><div><span>BitBybit CAD Studio</span><span className="footer-separator">·</span><span>FreeCAD UI baseline 1.1.1</span></div></div>
  </div>
}

function QuickAction({ icon: ActionIcon, title, detail, onClick }: { icon: Icon; title: string; detail: string; onClick: () => void }) {
  return <button className="quick-action" onClick={onClick}><span className="quick-icon"><ActionIcon size={17} /></span><span><strong>{title}</strong><small>{detail}</small></span><ArrowRight size={15} /></button>
}

function ProjectCard({ project, index, onClick }: { project: typeof projects[number]; index: number; onClick: () => void }) {
  return <button className="project-card" onClick={onClick}><div className={`project-preview preview-${index}`}><div className="preview-shape" /><div className="preview-grid" /></div><div className="project-card-info"><div className="project-card-title"><strong>{project.name}</strong><MoreHorizontal size={15} /></div><span>{project.path}</span><div className="project-card-meta"><span>{project.modified}</span><span>{project.objects} objects</span><Badge tone={project.state === 'Unsaved' ? 'amber' : project.state === 'Read only' ? 'muted' : 'green'}>{project.state}</Badge></div></div></button>
}

function ProjectsPage({ onNavigate, onOpenWorkspace, showNotice, facade }: { onNavigate: (page: Page) => void; onOpenWorkspace: () => void; showNotice: (message: string) => void; facade: BitBybitWebCadFacade }) {
  const [savedProjects, setSavedProjects] = useState<ProjectSummary[]>([])
  const [loading, setLoading] = useState(true)
  useEffect(() => {
    let cancelled = false
    void facade.project.list().then((items) => { if (!cancelled) setSavedProjects(items) }).catch((error: unknown) => { if (!cancelled) showNotice(`Project list unavailable: ${error instanceof Error ? error.message : String(error)}`) }).finally(() => { if (!cancelled) setLoading(false) })
    return () => { cancelled = true }
  }, [facade, showNotice])
  const openSavedProject = async (documentId: string) => {
    const loaded = await facade.app.document.load(documentId)
    if (!loaded) { showNotice('No saved local snapshot found'); return }
    showNotice(`Loaded ${loaded.label}`)
    onOpenWorkspace()
  }
  return <div className="projects-page"><PageHeader eyebrow="Project manager" title="Your projects." description="Local-first project storage with explicit save and recovery states." actions={<><button className="button button-outline" onClick={() => onNavigate('import')}><Upload size={16} />Import</button><button className="button button-primary" onClick={onOpenWorkspace}><Plus size={16} />New project</button></>} /><div className="manager-toolbar"><div className="large-search"><Search size={16} /><input placeholder="Search projects" /><kbd>/</kbd></div><div className="toolbar-select"><span>Sort by</span><select><option>Last modified</option><option>Name</option><option>Object count</option></select><ChevronDown size={14} /></div><IconButton icon={LayoutGrid} label="Grid view" active /><IconButton icon={ListTree} label="List view" /></div><div className="project-list">{loading ? <div className="project-list-empty">Loading local projects</div> : savedProjects.length === 0 ? <div className="project-list-empty">No saved local projects</div> : savedProjects.map((project, index) => { const state = project.readOnly ? 'Read only' : project.dirty ? 'Unsaved' : 'Saved'; return <button className="project-list-row" key={project.documentId} onClick={() => void openSavedProject(project.documentId)}><div className={`list-thumbnail preview-${index % 4}`}><div className="preview-shape" /><div className="preview-grid" /></div><div className="list-main"><strong>{project.label}</strong><span>Local / {project.documentId}</span></div><span className="list-count">{project.objectCount} objects</span><span className="list-modified">{new Date(project.updatedAt).toLocaleDateString()}</span><Badge tone={state === 'Unsaved' ? 'amber' : state === 'Read only' ? 'muted' : 'green'}>{state}</Badge><span className="row-action" title="Open project"><ArrowRight size={16} /></span></button> })}</div><div className="storage-banner"><div className="storage-icon"><HardDrive size={18} /></div><div><strong>Local storage</strong><span>{savedProjects.length} saved project{savedProjects.length === 1 ? '' : 's'} · browser-managed capacity</span></div><button className="text-button" onClick={() => onNavigate('settings')}>Manage storage <ArrowRight size={14} /></button></div></div>
}

function FileFlowPage({ mode, onNavigate, showNotice, facade }: { mode: 'import' | 'export'; onNavigate: (page: Page) => void; showNotice: (message: string) => void; facade: BitBybitWebCadFacade }) {
  const isImport = mode === 'import'
  const [fcstdReport, setFcstdReport] = useState<FcstdInspection | null>(null)
  const [selectedFormat, setSelectedFormat] = useState<'STEP' | 'STL' | 'GLB / GLTF' | 'Web CAD package'>('STEP')
  const [exporting, setExporting] = useState(false)
  const fileInputRef = useRef<HTMLInputElement>(null)
  const inspectFile = async (file: File) => {
    if (!file.name.toLowerCase().endsWith('.fcstd')) { showNotice('Only FCStd inspection is connected to this import boundary'); return }
    try {
      const report = facade.project.fcstd.inspect(new Uint8Array(await file.arrayBuffer()))
      setFcstdReport(report)
      showNotice(`FCStd inspected: ${report.compatibility.level}`)
    } catch (error) { setFcstdReport(null); showNotice(`FCStd rejected: ${error instanceof Error ? error.message : String(error)}`) }
  }
  const exportModel = async () => {
    if (selectedFormat !== 'STEP' && selectedFormat !== 'STL') { showNotice(`${selectedFormat} export is not implemented yet`); return }
    const objectIds = ['fillet', 'chamfer', 'revolution', 'intersection', 'cut', 'union', 'pocket', 'pad', 'box', 'cylinder', 'sphere', 'cone']
    const shape = objectIds.map((objectId) => facade.geometry.getObjectShape(objectId)).find((candidate): candidate is ShapeHandle => Boolean(candidate))
    if (!shape) { showNotice('Recompute a valid Part or Part Design shape before exporting'); return }
    setExporting(true)
    try {
      const result = selectedFormat === 'STEP' ? await facade.geometry.exportStep(shape, `${facade.app.document.getActive().label}.step`) : await facade.geometry.exportStl(shape, `${facade.app.document.getActive().label}.stl`)
      const blob = new Blob([result.text], { type: result.mediaType })
      const url = URL.createObjectURL(blob)
      const anchor = document.createElement('a')
      anchor.href = url
      anchor.download = result.fileName
      anchor.click()
      URL.revokeObjectURL(url)
      showNotice(`${result.format.toUpperCase()} export downloaded`)
    } catch (error) {
      showNotice(`Export failed: ${error instanceof Error ? error.message : String(error)}`)
    } finally { setExporting(false) }
  }
  return <div className="flow-page"><PageHeader eyebrow={isImport ? 'Import model' : 'Export project'} title={isImport ? 'Bring a model into your workspace.' : 'Export a clean deliverable.'} description={isImport ? 'Review format, units and compatibility before the document is created.' : 'Choose an exchange format and keep the native project available for future edits.'} onBack={() => onNavigate('start')} /><div className="flow-layout"><div className="flow-steps"><FlowStep index="01" title="Choose file" active={!isImport} complete={isImport} /><FlowStep index="02" title="Review mapping" active={isImport} complete={false} /><FlowStep index="03" title="Confirm" active={false} complete={false} /></div><section className="flow-card panel-surface"><div className="flow-card-header"><div><span className="section-kicker">Step 01 / 03</span><h2>{isImport ? 'Select a CAD file' : 'Select an export format'}</h2></div><Badge tone="cyan">Local only</Badge></div>{isImport ? <><div className="drop-zone"><div className="drop-icon"><Upload size={20} /></div><strong>Drop a model here</strong><span>or browse from your device</span><input ref={fileInputRef} type="file" accept=".FCStd,.fcstd" hidden onChange={(event) => { const file = event.target.files?.[0]; if (file) void inspectFile(file); event.currentTarget.value = '' }} /><button className="button button-outline" onClick={() => fileInputRef.current?.click()}><FolderOpen size={15} />Browse files</button><small>STEP · IGES · STL · OBJ · PLY · FCStd</small></div><div className="flow-note"><AlertTriangle size={15} /><span>FCStd is currently a read-only metadata inspection boundary. Python/macros are isolated and never executed.</span></div>{fcstdReport && <div className="flow-note"><CheckCircle2 size={15} className="icon-green" /><span>{fcstdReport.label} · {fcstdReport.objects.length} objects · {fcstdReport.compatibility.level}; {fcstdReport.compatibility.warnings.join(' ') || 'No compatibility warnings.'}</span></div>}</> : <div className="format-grid">{['STEP', 'IGES', 'STL', 'GLB / GLTF', 'Web CAD package'].map((format, index) => <button key={format} className={`format-card ${selectedFormat === format ? 'is-selected' : ''}`} disabled={format === 'IGES' || format === 'GLB / GLTF' || format === 'Web CAD package'} onClick={() => { setSelectedFormat(format as typeof selectedFormat); showNotice(`${format} selected`) }}><span className="format-icon">{index === 4 ? <FileBox size={18} /> : <FileText size={18} />}</span><strong>{format}</strong><small>{index === 0 ? 'Best for editable solids' : index === 2 ? 'Mesh export' : 'Not implemented'}</small>{selectedFormat === format && <Check size={15} className="format-check" />}</button>)}</div>}<div className="flow-footer"><button className="button button-quiet" onClick={() => onNavigate('start')}>Cancel</button><button className="button button-primary" disabled={isImport ? false : exporting} onClick={() => { if (isImport) showNotice(fcstdReport ? 'Metadata review complete; import mapping remains disabled' : 'Choose a file to review'); else void exportModel() }}><span>{isImport ? 'Continue' : exporting ? 'Exporting' : `Export ${selectedFormat}`}</span>{exporting ? <RefreshCw size={15} /> : <ArrowRight size={15} />}</button></div></section></div></div>
}

function FlowStep({ index, title, active, complete }: { index: string; title: string; active: boolean; complete: boolean }) {
  return <div className={`flow-step ${active ? 'is-active' : ''} ${complete ? 'is-complete' : ''}`}><span className="flow-index">{complete ? <Check size={13} /> : index}</span><span>{title}</span></div>
}

function SettingsPage({ onNavigate, showNotice }: { onNavigate: (page: Page) => void; showNotice: (message: string) => void }) {
  return <div className="settings-page"><PageHeader eyebrow="Preferences" title="Workspace settings." description="Keep the FreeCAD workflow familiar and tune the browser workspace around it." onBack={() => onNavigate('start')} actions={<button className="button button-primary" onClick={() => showNotice('Preferences saved')}><Save size={16} />Save changes</button>} /><div className="settings-layout"><aside className="settings-nav"><button className="is-active"><SlidersHorizontal size={15} />General</button><button><Rotate3D size={15} />Navigation</button><button><Circle size={15} />Units & precision</button><button><Layers3 size={15} />Display</button><button><Command size={15} />Shortcuts</button><button><HardDrive size={15} />Storage</button><button><UserRound size={15} />Privacy & security</button></aside><section className="settings-content panel-surface"><SettingSection title="Document defaults" detail="New documents inherit these values."><SettingRow label="Unit system" detail="Used for new projects and property editors"><select><option>Metric (mm, kg, s)</option><option>Imperial (in, lb, s)</option></select></SettingRow><SettingRow label="Autosave interval" detail="A local snapshot is created after inactivity"><select><option>Every 5 minutes</option><option>Every 10 minutes</option><option>Manual only</option></select></SettingRow></SettingSection><SettingSection title="Viewport" detail="The default FreeCAD navigation preset is kept intact."><SettingRow label="Navigation preset" detail="Orbit, pan and zoom mapping"><select><option>FreeCAD CAD</option><option>Trackpad</option><option>Blender</option></select></SettingRow><SettingRow label="Display mode" detail="Default rendering for precise edges"><select><option>Flat lines</option><option>Shaded</option><option>Wireframe</option></select></SettingRow><SettingRow label="Show selection edges" detail="Highlight selected sub-shapes"><input type="checkbox" defaultChecked /></SettingRow></SettingSection><SettingSection title="Local storage" detail="No design data leaves this browser unless you export or sync it."><SettingRow label="OPFS workspace" detail="3.4 GB of 10 GB used"><span className="storage-meter"><span /></span></SettingRow><SettingRow label="Diagnostic uploads" detail="Share only when you explicitly attach a report"><span className="setting-value">Off</span></SettingRow></SettingSection></section></div></div>
}

function SettingSection({ title, detail, children }: { title: string; detail: string; children: ReactNode }) {
  return <section className="setting-section"><div className="setting-section-heading"><h2>{title}</h2><p>{detail}</p></div>{children}</section>
}

function SettingRow({ label, detail, children }: { label: string; detail: string; children: ReactNode }) {
  return <div className="setting-row"><div><strong>{label}</strong><span>{detail}</span></div><div className="setting-control">{children}</div></div>
}

function HelpPage({ onNavigate, showNotice }: { onNavigate: (page: Page) => void; showNotice: (message: string) => void }) {
  const helpItems = [{ title: 'Create a feature-based part', detail: 'Body → Sketch → Pad → Pocket → Fillet', icon: Box }, { title: 'Understand the model tree', detail: 'Objects, links, Tip and recompute states', icon: ListTree }, { title: 'Navigate the viewport', detail: 'FreeCAD CAD preset and view controls', icon: Rotate3D }, { title: 'Recover a project', detail: 'Snapshots, compatibility and backups', icon: Archive }]
  return <div className="help-page"><PageHeader eyebrow="Help center" title="Find your next command." description="FreeCAD workflow references, keyboard shortcuts and compatibility notes." onBack={() => onNavigate('start')} /><div className="help-search"><Search size={18} /><input placeholder="Search commands, workbenches and help" autoFocus /><kbd>⌘ K</kbd></div><div className="help-grid">{helpItems.map((item) => <button className="help-card panel-surface" key={item.title} onClick={() => showNotice(`${item.title} opened`)}><span className="help-icon"><item.icon size={18} /></span><span><strong>{item.title}</strong><small>{item.detail}</small></span><ArrowRight size={15} /></button>)}</div><section className="shortcut-panel panel-surface"><div className="section-title"><div><span className="section-kicker">Keyboard</span><h3>Core shortcuts</h3></div><button className="text-button" onClick={() => showNotice('Shortcut editor opened')}>Customize <ArrowRight size={14} /></button></div><div className="shortcut-grid"><Shortcut keyName="⌘ K" label="Command search" /><Shortcut keyName="Space" label="Toggle visibility" /><Shortcut keyName="F" label="Fit all" /><Shortcut keyName="Esc" label="Cancel task or selection" /><Shortcut keyName="⌘ Z" label="Undo" /><Shortcut keyName="⌘ S" label="Save project" /></div></section></div>
}

function Shortcut({ keyName, label }: { keyName: string; label: string }) {
  return <div className="shortcut-row"><kbd>{keyName}</kbd><span>{label}</span></div>
}

function DiagnosticsPage({ onNavigate, showNotice, facade }: { onNavigate: (page: Page) => void; showNotice: (message: string) => void; facade: BitBybitWebCadFacade }) {
  const [recovery, setRecovery] = useState<{ integrity: string; lastSavedVersion: number | null; warnings: string[] } | null>(null)
  const [geometry, setGeometry] = useState(() => facade.geometry.capabilities())
  const document = facade.getState().document
  const persistence = facade.project.capabilities()
  const diagnosticTree = facade.diagnostics.tree()
  const geometryTone = geometry.status === 'ready' ? 'green' : geometry.status === 'failed' || geometry.status === 'unavailable' ? 'amber' : 'cyan'
  const geometryValue = geometry.status === 'ready' ? 'Ready' : geometry.status === 'initializing' ? 'Loading' : geometry.status
  useEffect(() => { void facade.project.recovery(facade.getState().document.id).then(setRecovery).catch((error: unknown) => showNotice(`Recovery report unavailable: ${error instanceof Error ? error.message : String(error)}`)) }, [facade, showNotice])
  useEffect(() => {
    let disposed = false
    void facade.geometry.initialize().then((capabilities) => { if (!disposed) setGeometry(capabilities) }).catch((error: unknown) => { if (!disposed) showNotice(`Geometry capability probe failed: ${error instanceof Error ? error.message : String(error)}`) })
    return () => { disposed = true }
  }, [facade, showNotice])
  return <div className="diagnostics-page">
    <PageHeader eyebrow="System status" title="Runtime checks." description="A concise view of browser capabilities, local storage and the current document runtime." onBack={() => onNavigate('start')} actions={<button className="button button-outline" onClick={() => showNotice('Diagnostic package prepared')}><Download size={16} />Export report</button>} />
    <div className="health-grid"><HealthCard label="WebAssembly" value={geometryValue} detail={geometry.reason || 'BitBybit OCCT package loads on demand'} tone={geometryTone} icon={Code2} /><HealthCard label="Local storage" value={persistence.mode === 'sqlite-opfs' ? 'SQLite + OPFS' : persistence.mode === 'sqlite-memory' ? 'Memory fallback' : 'Unavailable'} detail={`Schema v${persistence.schemaVersion || 'n/a'} · ${persistence.crossTabWriteLock || 'local queue'}`} tone={persistence.mode === 'unavailable' ? 'amber' : 'cyan'} icon={HardDrive} /><HealthCard label="Viewport" value="WebGL2" detail="Three.js 0.185.1" tone="cyan" icon={Rotate3D} /><HealthCard label="Document" value={`${document.recompute?.errors.length || 0} warnings`} detail={`${document.label} · v${document.version}`} tone={document.recompute?.errors.length ? 'amber' : 'green'} icon={AlertTriangle} /></div>
    <section className="diagnostic-table panel-surface"><div className="section-title"><div><span className="section-kicker">Runtime</span><h3>Capability checks</h3></div><span className="last-checked">Last checked just now</span></div><DiagnosticRow name="BitBybit Facade" value="Connected" detail="API v0.1 · single public entry" tone="green" /><DiagnosticRow name="Geometry Worker" value={geometryValue} detail={`${geometry.provider} ${geometry.version} · Box, Boolean, feature and export boundaries`} tone={geometryTone} /><DiagnosticRow name="SQLite WASM" value={persistence.sqliteWasm ? 'Worker ready' : 'Memory fallback'} detail={`Schema v${persistence.schemaVersion || 'n/a'} · ${persistence.reason || 'SQLite worker configured'}`} tone={persistence.sqliteWasm ? 'green' : 'cyan'} /><DiagnosticRow name="OPFS" value={persistence.opfs ? 'Available' : 'Fallback'} detail="Cross-origin isolation and browser OPFS capability" tone={persistence.opfs ? 'green' : 'cyan'} /><DiagnosticRow name="Recovery" value={recovery?.integrity || 'Checking'} detail={recovery ? `Last saved v${recovery.lastSavedVersion ?? 'none'}${recovery.warnings.length ? ` · ${recovery.warnings.length} warning(s)` : ''}` : 'Checking SQLite integrity and saved snapshot'} tone={recovery?.integrity === 'ok' ? 'green' : 'cyan'} /><DiagnosticRow name="FreeCAD baseline" value="1.1.1" detail="Compatibility manifest loaded; unsupported commands remain disabled" tone="cyan" /></section>
    <section className="diagnostic-tree-panel panel-surface"><div className="section-title"><div><span className="section-kicker">Document</span><h3>Diagnostic tree</h3></div><strong className={diagnosticTree.length ? 'icon-amber' : 'icon-green'}>{diagnosticTree.length} root causes</strong></div>{diagnosticTree.length === 0 ? <div className="diagnostic-empty"><CheckCircle2 size={16} />No active document diagnostics</div> : <div className="diagnostic-tree">{diagnosticTree.map((node) => <DocumentDiagnosticNode key={node.diagnostic.id} node={node} facade={facade} showNotice={showNotice} />)}</div>}</section>
  </div>
}

function DocumentDiagnosticNode({ node, facade, showNotice, child = false }: { node: DiagnosticTreeNode; facade: BitBybitWebCadFacade; showNotice: (message: string) => void; child?: boolean }) {
  const diagnostic = node.diagnostic
  const topologyRepair = diagnostic.topologyRepair
  const [topologyCandidate, setTopologyCandidate] = useState(topologyRepair?.candidates[0] ?? '')
  const runRepair = (actionId: 'select-object' | 'recompute-root' | 'suppress-root') => {
    void facade.diagnostics.repair(diagnostic.id, actionId).then((result) => showNotice(result.message))
  }
  const replaceTopologyReference = () => {
    if (!topologyRepair || !topologyCandidate) return
    try {
      facade.app.document.resolveTopologyReference({ ...topologyRepair, candidatePersistentId: topologyCandidate })
      void facade.app.document.recomputeAsync().then((result) => showNotice(result.status === 'completed' ? 'Topology reference replaced' : `Reference replaced; recompute ${result.status}`))
    } catch (error) { showNotice(error instanceof Error ? error.message : String(error)) }
  }
  return <div className={`document-diagnostic ${child ? 'is-child' : ''}`}>
    <div className="document-diagnostic-main"><span className={`diagnostic-severity ${diagnostic.severity}`}><AlertTriangle size={14} /></span><div><strong>{diagnostic.code}</strong><span>{diagnostic.message}</span><small>{diagnostic.objectId || diagnostic.source}{diagnostic.dependencyPath && diagnostic.dependencyPath.length > 1 ? ` · ${diagnostic.dependencyPath.join(' → ')}` : ''}{diagnostic.generation ? ` · generation ${diagnostic.generation}` : ''}</small></div></div>
    {diagnostic.repairActions?.length ? <div className="diagnostic-actions">{diagnostic.repairActions.map((action) => <button key={action.id} className="button button-quiet" disabled={!action.enabled} title={action.reason || action.label} onClick={() => runRepair(action.id)}>{action.id === 'select-object' ? <Search size={13} /> : action.id === 'recompute-root' ? <RefreshCw size={13} /> : <Pause size={13} />}{action.label}</button>)}</div> : null}
    {topologyRepair ? <div className="topology-repair"><select className="property-control" aria-label="Replacement subshape" value={topologyCandidate} onChange={(event) => setTopologyCandidate(event.target.value)}>{topologyRepair.candidates.map((candidate) => <option value={candidate} key={candidate}>{candidate}</option>)}</select><button className="button button-quiet" onClick={replaceTopologyReference} disabled={!topologyCandidate}><Check size={13} />Replace reference</button></div> : null}
    {node.children.length > 0 ? <div className="diagnostic-children">{node.children.map((entry) => <DocumentDiagnosticNode key={entry.diagnostic.id} node={entry} facade={facade} showNotice={showNotice} child />)}</div> : null}
  </div>
}

function HealthCard({ label, value, detail, tone, icon: HealthIcon }: { label: string; value: string; detail: string; tone: 'green' | 'cyan' | 'amber'; icon: Icon }) {
  return <div className="health-card panel-surface"><div className={`health-icon ${tone}`}><HealthIcon size={17} /></div><span className="section-kicker">{label}</span><strong>{value}</strong><small>{detail}</small></div>
}

function DiagnosticRow({ name, value, detail, tone, onClick }: { name: string; value: string; detail: string; tone: 'green' | 'cyan' | 'amber'; onClick?: () => void }) {
  return <button className="diagnostic-row" onClick={onClick}><span className="diagnostic-name"><span className={`status-dot ${tone}`} />{name}</span><span className="diagnostic-detail">{detail}</span><strong className={`diagnostic-value ${tone}`}>{value}</strong><ChevronRight size={15} /></button>
}

function SyncPage({ onNavigate, showNotice }: { onNavigate: (page: Page) => void; showNotice: (message: string) => void }) {
  return <div className="sync-page"><PageHeader eyebrow="Account and sync" title="Stay local by default." description="Cloud features are optional. Your current workspace is stored in this browser." onBack={() => onNavigate('start')} /><div className="sync-grid"><section className="sync-card panel-surface"><div className="sync-card-header"><span className="sync-logo"><UserRound size={18} /></span><div><span className="section-kicker">Not signed in</span><h2>Local workspace</h2></div><Badge tone="green">Active</Badge></div><p>Projects, recovery snapshots and cached geometry remain on this device until you explicitly export or sync them.</p><div className="sync-stats"><div><strong>4</strong><span>projects</span></div><div><strong>3.4 GB</strong><span>storage used</span></div><div><strong>Just now</strong><span>last backup</span></div></div><button className="button button-outline" onClick={() => showNotice('Sign-in flow is ready for the next phase')}><UserRound size={16} />Connect an account</button></section><section className="sync-card panel-surface"><div className="section-title"><div><span className="section-kicker">Optional services</span><h3>Choose when to share</h3></div><Settings2 size={16} /></div><SyncRow title="Project sync" detail="Keep a remote copy and resolve conflicts" disabled /><SyncRow title="Team review links" detail="Share read-only documents" disabled /><SyncRow title="Diagnostic uploads" detail="Attach reports only when requested" disabled /></section></div></div>
}

function SyncRow({ title, detail, disabled }: { title: string; detail: string; disabled?: boolean }) {
  return <div className={`sync-row ${disabled ? 'is-disabled' : ''}`}><div><strong>{title}</strong><span>{detail}</span></div><span className="toggle"><span /></span></div>
}

export default App
