import { createHash } from 'node:crypto'
import { createReadStream, existsSync } from 'node:fs'
import { mkdir, readFile, writeFile } from 'node:fs/promises'
import { createServer } from 'node:http'
import { extname, normalize, resolve } from 'node:path'
import { spawn } from 'node:child_process'
import { createChromeProfile, removeChromeProfile } from './chrome-profile.mjs'

const root = resolve(new URL('..', import.meta.url).pathname)
const dist = resolve(root, 'dist')
const evidenceDir = resolve(root, 'fixtures/chrome-app-e2e')
const reportPath = resolve(root, 'config/chrome-app-e2e-verification.json')
const chromeExecutable = process.env.CHROME_BIN || '/home/mes123456/.local/bin/google-chrome'
const contentTypes = {
  '.css': 'text/css; charset=utf-8',
  '.html': 'text/html; charset=utf-8',
  '.js': 'text/javascript; charset=utf-8',
  '.json': 'application/json; charset=utf-8',
  '.wasm': 'application/wasm',
}

if (!existsSync(resolve(dist, 'index.html'))) throw new Error('Chrome app E2E requires a production build in dist/. Run npm run build first.')
if (!existsSync(chromeExecutable)) throw new Error(`Chrome executable is unavailable: ${chromeExecutable}`)
await mkdir(evidenceDir, { recursive: true })

const server = createServer(async (request, response) => {
  response.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
  response.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
  response.setHeader('Cross-Origin-Resource-Policy', 'same-origin')
  const requestPath = decodeURIComponent((request.url || '/').split('?')[0])
  const requestedFile = requestPath === '/' ? resolve(dist, 'index.html') : normalize(resolve(dist, `.${requestPath}`))
  const file = requestedFile.startsWith(dist) && existsSync(requestedFile) ? requestedFile : resolve(dist, 'index.html')
  response.setHeader('Content-Type', contentTypes[extname(file)] || 'application/octet-stream')
  createReadStream(file).on('error', (error) => {
    response.writeHead(500)
    response.end(String(error))
  }).pipe(response)
})

await new Promise((resolveServer, rejectServer) => {
  server.once('error', rejectServer)
  server.listen(0, '127.0.0.1', resolveServer)
})
const port = server.address().port
const baseUrl = `http://127.0.0.1:${port}`
const chromeProfile = await createChromeProfile('app-e2e')

const chrome = spawn(chromeExecutable, [
  '--headless=new',
  '--no-sandbox',
  '--disable-dev-shm-usage',
  '--no-first-run',
  '--no-default-browser-check',
  '--enable-webgl',
  '--enable-unsafe-swiftshader',
  '--use-angle=swiftshader',
  '--remote-debugging-port=0',
  `--user-data-dir=${chromeProfile}`,
  'about:blank',
], { cwd: root, stdio: ['ignore', 'ignore', 'pipe'] })

let chromeStderr = ''
const debuggerUrl = await new Promise((resolveDebugger, rejectDebugger) => {
  const timer = setTimeout(() => rejectDebugger(new Error(`Chrome DevTools endpoint timed out. ${chromeStderr.slice(-2000)}`)), 30_000)
  chrome.stderr.on('data', (chunk) => {
    chromeStderr += String(chunk)
    const match = chromeStderr.match(/DevTools listening on (ws:\/\/[^\s]+)/)
    if (!match) return
    clearTimeout(timer)
    resolveDebugger(match[1])
  })
  chrome.once('exit', (code, signal) => {
    clearTimeout(timer)
    rejectDebugger(new Error(`Chrome exited before DevTools was ready: code=${code}, signal=${signal}. ${chromeStderr.slice(-2000)}`))
  })
})

class CdpClient {
  constructor(url) {
    this.socket = new WebSocket(url)
    this.sequence = 0
    this.pending = new Map()
    this.listeners = new Set()
  }

  async open() {
    await new Promise((resolveOpen, rejectOpen) => {
      this.socket.addEventListener('open', resolveOpen, { once: true })
      this.socket.addEventListener('error', () => rejectOpen(new Error('Chrome DevTools WebSocket failed to open.')), { once: true })
    })
    this.socket.addEventListener('message', (event) => {
      const message = JSON.parse(String(event.data))
      if (message.id) {
        const pending = this.pending.get(message.id)
        if (!pending) return
        this.pending.delete(message.id)
        clearTimeout(pending.timer)
        if (message.error) pending.reject(new Error(`${pending.method}: ${message.error.message}`))
        else pending.resolve(message.result)
        return
      }
      for (const listener of this.listeners) listener(message)
    })
  }

  send(method, params = {}, sessionId) {
    const id = ++this.sequence
    return new Promise((resolveMessage, rejectMessage) => {
      const timer = setTimeout(() => {
        this.pending.delete(id)
        const detail = typeof params.expression === 'string' ? ` expression=${params.expression.slice(0, 180)}` : ''
        rejectMessage(new Error(`${method}: Chrome DevTools request timed out.${detail}`))
      }, 20_000)
      this.pending.set(id, { resolve: resolveMessage, reject: rejectMessage, method, timer })
      this.socket.send(JSON.stringify({ id, method, params, ...(sessionId ? { sessionId } : {}) }))
    })
  }

  close() {
    this.socket.close()
  }
}

