import assert from 'node:assert/strict'
import test from 'node:test'
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'

test('canvas workflow side panel resizing is owned by the shared layout controller', () => {
  const workflowPanelsSource = readFileSync(resolve('src/features/canvas/ui/CanvasWorkflowPanels.tsx'), 'utf8')
  const workflowComponentSource = readFileSync(resolve('../../packages/ui/src/components/business/canvas/workflow/index.tsx'), 'utf8')
  const workflowStyles = readFileSync(resolve('../../packages/ui/src/components/business/canvas/workflow/styles.css'), 'utf8')

  assert.match(workflowPanelsSource, /useResizablePanel\(\{[\s\S]*resizeEdge: 'left'/)
  assert.match(workflowPanelsSource, /<CanvasWorkflowResizeHandle[\s\S]*\{\.{3}sidePanelResize\.resizeHandleProps\}[\s\S]*side="left"/)
  assert.match(workflowComponentSource, /return <PanelResizeHandle className=\{cn\("canvas-workflow-side-panel__resize-handle"/)
  assert.match(workflowStyles, /\.canvas-workflow-side-panel__resize-handle\.panel-resize-handle--left \{[\s\S]*width: 8px;[\s\S]*transform: translateX\(-4px\);/)
  assert.doesNotMatch(workflowPanelsSource, /function startResize/)
  assert.doesNotMatch(workflowPanelsSource, /window\.addEventListener\('pointermove'/)
})

test('canvas viewport overlays are owned by an explicit viewport overlay layer', () => {
  const canvasEditorSource = readFileSync(resolve('src/features/canvas/components/CanvasEditorPage.tsx'), 'utf8')
  const contextMenuSource = readFileSync(resolve('src/features/canvas/ui/ContextMenu.tsx'), 'utf8')
  const contextMenuPlacementSource = readFileSync(resolve('src/features/canvas/presentation/canvasContextMenuPlacement.ts'), 'utf8')
  const canvasEditorComponentSource = readFileSync(resolve('../../packages/ui/src/components/business/canvas/editor/index.tsx'), 'utf8')
  const canvasEditorStyles = readFileSync(resolve('../../packages/ui/src/components/business/canvas/editor/styles.css'), 'utf8')
  const contextMenuStyles = readFileSync(resolve('../../packages/ui/src/components/business/canvas/context-menu/styles.css'), 'utf8')

  assert.match(canvasEditorComponentSource, /export function CanvasViewportOverlayLayer/)
  assert.match(canvasEditorStyles, /\.canvas-viewport-overlay-layer \{[\s\S]*position: absolute;[\s\S]*inset: 0;[\s\S]*z-index: 100;/)
  assert.match(canvasEditorSource, /<CanvasViewportOverlayLayer>[\s\S]*<CanvasViewportEmptyOverlay>[\s\S]*<CanvasDropOverlay>[\s\S]*<CanvasViewportStatusOverlay[\s\S]*<ContextMenu/)
  assert.match(canvasEditorSource, /positioning="viewport"/)
  assert.match(contextMenuSource, /positioning\?: 'fixed' \| 'viewport'/)
  assert.match(contextMenuPlacementSource, /export function canvasContextMenuPositionFromElement/)
  assert.match(contextMenuPlacementSource, /export function canvasContextMenuStyleFromPosition/)
  assert.match(contextMenuSource, /canvasContextMenuPositionFromElement\(\{/)
  assert.match(contextMenuSource, /canvasContextMenuStyleFromPosition\(position\)/)
  assert.doesNotMatch(contextMenuSource, /left: position\.left/)
  assert.doesNotMatch(contextMenuSource, /top: position\.top/)
  assert.doesNotMatch(contextMenuSource, /getBoundingClientRect\(\)/)
  assert.doesNotMatch(contextMenuSource, /window\.innerWidth/)
  assert.doesNotMatch(contextMenuSource, /window\.innerHeight/)
  assert.match(contextMenuStyles, /\.canvas-context-menu--viewport \{[\s\S]*position: absolute;/)
})

test('canvas drop target parsing is centralized before page-level commit actions', () => {
  const canvasEditorSource = readFileSync(resolve('src/features/canvas/components/CanvasEditorPage.tsx'), 'utf8')
  const dropTargetSource = readFileSync(resolve('src/features/canvas/domain/canvasDropTarget.ts'), 'utf8')
  const viewportGeometrySource = readFileSync(resolve('src/features/canvas/presentation/canvasViewportGeometry.ts'), 'utf8')

  assert.match(dropTargetSource, /export type CanvasDropPayload =/)
  assert.match(dropTargetSource, /export interface CanvasDropLayoutHitMap/)
  assert.match(dropTargetSource, /export function createCanvasViewportDropHitMap/)
  assert.match(dropTargetSource, /export function canvasDropHasAcceptedPayload/)
  assert.match(dropTargetSource, /export function acceptCanvasDropDragOver/)
  assert.match(dropTargetSource, /export function startCanvasNodeTemplateDrag/)
  assert.match(dropTargetSource, /export function startCanvasWorkflowDrag/)
  assert.match(dropTargetSource, /export function readCanvasDropPayload/)
  assert.match(viewportGeometrySource, /export function createCanvasViewportDropHitMapFromElement/)
  assert.match(viewportGeometrySource, /export function canvasClientPointFromEvent/)
  assert.match(viewportGeometrySource, /export function canvasViewportDropHitBoxFromEvent/)
  assert.match(canvasEditorSource, /const payload = readCanvasDropPayload\(e\.dataTransfer/)
  assert.match(canvasEditorSource, /const clientPoint = canvasClientPointFromEvent\(e\)/)
  assert.match(canvasEditorSource, /canvasViewportDropHitBoxFromEvent\(\{ event: e, viewport: canvasPaneRef\.current, payload \}\)/)
  assert.match(canvasEditorSource, /switch \(payload\.kind\)/)
  assert.match(canvasEditorSource, /acceptCanvasDropDragOver\(\{ dataTransfer: e\.dataTransfer, hitBox \}\)/)
  assert.doesNotMatch(canvasEditorSource, /createCanvasViewportDropHitMap\(\{/)
  assert.doesNotMatch(canvasEditorSource, /e\.clientX/)
  assert.doesNotMatch(canvasEditorSource, /e\.clientY/)
  assert.doesNotMatch(canvasEditorSource, /canvasPaneRef\.current\?\.getBoundingClientRect\(\)/)
  assert.doesNotMatch(canvasEditorSource, /readCanvasWorkflowDragPayload\(e\.dataTransfer\)/)
  assert.doesNotMatch(canvasEditorSource, /readCanvasNodeTypeDragPayload\(e\.dataTransfer\)/)
  assert.doesNotMatch(canvasEditorSource, /readResourceFromDragPayload\(e\.dataTransfer\)/)
  assert.doesNotMatch(canvasEditorSource, /writeCanvasNodeTypeDragPayload\(/)
  assert.doesNotMatch(canvasEditorSource, /dataTransfer\.dropEffect = 'copy'/)
})

test('canvas viewport geometry is owned by the presentation adapter', () => {
  const canvasEditorSource = readFileSync(resolve('src/features/canvas/components/CanvasEditorPage.tsx'), 'utf8')
  const viewportGeometrySource = readFileSync(resolve('src/features/canvas/presentation/canvasViewportGeometry.ts'), 'utf8')

  assert.match(viewportGeometrySource, /export function canvasDefaultClientPointFromViewportElement/)
  assert.match(viewportGeometrySource, /export function canvasOverlayPointFromClient/)
  assert.match(viewportGeometrySource, /export function canvasViewportContextMenuBoundary/)
  assert.match(viewportGeometrySource, /export function canvasViewportSizeFromElement/)
  assert.match(viewportGeometrySource, /export function canvasRenderDiagnosticViewport/)
  assert.match(canvasEditorSource, /canvasDefaultClientPointFromViewportElement\(canvasPaneRef\.current\)/)
  assert.match(canvasEditorSource, /canvasOverlayPointFromViewportElement\(point, canvasPaneRef\.current\)/)
  assert.match(canvasEditorSource, /boundary: canvasViewportContextMenuBoundary\(canvasPaneRef\.current\)/)
  assert.match(canvasEditorSource, /const viewportSize = canvasViewportSizeFromElement\(canvasPaneRef\.current\)/)
  assert.match(canvasEditorSource, /viewport: canvasRenderDiagnosticViewport\(\)/)
  assert.doesNotMatch(canvasEditorSource, /window\.innerWidth/)
  assert.doesNotMatch(canvasEditorSource, /window\.innerHeight/)
  assert.doesNotMatch(canvasEditorSource, /window\.devicePixelRatio/)
})

test('canvas viewport performance states avoid imperative CSS overrides', () => {
  const flowStyles = readFileSync(resolve('../../packages/ui/src/components/business/canvas/flow/styles.css'), 'utf8')

  assert.match(flowStyles, /\.canvas-flow\.canvas-flow--debug-no-shadows \.react-flow__node/)
  assert.match(flowStyles, /\.canvas-flow\.canvas-flow--overview \.react-flow__handle/)
  assert.match(flowStyles, /\.canvas-flow\.canvas-flow--overview \.canvas-node-card,[\s\S]*box-shadow: none;/)
  assert.doesNotMatch(flowStyles, /!important/)
})

test('canvas render diagnostics reuse layout helpers for rect formatting', () => {
  const canvasEditorSource = readFileSync(resolve('src/features/canvas/components/CanvasEditorPage.tsx'), 'utf8')
  const layoutSource = readFileSync(resolve('src/features/canvas/domain/layout.ts'), 'utf8')
  const renderDiagnosticsSource = readFileSync(resolve('src/features/canvas/presentation/canvasRenderDiagnostics.ts'), 'utf8')
  const debugOptionsSource = readFileSync(resolve('src/features/canvas/presentation/canvasDebugOptions.ts'), 'utf8')

  assert.match(layoutSource, /export function compactCanvasLayoutRect/)
  assert.match(renderDiagnosticsSource, /compactCanvasLayoutRect\(dom\.rootRect\)/)
  assert.match(renderDiagnosticsSource, /compactCanvasLayoutRect\(dom\.flowRect\)/)
  assert.match(renderDiagnosticsSource, /compactCanvasLayoutRect\(rect\)/)
  assert.match(debugOptionsSource, /export function parseCanvasDebugOptions/)
  assert.match(debugOptionsSource, /window\.localStorage\.getItem\(key\)/)
  assert.match(canvasEditorSource, /parseCanvasDebugOptions\(search\)/)
  assert.match(canvasEditorSource, /canvasRenderDiagnosticsEnabled\(\{[\s\S]*dev: import\.meta\.env\.DEV,[\s\S]*renderDiagnostics: import\.meta\.env\.VITE_MOVSCRIPT_RENDER_DIAGNOSTICS/)
  assert.match(canvasEditorSource, /logCanvasRenderDiagnostics\(\{/)
  assert.doesNotMatch(canvasEditorSource, /function compactCanvasRect/)
  assert.doesNotMatch(canvasEditorSource, /function compactCanvasMediaElement/)
  assert.doesNotMatch(canvasEditorSource, /querySelectorAll\('img'\)/)
  assert.doesNotMatch(canvasEditorSource, /window\.localStorage\.getItem/)
  assert.doesNotMatch(canvasEditorSource, /movscript\.canvasDebug/)
})

test('canvas text node card layout is keyed by explicit content mode', () => {
  const nodeCardSource = readFileSync(resolve('../../packages/ui/src/components/business/canvas/card/node/core/index.tsx'), 'utf8')
  const nodeCardStyles = readFileSync(resolve('../../packages/ui/src/components/business/canvas/card/node/core/styles.css'), 'utf8')

  assert.match(nodeCardSource, /contentMode\?: "text"/)
  assert.match(nodeCardSource, /data-content-mode=\{contentMode\}/)
  assert.match(nodeCardSource, /<CanvasNodeCard selected=\{selected\} contentMode="text">/)
  assert.match(nodeCardStyles, /\.canvas-node-card\[data-content-mode="text"\]/)
  assert.doesNotMatch(nodeCardStyles, /\.canvas-node-card:has\(\.canvas-node-card-(textarea|preview-text)\)/)
})