const client = new CdpClient(debuggerUrl)
let status = 'failed'
try {
  await client.open()
  const version = await client.send('Browser.getVersion')
  if (!/Chrome/i.test(version.product || '')) throw new Error(`Unexpected browser product: ${version.product || 'unknown'}`)
  const { targetInfos } = await client.send('Target.getTargets')
  const target = targetInfos.find((candidate) => candidate.type === 'page')
  if (!target) throw new Error('Chrome did not expose a page target.')
  const { sessionId } = await client.send('Target.attachToTarget', { targetId: target.targetId, flatten: true })
  await Promise.all([
    client.send('Page.enable', {}, sessionId),
    client.send('Runtime.enable', {}, sessionId),
    client.send('Log.enable', {}, sessionId),
  ])

  const pageErrors = []
  client.listeners.add((message) => {
    if (message.sessionId !== sessionId) return
    if (message.method === 'Runtime.exceptionThrown') pageErrors.push(message.params?.exceptionDetails?.text || 'Uncaught page exception')
    if (message.method === 'Runtime.consoleAPICalled' && message.params?.type === 'error') pageErrors.push(message.params.args?.map((entry) => entry.value || entry.description || '').join(' ') || 'console.error')
    if (message.method === 'Log.entryAdded' && message.params?.entry?.level === 'error') pageErrors.push(message.params.entry.text || 'Chrome log error')
  })

  const evaluate = async (expression) => {
    const result = await client.send('Runtime.evaluate', { expression, returnByValue: true, awaitPromise: true }, sessionId)
    if (result.exceptionDetails) throw new Error(result.exceptionDetails.exception?.description || result.exceptionDetails.text || 'Chrome evaluation failed.')
    return result.result?.value
  }
  const waitFor = async (expression, label, timeoutMs = 30_000) => {
    const deadline = Date.now() + timeoutMs
    while (Date.now() < deadline) {
      if (await evaluate(expression)) return
      await new Promise((resolveWait) => setTimeout(resolveWait, 100))
    }
    const snapshot = await evaluate('document.body.innerText.slice(-1200)')
    throw new Error(`Chrome E2E timed out waiting for ${label}. Body tail: ${snapshot}`)
  }
  const setViewport = (width, height, deviceScaleFactor = 1) => client.send('Emulation.setDeviceMetricsOverride', { width, height, deviceScaleFactor, mobile: width <= 480 }, sessionId)
  const navigate = async (path) => {
    await client.send('Page.navigate', { url: `${baseUrl}${path}` }, sessionId)
    await waitFor('document.readyState === "complete" && Boolean(document.querySelector(".app-shell"))', `${path} application shell`)
  }
  const clickButton = async (label) => {
    const clicked = await evaluate(`(() => { const label = ${JSON.stringify(label)}; const button = [...document.querySelectorAll('button')].find((candidate) => !candidate.disabled && [candidate.getAttribute('aria-label'), candidate.getAttribute('title'), candidate.textContent?.trim()].some((value) => value?.includes(label))); if (!button) return false; button.click(); return true })()`)
    if (!clicked) throw new Error(`Chrome E2E could not find enabled button containing ${JSON.stringify(label)}.`)
  }
  const screenshot = async (name) => {
    const capture = await client.send('Page.captureScreenshot', { format: 'png', fromSurface: true, captureBeyondViewport: false }, sessionId)
    const bytes = Buffer.from(capture.data, 'base64')
    if (bytes.byteLength < 20_000) throw new Error(`${name} screenshot is unexpectedly small: ${bytes.byteLength} bytes.`)
    const relativePath = `fixtures/chrome-app-e2e/${name}.png`
    await writeFile(resolve(root, relativePath), bytes)
    return { path: relativePath, byteLength: bytes.byteLength, sha256: createHash('sha256').update(bytes).digest('hex') }
  }

  await setViewport(1440, 1000)
  await navigate('/start')
  await waitFor('document.body.innerText.includes("Start a new design.")', 'start page heading')
  const offline = await evaluate(`({ path: location.pathname, shell: document.querySelector('.app-shell') !== null, heading: document.body.innerText.includes('Start a new design.'), mode: 'online-shell' })`)
  if (offline.path !== '/start' || offline.shell !== true || offline.heading !== true) throw new Error(`Chrome shell route gate failed: ${JSON.stringify(offline)}`)
  await clickButton('New document')
  await waitFor('Boolean(document.querySelector(".workspace-page"))', 'workspace page')
  await waitFor('Boolean(document.querySelector(".three-viewport-host canvas"))', 'Three.js viewport canvas')
  await waitFor('document.querySelector(".three-viewport-host canvas")?.dataset.geometrySource === "bitbybit-occt"', 'Bitbybit geometry preview', 90_000)
  const kernelPreviewSource = await evaluate(`document.querySelector('.three-viewport-host canvas')?.dataset.geometrySource || ''`)

  const selectedPartForBoxSelection = await evaluate(`(() => { const select = document.querySelector('select[aria-label="Workbench"]'); if (!select) return false; select.value = 'Part'; select.dispatchEvent(new Event('change', { bubbles: true })); return true })()`)
  if (!selectedPartForBoxSelection) throw new Error('Workbench selector could not switch to Part for viewport box selection.')
  await waitFor('document.querySelector("select[aria-label=Workbench]")?.value === "Part"', 'Part workbench change')
  await clickButton('Create primitives')
  await waitFor('Boolean(document.querySelector(".task-body select.field-input"))', 'Box primitive task')
  await clickButton('OK')
  await waitFor('document.querySelector(".report-line")?.textContent?.includes("Recompute completed") === true && Number(document.querySelector(".three-viewport-host canvas")?.dataset.objectCount || 0) >= 1', 'Box primitive recompute', 90_000)
  await clickButton('Create primitives')
  await waitFor('Boolean(document.querySelector(".task-body select.field-input"))', 'Cylinder primitive task')
  const selectedCylinder = await evaluate(`(() => { const select = document.querySelector('.task-body select.field-input'); if (!select) return false; select.value = 'Cylinder'; select.dispatchEvent(new Event('change', { bubbles: true })); return true })()`)
  if (!selectedCylinder) throw new Error('Cylinder primitive type could not be selected.')
  await clickButton('OK')
  await waitFor('document.querySelector(".report-line")?.textContent?.includes("Recompute completed") === true && Number(document.querySelector(".three-viewport-host canvas")?.dataset.objectCount || 0) >= 2', 'multi-object viewport scene', 90_000)
  const boxGesture = await evaluate(`(() => { const bounds = document.querySelector('.three-viewport-host canvas')?.getBoundingClientRect(); return bounds ? { startX: bounds.right - 20, startY: bounds.top + 20, endX: bounds.left + 20, endY: bounds.bottom - 70 } : null })()`)
  if (!boxGesture) throw new Error('Viewport canvas bounds are unavailable for box selection.')
  await client.send('Input.dispatchMouseEvent', { type: 'mousePressed', x: boxGesture.startX, y: boxGesture.startY, button: 'left', buttons: 1, modifiers: 8, clickCount: 1 }, sessionId)
  await client.send('Input.dispatchMouseEvent', { type: 'mouseMoved', x: boxGesture.endX, y: boxGesture.endY, button: 'left', buttons: 1, modifiers: 8 }, sessionId)
  await client.send('Input.dispatchMouseEvent', { type: 'mouseReleased', x: boxGesture.endX, y: boxGesture.endY, button: 'left', buttons: 0, modifiers: 8, clickCount: 1 }, sessionId)
  const viewportBoxGesture = await evaluate(`(() => { const canvas = document.querySelector('.three-viewport-host canvas'); return { mode: canvas?.dataset.boxSelectionMode || '', objectIds: (canvas?.dataset.boxSelectionObjectIds || '').split(',').filter(Boolean) } })()`)
  if (viewportBoxGesture.mode !== 'crossing' || viewportBoxGesture.objectIds.length < 2) throw new Error(`Viewport box gesture did not resolve multiple objects: ${JSON.stringify({ boxGesture, viewportBoxGesture })}`)
  const reopenedModelForBox = await evaluate(`(() => { const tab = [...document.querySelectorAll('.panel-tabs button')].find((candidate) => candidate.textContent?.trim() === 'Model'); if (!tab) return false; tab.click(); return true })()`)
  if (!reopenedModelForBox) throw new Error('Model tab could not be opened after viewport box selection.')
  await waitFor('document.querySelectorAll(".tree-row.is-selected").length >= 2', 'viewport box multi-selection')
  const viewportBoxSelection = await evaluate(`(() => { const canvas = document.querySelector('.three-viewport-host canvas'); return { objectCount: Number(canvas?.dataset.objectCount || 0), topologySource: canvas?.dataset.topologySource || '', topologySources: { face: canvas?.dataset.faceTopologySource || '', edge: canvas?.dataset.edgeTopologySource || '', vertex: canvas?.dataset.vertexTopologySource || '' }, edgeCount: Number(canvas?.dataset.subshapeEdgeCount || 0), vertexCount: Number(canvas?.dataset.subshapeVertexCount || 0), selectedCount: document.querySelectorAll('.tree-row.is-selected').length, labels: [...document.querySelectorAll('.tree-row.is-selected')].map((row) => row.textContent?.trim() || ''), gesture: ${JSON.stringify(viewportBoxGesture)} } })()`)
  if (viewportBoxSelection.objectCount < 2 || viewportBoxSelection.topologySource !== 'occt-analytic' || viewportBoxSelection.edgeCount < 4 || viewportBoxSelection.vertexCount < 4 || viewportBoxSelection.selectedCount < 2 || !viewportBoxSelection.labels.includes('Box') || !viewportBoxSelection.labels.includes('Cylinder')) throw new Error(`Viewport box selection gate failed: ${JSON.stringify(viewportBoxSelection)}`)

  await clickButton('File')
  await waitFor('Boolean(document.querySelector(".menu-popover[role=menu]"))', 'File menu')
  const fileMenu = await evaluate(`(() => { const menu = document.querySelector('.menu-popover[role=menu]'); return { items: menu?.querySelectorAll('[role=menuitem]').length || 0, labels: [...(menu?.querySelectorAll('[role=menuitem]') || [])].map((item) => item.textContent?.trim() || ''), expanded: document.querySelector('.top-menu button[aria-expanded=true]')?.textContent || '' } })()`)
  if (fileMenu.items < 7 || fileMenu.expanded !== 'File' || !fileMenu.labels.some((label) => label.includes('Save'))) throw new Error(`FreeCAD File menu gate failed: ${JSON.stringify(fileMenu)}`)
  await evaluate(`document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))`)
  await waitFor('!document.querySelector(".menu-popover")', 'File menu Escape close')

  await clickButton('Search commands')
  await waitFor('Boolean(document.querySelector(".freecad-dialog .command-palette"))', 'command search dialog')
  await waitFor('document.activeElement?.getAttribute("aria-label") === "Command search"', 'command search focus')
  const commandDialog = await evaluate(`(() => ({ modal: document.querySelector('.freecad-dialog')?.getAttribute('aria-modal') === 'true', results: document.querySelectorAll('.command-palette-list [role=option]').length, title: document.querySelector('#freecad-dialog-title')?.textContent || '', focused: document.activeElement?.getAttribute('aria-label') || '' }))()`)
  if (!commandDialog.modal || commandDialog.results < 10 || commandDialog.title !== 'Command search' || commandDialog.focused !== 'Command search') throw new Error(`Command search dialog gate failed: ${JSON.stringify(commandDialog)}`)
  await clickButton('Close dialog')

  await clickButton('Edit')
  await clickButton('Preferences')
  await waitFor('document.querySelector("#freecad-dialog-title")?.textContent === "Preferences"', 'Preferences dialog')
  const preferencesDialog = await evaluate(`(() => ({ selects: document.querySelectorAll('.dialog-form select').length, checks: document.querySelectorAll('.dialog-form input[type=checkbox]').length, modal: document.querySelector('.freecad-dialog')?.getAttribute('aria-modal') === 'true' }))()`)
  if (!preferencesDialog.modal || preferencesDialog.selects !== 3 || preferencesDialog.checks !== 2) throw new Error(`Preferences dialog gate failed: ${JSON.stringify(preferencesDialog)}`)
  await clickButton('Cancel')

  await clickButton('Help')
  await clickButton('About BitBybit CAD')
  await waitFor('document.querySelector("#freecad-dialog-title")?.textContent.includes("About BitBybit Web FreeCAD")', 'About dialog')
  const aboutDialog = await evaluate(`(() => ({ modal: document.querySelector('.freecad-dialog')?.getAttribute('aria-modal') === 'true', baseline: document.body.innerText.includes('FreeCAD 1.1.1 interaction baseline') }))()`)
  if (!aboutDialog.modal || !aboutDialog.baseline) throw new Error(`About dialog gate failed: ${JSON.stringify(aboutDialog)}`)
  await clickButton('Close')

  const selectedSketcher = await evaluate(`(() => { const select = document.querySelector('select[aria-label="Workbench"]'); if (!select) return false; select.value = 'Sketcher'; select.dispatchEvent(new Event('change', { bubbles: true })); return true })()`)
  if (!selectedSketcher) throw new Error('Workbench selector is missing from the workspace.')
  await waitFor('document.querySelector("select[aria-label=Workbench]")?.value === "Sketcher" && document.body.innerText.includes("Sketcher workbench loaded")', 'Sketcher workbench change')
  await clickButton('Create sketch')
  await waitFor('Boolean(document.querySelector(".toast"))', 'Create sketch notice')
  const cancelledSketch = await evaluate(`(() => { const button = document.querySelector('.task-actions-top .button-quiet'); if (!button || button.disabled) return false; button.click(); return true })()`)
  if (!cancelledSketch) throw new Error('Chrome E2E could not cancel the Create Sketch preview.')
  await waitFor('document.querySelector(".toast")?.textContent.includes("Task cancelled")', 'Create sketch task cancellation')
  const openedModelTab = await evaluate(`(() => { const tab = [...document.querySelectorAll('.panel-tabs button')].find((candidate) => candidate.textContent?.trim() === 'Model'); if (!tab) return false; tab.click(); return true })()`)
  if (!openedModelTab) throw new Error('Chrome E2E could not reopen the model tree tab.')
  const selectedProfile = await evaluate(`(() => { const row = [...document.querySelectorAll('.tree-row')].find((candidate) => candidate.textContent?.trim() === 'Sketch'); if (!row) return { ok: false, rows: [...document.querySelectorAll('.tree-row')].map((candidate) => candidate.textContent?.trim() || '') }; row.click(); return { ok: true, rows: [] } })()`)
  if (!selectedProfile?.ok) throw new Error(`Chrome E2E could not select the existing Sketch profile. Rows: ${JSON.stringify(selectedProfile?.rows || [])}`)
  const openedContextMenu = await evaluate(`(() => { const row = [...document.querySelectorAll('.tree-row')].find((candidate) => candidate.textContent?.trim() === 'Sketch'); if (!row) return false; row.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true, cancelable: true, clientX: 180, clientY: 330 })); return true })()`)
  if (!openedContextMenu) throw new Error('Chrome E2E could not open the model tree context menu.')
  await waitFor('Boolean(document.querySelector(".tree-context-menu[role=menu]"))', 'model tree context menu')
  const contextMenu = await evaluate(`(() => ({ items: [...document.querySelectorAll('.tree-context-menu [role=menuitem]')].map((item) => item.textContent?.trim() || ''), left: document.querySelector('.tree-context-menu')?.getBoundingClientRect().left || -1, top: document.querySelector('.tree-context-menu')?.getBoundingClientRect().top || -1 }))()`)
  if (contextMenu.items.length !== 4 || !contextMenu.items.some((label) => label.includes('Toggle visibility')) || !contextMenu.items.some((label) => label.includes('Delete')) || contextMenu.left < 0 || contextMenu.top < 0) throw new Error(`Model tree context menu gate failed: ${JSON.stringify(contextMenu)}`)
  await evaluate(`document.body.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true }))`)
  await waitFor('!document.querySelector(".tree-context-menu")', 'model tree context menu close')
  const stagedMultiSelection = await evaluate(`(() => { const rows = [...document.querySelectorAll('.tree-row')]; const sketch = rows.find((candidate) => candidate.textContent?.trim() === 'Sketch'); const pad = rows.find((candidate) => candidate.textContent?.trim() === 'Pad'); if (!sketch || !pad) return { ok: false, rows: rows.map((candidate) => candidate.textContent?.trim() || '') }; sketch.click(); pad.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, shiftKey: true })); return { ok: true, rows: [] } })()`)
  if (!stagedMultiSelection?.ok) throw new Error(`Chrome E2E could not stage model tree multi-selection. Rows: ${JSON.stringify(stagedMultiSelection?.rows || [])}`)
  await waitFor('document.querySelectorAll(".tree-row.is-selected").length >= 2', 'model tree multi-selection')
  const multiSelection = await evaluate(`(() => ({ count: document.querySelectorAll('.tree-row.is-selected').length, labels: [...document.querySelectorAll('.tree-row.is-selected')].map((row) => row.textContent?.trim() || '') }))()`)
  if (!multiSelection.labels.includes('Sketch') || !multiSelection.labels.includes('Pad')) throw new Error(`Model tree multi-selection gate failed: ${JSON.stringify(multiSelection)}`)
  await evaluate(`(() => { const sketch = [...document.querySelectorAll('.tree-row')].find((candidate) => candidate.textContent?.trim() === 'Sketch'); sketch?.click(); return Boolean(sketch) })()`)
  const selectedPartDesign = await evaluate(`(() => { const select = document.querySelector('select[aria-label="Workbench"]'); if (!select) return false; select.value = 'Part Design'; select.dispatchEvent(new Event('change', { bubbles: true })); return true })()`)
  if (!selectedPartDesign) throw new Error('Workbench selector could not switch to Part Design.')
  await waitFor('document.querySelector("select[aria-label=Workbench]")?.value === "Part Design"', 'Part Design workbench change')

  await clickButton('Additive loft')
  await waitFor('document.querySelectorAll(".task-link-list input[type=checkbox]").length >= 1', 'Loft section task controls')
  const loftTask = await evaluate(`(() => {
    const list = document.querySelector('.task-link-list')
    const panel = document.querySelector('.right-panel')
    const checks = [...document.querySelectorAll('.task-link-list input[type=checkbox]')]
    return {
      sectionCount: checks.length,
      checkedSectionCount: checks.filter((input) => input.checked).length,
      labels: [...document.querySelectorAll('.task-link-list .check-row span')].map((entry) => entry.textContent?.trim() || ''),
      listVerticalOverflow: list ? list.scrollHeight - list.clientHeight : -1,
      panelHorizontalOverflow: panel ? panel.scrollWidth - panel.clientWidth : -1,
    }
  })()`)
  if (loftTask.sectionCount < 1 || loftTask.checkedSectionCount !== 1 || !loftTask.labels.includes('Sketch (sketch)') || loftTask.panelHorizontalOverflow > 1) throw new Error(`Loft task UI gate failed: ${JSON.stringify(loftTask)}`)
  await clickButton('Collapse bottom panel')

  const desktop = await evaluate(`(async () => {
    await new Promise((resolveFrame) => requestAnimationFrame(resolveFrame))
    const canvas = document.querySelector('.three-viewport-host canvas')
    const left = document.querySelector('.left-panel')?.getBoundingClientRect()
    const viewport = document.querySelector('.viewport-region')?.getBoundingClientRect()
    const right = document.querySelector('.right-panel')?.getBoundingClientRect()
    const gl = canvas?.getContext('webgl2') || canvas?.getContext('webgl')
    let uniqueCanvasColors = 0
    let canvasGlError = -1
    if (canvas && gl && canvas.width > 0 && canvas.height > 0) {
      const pixels = new Uint8Array(canvas.width * canvas.height * 4)
      gl.readPixels(0, 0, canvas.width, canvas.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels)
      canvasGlError = gl.getError()
      const colors = new Set()
      const stride = Math.max(4, Math.floor(pixels.length / 4096 / 4) * 4)
      for (let index = 0; index < pixels.length && colors.size < 64; index += stride) colors.add([pixels[index], pixels[index + 1], pixels[index + 2], pixels[index + 3]].join(','))
      uniqueCanvasColors = colors.size
    }
    const overflowingControls = [...document.querySelectorAll('button, select, input')].filter((element) => {
      const style = getComputedStyle(element)
      return style.display !== 'none' && style.visibility !== 'hidden' && element.clientWidth > 0 && element.scrollWidth > element.clientWidth + 2
    }).length
    return {
      path: location.pathname,
      workbench: document.querySelector('select[aria-label="Workbench"]')?.value || '',
      persistenceMode: document.querySelector('.app-shell')?.dataset.persistenceMode || '',
      bodyHorizontalOverflow: document.documentElement.scrollWidth - innerWidth,
      overflowingControls,
      canvas: { width: canvas?.width || 0, height: canvas?.height || 0, source: canvas?.dataset.geometrySource || '', uniqueColors: uniqueCanvasColors, glError: canvasGlError },
      panelsSeparated: Boolean(left && viewport && right && left.right <= viewport.left + 1 && viewport.right <= right.left + 1),
      commandGroups: document.querySelectorAll('.workbench-commandbar .command-tool-group').length,
      comboTabs: [...document.querySelectorAll('.combo-panel > .panel-tabs button')].map((entry) => entry.textContent?.trim() || ''),
      selectionView: Boolean(document.querySelector('.selection-panel[aria-label="Selection View"]')),
      statusBar: Boolean(document.querySelector('.freecad-statusbar[role=status]')),
    }
  })()`)
  desktop.kernelPreviewSource = kernelPreviewSource
  if (desktop.path !== '/workspace/pump-housing' || desktop.workbench !== 'Part Design') throw new Error('Desktop workflow did not retain its workspace route and workbench state.')
  if (desktop.bodyHorizontalOverflow > 1 || !desktop.panelsSeparated || desktop.overflowingControls > 0 || desktop.commandGroups < 4 || !desktop.comboTabs.some((label) => label.startsWith('Model')) || !desktop.comboTabs.some((label) => label.startsWith('Tasks')) || !desktop.selectionView || !desktop.statusBar) throw new Error(`Desktop layout gate failed: ${JSON.stringify(desktop)}`)
  if (desktop.kernelPreviewSource !== 'bitbybit-occt' || desktop.canvas.width < 100 || desktop.canvas.height < 100 || desktop.canvas.uniqueColors < 4 || desktop.canvas.glError !== 0) throw new Error(`Desktop canvas pixel gate failed: ${JSON.stringify({ kernelPreviewSource: desktop.kernelPreviewSource, canvas: desktop.canvas })}`)
  const desktopScreenshot = await screenshot('desktop-workspace')

  await clickButton('Cancel')
  await waitFor('document.querySelector(".toast")?.textContent.includes("Task cancelled")', 'task cancellation')

  const selectedCam = await evaluate(`(() => { const select = document.querySelector('select[aria-label="Workbench"]'); if (!select) return false; select.value = 'CAM'; select.dispatchEvent(new Event('change', { bubbles: true })); return true })()`)
  if (!selectedCam) throw new Error('Workbench selector could not switch to CAM.')
  await waitFor('document.querySelector("select[aria-label=Workbench]")?.value === "CAM" && Boolean([...document.querySelectorAll(".top-menu > .menu-wrapper > button")].find((button) => button.textContent?.trim() === "CAM"))', 'CAM workbench chrome')
  await clickButton('CAM')
  await waitFor('Boolean(document.querySelector(".menu-popover-cam[role=menu]"))', 'CAM workbench menu')
  const camMenu = await evaluate(`(() => ({ items: document.querySelectorAll('.menu-popover-cam [role=menuitem]').length, groups: [...document.querySelectorAll('.menu-popover-cam .menu-section-label')].map((entry) => entry.textContent?.trim() || ''), labels: [...document.querySelectorAll('.menu-popover-cam [role=menuitem]')].map((entry) => entry.textContent?.trim() || '') }))()`)
  if (camMenu.items !== 60 || JSON.stringify(camMenu.groups) !== JSON.stringify(['Project Setup', 'Simulation and Tools', '2D Operations', 'Machining Operations', 'Path Modification']) || !camMenu.labels.some((label) => label.includes('Post Process')) || !camMenu.labels.some((label) => label.includes('Drag Knife Dress-up'))) throw new Error(`CAM menu gate failed: ${JSON.stringify(camMenu)}`)
  await evaluate(`document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))`)
  await waitFor('!document.querySelector(".menu-popover-cam")', 'CAM menu close')

  await clickButton('Create Job')
  await waitFor('document.querySelector("[data-testid=cam-task-panel] .task-header h2")?.textContent === "Create Job"', 'CAM Job task')
  const camJobTask = await evaluate(`(() => ({ stockModes: document.querySelector('[data-testid=cam-task-panel] select')?.options.length || 0, fields: document.querySelectorAll('[data-testid=cam-task-panel] input').length, actions: [...document.querySelectorAll('[data-testid=cam-task-panel] .task-actions-top button')].map((button) => button.textContent?.trim() || '') }))()`)
  if (camJobTask.stockModes !== 4 || camJobTask.fields < 5 || JSON.stringify(camJobTask.actions) !== JSON.stringify(['OK', 'Apply', 'Cancel'])) throw new Error(`CAM Job task gate failed: ${JSON.stringify(camJobTask)}`)
  await clickButton('OK')
  await waitFor('document.querySelector(".toast")?.textContent.includes("CAM Job and SetupSheet updated")', 'CAM Job task commit')
  await clickButton('Fixture')
  await waitFor('document.querySelector("[data-testid=cam-task-panel] .task-header h2")?.textContent === "Fixture"', 'CAM Fixture task')
  const camFixtureTask = await evaluate(`(() => ({ inputs: document.querySelectorAll('[data-testid=cam-task-panel] input').length, section: [...document.querySelectorAll('[data-testid=cam-task-panel] .cam-task-section')].some((entry) => entry.textContent?.trim() === 'Fixture Bounds'), labels: [...document.querySelectorAll('[data-testid=cam-task-panel] .field-label')].map((label) => label.textContent?.trim() || '') }))()`)
  if (camFixtureTask.inputs !== 7 || !camFixtureTask.section || !camFixtureTask.labels.some((label) => label.includes('Fixture ID')) || !camFixtureTask.labels.some((label) => label.includes('Max Z'))) throw new Error(`CAM Fixture task gate failed: ${JSON.stringify(camFixtureTask)}`)
  await clickButton('Cancel')
  await waitFor('!document.querySelector("[data-testid=cam-task-panel] .task-actions-top")', 'CAM Fixture cancellation')
  await clickButton('Add Tool Controller')
  await waitFor('document.querySelector("[data-testid=cam-task-panel] .task-header h2")?.textContent === "Tool Controller"', 'CAM Tool Controller task')
  const camToolTask = await evaluate(`(() => ({ selects: document.querySelectorAll('[data-testid=cam-task-panel] select').length, inputs: document.querySelectorAll('[data-testid=cam-task-panel] input').length }))()`)
  if (camToolTask.selects < 2 || camToolTask.inputs !== 13) throw new Error(`CAM Tool Controller task gate failed: ${JSON.stringify(camToolTask)}`)
  await clickButton('OK')
  await waitFor('document.querySelector(".toast")?.textContent.includes("ToolBit and Tool Controller")', 'CAM Tool Controller commit')
  await clickButton('Profile')
  await waitFor('document.querySelector("[data-testid=cam-task-panel] .task-header h2")?.textContent === "Profile"', 'CAM Profile task')
  const camOperationTask = await evaluate(`(() => ({ inputs: document.querySelectorAll('[data-testid=cam-task-panel] input').length, selects: document.querySelectorAll('[data-testid=cam-task-panel] select').length }))()`)
  if (camOperationTask.inputs < 5 || camOperationTask.selects < 2) throw new Error(`CAM Profile task gate failed: ${JSON.stringify(camOperationTask)}`)
  await clickButton('OK')
  await waitFor('document.querySelector(".toast")?.textContent.includes("path points")', 'CAM Profile generation')
  await clickButton('Undo')
  await waitFor('Number(document.querySelector(".three-viewport-host canvas")?.dataset.toolpathPoints || 0) === 0', 'CAM toolpath undo')
  const camUndoUi = await evaluate(`({ pathPoints: Number(document.querySelector('.three-viewport-host canvas')?.dataset.toolpathPoints || 0), redoEnabled: document.querySelector('button[aria-label="Redo"]')?.disabled === false })`)
  if (camUndoUi.pathPoints !== 0 || !camUndoUi.redoEnabled) throw new Error(`CAM Undo UI gate failed: ${JSON.stringify(camUndoUi)}`)
  await clickButton('Redo')
  await waitFor('Number(document.querySelector(".three-viewport-host canvas")?.dataset.toolpathPoints || 0) >= 5', 'CAM toolpath redo')
  const camRedoUi = await evaluate(`({ pathPoints: Number(document.querySelector('.three-viewport-host canvas')?.dataset.toolpathPoints || 0), undoEnabled: document.querySelector('button[aria-label="Undo"]')?.disabled === false })`)
  if (camRedoUi.pathPoints < 5 || !camRedoUi.undoEnabled) throw new Error(`CAM Redo UI gate failed: ${JSON.stringify(camRedoUi)}`)
  await clickButton('Load ToolBit')
  await waitFor('document.querySelector("[data-testid=cam-task-panel] .task-header h2")?.textContent === "Load ToolBit"', 'CAM ToolBit Load task')
  const camToolBitLoadTask = await evaluate(`(() => ({ inputs: document.querySelectorAll('[data-testid=cam-task-panel] input').length, textareas: document.querySelectorAll('[data-testid=cam-task-panel] textarea').length, schemaVersion: document.querySelector('[data-testid=cam-task-panel] textarea')?.value.includes('"schemaVersion": 1') === true }))()`)
  if (camToolBitLoadTask.inputs !== 1 || camToolBitLoadTask.textareas !== 1 || !camToolBitLoadTask.schemaVersion) throw new Error(`CAM ToolBit Load task gate failed: ${JSON.stringify(camToolBitLoadTask)}`)
  await clickButton('Cancel')
  await waitFor('!document.querySelector("[data-testid=cam-task-panel] .task-actions-top")', 'CAM ToolBit Load cancellation')
  await clickButton('Drilling')
  await waitFor('document.querySelector("[data-testid=cam-task-panel] .task-header h2")?.textContent === "Drilling"', 'CAM Drilling task')
  const camDrillingTask = await evaluate(`(() => ({ inputs: document.querySelectorAll('[data-testid=cam-task-panel] input').length, selects: document.querySelectorAll('[data-testid=cam-task-panel] select').length, labels: [...document.querySelectorAll('[data-testid=cam-task-panel] .field-label')].map((label) => label.textContent?.trim() || '') }))()`)
  if (camDrillingTask.inputs !== 5 || camDrillingTask.selects !== 2 || !camDrillingTask.labels.some((label) => label.includes('Final Depth'))) throw new Error(`CAM Drilling task gate failed: ${JSON.stringify(camDrillingTask)}`)
  await clickButton('Cancel')
  await waitFor('!document.querySelector("[data-testid=cam-task-panel] .task-actions-top")', 'CAM Drilling cancellation')
  await clickButton('Drag Knife Dress-up')
  await waitFor('document.querySelector("[data-testid=cam-task-panel] .task-header h2")?.textContent === "Drag Knife Dress-up"', 'CAM Drag Knife task')
  const camDragKnifeTask = await evaluate(`(() => ({ inputs: document.querySelectorAll('[data-testid=cam-task-panel] input').length, selects: document.querySelectorAll('[data-testid=cam-task-panel] select').length, knifeOffset: [...document.querySelectorAll('[data-testid=cam-task-panel] .field-label')].some((label) => label.textContent?.includes('Knife Offset')) }))()`)
  if (camDragKnifeTask.inputs !== 1 || camDragKnifeTask.selects !== 1 || !camDragKnifeTask.knifeOffset) throw new Error(`CAM Drag Knife task gate failed: ${JSON.stringify(camDragKnifeTask)}`)
  await clickButton('Cancel')
  await waitFor('!document.querySelector("[data-testid=cam-task-panel] .task-actions-top")', 'CAM Drag Knife cancellation')
  await clickButton('Post Process')
  await waitFor('document.querySelector("[data-testid=cam-task-panel] .task-header h2")?.textContent === "Post Process"', 'CAM Post Process task')
  const selectedFiveAxis = await evaluate(`(() => { const label = [...document.querySelectorAll('[data-testid=cam-task-panel] .field-label')].find((entry) => entry.textContent?.includes('Axis Configuration')); const select = label?.querySelector('select'); if (!select) return false; select.value = '5-axis'; select.dispatchEvent(new Event('change', { bubbles: true })); return true })()`)
  if (!selectedFiveAxis) throw new Error('CAM Post Process task could not select 5-axis mode.')
  await waitFor('document.querySelectorAll("[data-testid=cam-task-panel] select").length === 4 && document.querySelectorAll("[data-testid=cam-task-panel] input").length === 4', 'CAM 5-axis post controls')
  const camPostTask = await evaluate(`(() => ({ inputs: document.querySelectorAll('[data-testid=cam-task-panel] input').length, selects: document.querySelectorAll('[data-testid=cam-task-panel] select').length, labels: [...document.querySelectorAll('[data-testid=cam-task-panel] .field-label')].map((label) => label.textContent?.trim() || ''), note: document.querySelector('[data-testid=cam-task-panel] .task-note')?.textContent?.trim() || '' }))()`)
  if (camPostTask.inputs !== 4 || camPostTask.selects !== 4 || !camPostTask.labels.some((label) => label.includes('Rotary End')) || !camPostTask.labels.some((label) => label.includes('Tilt End')) || !camPostTask.note.includes('rotary limit checks')) throw new Error(`CAM 5-axis Post task gate failed: ${JSON.stringify(camPostTask)}`)
  await clickButton('Cancel')
  await waitFor('!document.querySelector("[data-testid=cam-task-panel] .task-actions-top")', 'CAM Post Process cancellation')
  const camModelTab = await evaluate(`(() => { const tab = [...document.querySelectorAll('.combo-panel > .panel-tabs button')].find((button) => button.textContent?.trim() === 'Model'); if (!tab) return false; tab.click(); return true })()`)
  if (!camModelTab) throw new Error('CAM workflow could not open the Model tab.')
  await waitFor('Boolean(document.querySelector("[data-testid=cam-job-tree]")) && document.querySelectorAll("[data-testid=cam-job-tree] .cam-tree-row").length >= 7', 'CAM Job tree')
  await clickButton('Simulators')
  await waitFor('document.querySelector(".toast")?.textContent.includes("CAM simulation passed")', 'CAM simulation')
  const reopenedCamModelTab = await evaluate(`(() => { const tab = [...document.querySelectorAll('.combo-panel > .panel-tabs button')].find((button) => button.textContent?.trim() === 'Model'); if (!tab) return false; tab.click(); return true })()`)
  if (!reopenedCamModelTab) throw new Error('CAM workflow could not reopen the Model tab after simulation.')
  await waitFor('Boolean(document.querySelector("[data-testid=cam-job-tree]"))', 'CAM Job tree after simulation')
  const camUi = await evaluate(`(() => { const canvas = document.querySelector('.three-viewport-host canvas'); return { workbench: document.querySelector('select[aria-label=Workbench]')?.value || '', commandGroups: document.querySelectorAll('.workbench-commandbar .command-tool-group').length, toolbarCommands: document.querySelectorAll('.workbench-commandbar .command-tool-buttons button').length, jobTree: Boolean(document.querySelector('[data-testid=cam-job-tree]')), treeRows: document.querySelectorAll('[data-testid=cam-job-tree] .cam-tree-row').length, operations: [...document.querySelectorAll('[data-testid=cam-job-tree] .cam-tree-row')].filter((row) => row.textContent?.includes('profile')).length, generated: [...document.querySelectorAll('[data-testid=cam-job-tree] .cam-state')].some((state) => state.textContent?.trim() === 'generated'), toolpathPoints: Number(canvas?.dataset.toolpathPoints || 0), toolpathOperations: Number(canvas?.dataset.toolpathOperations || 0), toolpathLegend: document.body.innerText.includes('Toolpath'), horizontalOverflow: document.documentElement.scrollWidth - innerWidth } })()`)
  if (camUi.workbench !== 'CAM' || camUi.commandGroups !== 4 || camUi.toolbarCommands !== 60 || !camUi.jobTree || camUi.treeRows < 7 || camUi.operations !== 1 || !camUi.generated || camUi.toolpathPoints < 5 || camUi.toolpathOperations !== 1 || !camUi.toolpathLegend || camUi.horizontalOverflow > 1) throw new Error(`CAM workbench UI gate failed: ${JSON.stringify(camUi)}`)
  const camScreenshot = await screenshot('cam-workbench')

  await clickButton('Save project')
  await waitFor('document.querySelector(".toast")?.textContent.includes("Saved to local workspace")', 'OPFS save completion')
  await clickButton('Open project')
  await waitFor('location.pathname === "/projects" && document.body.innerText.includes("Your projects.")', 'Project Manager')
  await waitFor('[...document.querySelectorAll(".project-list-row .list-main strong")].some((entry) => entry.textContent?.trim() === "Pump Housing")', 'saved OPFS project row')
  const openedSavedProject = await evaluate(`(() => { const label = [...document.querySelectorAll('.project-list-row .list-main strong')].find((entry) => entry.textContent?.trim() === 'Pump Housing'); const row = label?.closest('button'); if (!row) return false; row.click(); return true })()`)
  if (!openedSavedProject) throw new Error('Saved project row could not be reopened.')
  await waitFor('location.pathname === "/workspace/pump-housing" && document.querySelector(".toast")?.textContent.includes("Loaded Pump Housing")', 'saved OPFS project reopen')
  const persistenceRoundTrip = await evaluate(`({ path: location.pathname, documentLabel: document.querySelector('.context-document')?.textContent?.trim() || '', persistenceMode: document.querySelector('.app-shell')?.dataset.persistenceMode || '' })`)
  if (!persistenceRoundTrip.documentLabel.includes('Pump Housing') || persistenceRoundTrip.persistenceMode !== 'sqlite-opfs') throw new Error(`OPFS project reopen gate failed: ${JSON.stringify(persistenceRoundTrip)}`)

  await clickButton('Open project')
  await waitFor('location.pathname === "/projects" && document.body.innerText.includes("Your projects.")', 'project manager for import')
  await clickButton('Import')
  await waitFor('location.pathname === "/import" && document.body.innerText.includes("Select a CAD file")', 'import page')
  const importFlow = await evaluate(`(() => ({ path: location.pathname, accept: document.querySelector('input[type="file"]')?.getAttribute('accept') || '', exchangeHint: document.body.innerText.includes('STEP · IGES · BREP · FCStd') }))()`)
  if (importFlow.accept !== '.FCStd,.fcstd,.step,.stp,.iges,.igs,.brep,.brp' || importFlow.exchangeHint !== true) throw new Error(`Import format state gate failed: ${JSON.stringify(importFlow)}`)
  await navigate('/workspace/pump-housing')

  await clickButton('File')
  await clickButton('Export...')
  await waitFor('location.pathname === "/export" && document.body.innerText.includes("Export a clean deliverable.")', 'export page')
  const exportFlow = await evaluate(`(() => {
    const formats = Object.fromEntries([...document.querySelectorAll('.format-card')].map((button) => [button.querySelector('strong')?.textContent || '', { disabled: button.disabled, selected: button.classList.contains('is-selected') }]))
    return { path: location.pathname, formats }
  })()`)
  if (exportFlow.formats?.STEP?.selected !== true || exportFlow.formats?.STEP?.disabled !== false || exportFlow.formats?.STL?.disabled !== false || exportFlow.formats?.IGES?.disabled !== false) throw new Error(`Export format state gate failed: ${JSON.stringify(exportFlow)}`)
  await clickButton('STL')
  await waitFor('document.querySelector(".toast")?.textContent.includes("STL selected")', 'STL format selection')
  exportFlow.selectedAfterInteraction = await evaluate(`document.querySelector('.format-card.is-selected strong')?.textContent || ''`)
  if (exportFlow.selectedAfterInteraction !== 'STL') throw new Error('STL export selection did not update the UI state.')

  await setViewport(390, 844, 2)
  await navigate('/start')
  await waitFor('document.body.innerText.includes("Start a new design.")', 'mobile start page')
  const mobile = await evaluate(`(() => {
    const topbar = document.querySelector('.topbar')?.getBoundingClientRect()
    const heading = document.querySelector('.page-heading h1')?.getBoundingClientRect()
    const actions = document.querySelector('.page-actions')?.getBoundingClientRect()
    return {
      path: location.pathname,
      viewport: { width: innerWidth, height: innerHeight, devicePixelRatio },
      bodyHorizontalOverflow: document.documentElement.scrollWidth - innerWidth,
      visibleHeading: Boolean(heading && heading.width > 0 && heading.top >= (topbar?.bottom || 0) && heading.bottom < innerHeight),
      visibleActions: Boolean(actions && actions.width > 0 && actions.top >= (heading?.bottom || 0) && actions.bottom < innerHeight),
    }
  })()`)
  if (mobile.path !== '/start' || mobile.viewport.width !== 390 || mobile.bodyHorizontalOverflow > 1 || !mobile.visibleHeading || !mobile.visibleActions) throw new Error(`Mobile layout gate failed: ${JSON.stringify(mobile)}`)
  const pwa = await evaluate(`(async () => { const link = document.querySelector('link[rel="manifest"]'); const response = await fetch(link?.getAttribute('href') || ''); const manifest = response.ok ? await response.json() : null; return { manifestLinked: Boolean(link), manifestStatus: response.status, name: manifest?.name || '', startUrl: manifest?.start_url || '', scope: manifest?.scope || '', display: manifest?.display || '' } })()`)
  if (pwa.manifestLinked !== true || pwa.manifestStatus !== 200 || pwa.name !== 'BitBybit CAD Studio' || pwa.startUrl !== '/start' || pwa.scope !== '/' || pwa.display !== 'standalone') throw new Error(`PWA manifest gate failed: ${JSON.stringify(pwa)}`)
  const accessibility = await evaluate(`(() => {
    const visible = (element) => { const style = getComputedStyle(element); return style.display !== 'none' && style.visibility !== 'hidden' && element.getClientRects().length > 0 }
    const name = (element) => element.getAttribute('aria-label') || element.getAttribute('title') || element.textContent?.trim() || element.getAttribute('placeholder') || ''
    const controls = [...document.querySelectorAll('button, input, select, textarea')].filter(visible)
    const missing = controls.filter((element) => !name(element)).map((element) => element.tagName.toLowerCase() + '.' + (element.className || ''))
    return { checked: controls.length, missing }
  })()`)
  if (accessibility.missing.length > 0) throw new Error(`Chrome accessibility naming gate failed: ${JSON.stringify(accessibility)}`)
  const accessibilityTree = await client.send('Accessibility.getFullAXTree', {}, sessionId)
  const accessibilityRoles = new Set(['button', 'checkbox', 'combobox', 'link', 'menuitem', 'radio', 'searchbox', 'slider', 'spinbutton', 'switch', 'tab', 'textbox'])
  const accessibilityNodes = (accessibilityTree.nodes || []).filter((node) => node.ignored !== true)
  const accessibilityControls = accessibilityNodes.filter((node) => accessibilityRoles.has(node.role?.value || ''))
  const screenReader = {
    nodes: accessibilityNodes.length,
    controls: accessibilityControls.length,
    namedControls: accessibilityControls.filter((node) => Boolean(node.name?.value?.trim())).length,
    unnamedControls: accessibilityControls.filter((node) => !node.name?.value?.trim()).length,
    landmarks: accessibilityNodes.filter((node) => ['main', 'navigation', 'region'].includes(node.role?.value || '')).length,
  }
  if (screenReader.nodes < 10 || screenReader.controls < 8 || screenReader.namedControls !== screenReader.controls || screenReader.unnamedControls !== 0) throw new Error(`Chrome accessibility tree gate failed: ${JSON.stringify(screenReader)}`)
  const focusSequence = []
  for (let index = 0; index < 8; index += 1) {
    await client.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'Tab', code: 'Tab', windowsVirtualKeyCode: 9, nativeVirtualKeyCode: 9 }, sessionId)
    await client.send('Input.dispatchKeyEvent', { type: 'keyUp', key: 'Tab', code: 'Tab', windowsVirtualKeyCode: 9, nativeVirtualKeyCode: 9 }, sessionId)
    focusSequence.push(await evaluate(`(() => { const element = document.activeElement; return { tag: element?.tagName || '', name: element?.getAttribute('aria-label') || element?.getAttribute('title') || element?.textContent?.trim() || element?.getAttribute('placeholder') || '', visible: Boolean(element && element.getClientRects().length) } })()`))
  }
  const keyboard = { steps: focusSequence.length, named: focusSequence.filter((entry) => entry.visible && entry.name).length, unnamedVisible: focusSequence.filter((entry) => entry.visible && !entry.name).length, sequence: focusSequence }
  if (keyboard.steps !== 8 || keyboard.named !== keyboard.steps || keyboard.unnamedVisible !== 0) throw new Error(`Chrome keyboard focus gate failed: ${JSON.stringify(keyboard)}`)
  const mobileScreenshot = await screenshot('mobile-start')

  if (pageErrors.length > 0) throw new Error(`Chrome application emitted page errors: ${pageErrors.join(' | ')}`)
  status = 'pass'
  const report = {
    schemaVersion: 1,
    generatedAt: new Date().toISOString(),
    browserId: 'chrome',
    status,
    browser: { product: version.product, protocolVersion: version.protocolVersion, userAgent: version.userAgent },
    headers: { coop: 'same-origin', coep: 'require-corp' },
    workflows: ['start-to-workspace', 'viewport-multi-object-box-selection', 'freecad-menus', 'command-search-dialog', 'preferences-about-dialogs', 'model-tree-context-menu', 'workbench-change', 'create-sketch-command', 'loft-section-task', 'drawer-collapse', 'cam-workbench-job-flow', 'opfs-save-reopen', 'import-format-selection', 'export-format-selection'],
    uiParity: { fileMenu, commandDialog, preferencesDialog, aboutDialog, contextMenu, multiSelection, viewportBoxSelection, camMenu },
    desktop,
    loftTask,
    cam: { jobTask: camJobTask, toolTask: camToolTask, operationTask: camOperationTask, undoRedo: { undo: camUndoUi, redo: camRedoUi }, extendedTasks: { fixture: camFixtureTask, toolBitLoad: camToolBitLoadTask, drilling: camDrillingTask, dragKnife: camDragKnifeTask, post: camPostTask }, ui: camUi },
    persistenceRoundTrip,
    importFlow,
    exportFlow,
    mobile,
    accessibility,
    screenReader,
    keyboard,
    pwa,
    offline,
    screenshots: { desktop: desktopScreenshot, cam: camScreenshot, mobile: mobileScreenshot },
    pageErrors,
  }
  await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`)
  console.log(JSON.stringify(report, null, 2))
} finally {
  client.close()
  chrome.kill('SIGTERM')
  await new Promise((resolveServer) => server.close(resolveServer))
  await removeChromeProfile(chromeProfile)
  if (status !== 'pass') console.error(chromeStderr.slice(-3000))
}
