import { useCallback, useEffect, useRef, useState } from 'react';
import { AppShell } from '@add-ideas/toolbox-shell-react';
import '@add-ideas/toolbox-shell-react/styles.css';
import './index.css';

import {
  createAsset,
  type ImportedMediaAsset,
  type WorkspaceMode,
} from './app/application-state';
import { AppErrorBoundary } from './app/AppErrorBoundary';
import {
  SourceInspectionRegistry,
  type SourceInspectionToken,
} from './app/source-inspection-registry';
import { FileDropZone } from './components/FileDropZone';
import { MediaBin } from './components/MediaBin';
import {
  MediaPreview,
  type PreviewProxySettings,
} from './components/MediaPreview';
import {
  QuickConvert,
  type QuickExportConfiguration,
} from './components/QuickConvert';
import { CapabilityPanel } from './components/CapabilityPanel';
import { JobPanel } from './components/JobPanel';
import { StoragePanel } from './components/StoragePanel';
import { HelpDialog } from './components/HelpDialog';
import { Icon } from './components/Icon';
import { Timeline } from './components/Timeline';
import {
  AdvancedOperations,
  type AdvancedAudioRequest,
  type AdvancedCapabilityKey,
  type AdvancedCapabilityStatus,
  type AdvancedExportPresetOption,
  type AdvancedSplitBatchStatus,
  type AdvancedSplitRequest,
  type ChapterExecutionRequest,
  type ContactSheetRequest,
  type MetadataExecutionRequest,
  type SubtitleExecutionRequest,
  type ThumbnailSeriesRequest,
  type UserPresetAction,
} from './components/AdvancedOperations';
import {
  StructuralOperations,
  type StructuralCompatibilityDiagnostic,
  type StructuralConcatRequest,
  type StructuralTrimRequest,
} from './components/StructuralOperations';
import { Inspector, type ThumbnailRequest } from './components/Inspector';
import { engineManager } from './ffmpeg/EngineManager';
import type {
  EngineJobContext,
  EnginePreference,
  EngineState,
} from './ffmpeg/ffmpeg.types';
import { EngineError } from './ffmpeg/ffmpeg-error';
import { normalizeFfprobeReport } from './media';
import {
  createEmptyProject,
  importProjectDocument,
  projectDocumentFileName,
  projectReducer,
  rankReattachmentCandidates,
  serializeProject,
  type AvProjectV1,
  type MediaAssetReference,
  type OutputSettings,
  type ProjectAction,
  type TimelineClip,
} from './project';
import type { FFmpegCommandPlan } from './commands/command-plan';
import {
  buildConvertPlan,
  requirementsForUserPreset,
} from './commands/convert';
import { buildRemuxPlan, type RemuxStream } from './commands/remux';
import { buildSingleThumbnailPlan } from './commands/thumbnails';
import { buildPreviewProxyPlan } from './commands/preview-proxy';
import { buildTimelineExportPlan } from './commands/timeline-export';
import {
  buildContactSheetPlan,
  buildSceneChangeAnalysisPlan,
  buildSceneThumbnailSeriesPlan,
  buildThumbnailSeriesPlan,
  parseSceneChangeFrames,
} from './commands/thumbnails';
import { buildSplitPlan } from './commands/split';
import { buildTrimPlan } from './commands/trim';
import {
  buildFastConcatPlan,
  buildNormalizedConcatPlan,
  validateConcatCompatibility,
  type ConcatSource,
} from './commands/concatenate';
import {
  buildStaticWaveformPlan,
  buildWaveformAnalysisPlan,
} from './commands/waveform';
import {
  buildLoudnessAnalysisPlan,
  buildLoudnessApplyPlan,
  buildPeakAnalysisPlan,
  buildPeakNormalizationPlan,
  parseLoudnessMeasurement,
  parsePeakMeasurement,
  type LoudnessMeasurement,
} from './commands/loudness';
import { buildMetadataEditPlan, type MetadataEdits } from './commands/metadata';
import { buildChapterMuxPlan } from './commands/chapters';
import {
  buildSubtitleBurnPlan,
  buildSubtitleConversionPlan,
  buildSubtitleExtractionPlan,
  buildSubtitleMuxPlan,
} from './commands/subtitles';
import { calculateResize, validateCrop } from './commands/transform';
import {
  BUILT_IN_PRESETS,
  findBuiltInPreset,
  presetAvailability,
} from './presets/preset-registry';
import {
  IndexedDbUserPresetPersistence,
  MemoryUserPresetPersistence,
  UserPresetRegistry,
} from './presets/user-presets';
import type { UserExportPreset } from './presets/preset.types';
import {
  collectCommandOutputs,
  createExportReport,
  downloadBlob,
  ExportResultCollection,
  saveCollectionResult,
  saveExportReport,
  saveResultsZip,
  safeExportFileName,
  type ExportReport,
  type ExportResult,
} from './export';
import { manifest } from './toolbox/manifest';
import { cacheDerivative, readCachedDerivative } from './app/derived-cache';
import {
  DEFAULT_RESOURCE_POLICY,
  estimatePlanResources,
  policyForDeviceMemory,
  preflightResources,
  type ResourcePolicy,
} from './storage';
import { assessGeneratedResultPreview, type MediaProbe } from './media';
import {
  createWaveformRuntime,
  deserializeWaveformPeaks,
  serializeWaveformPeaks,
  WAVEFORM_PEAKS_MEDIA_TYPE,
  type WaveformPeakData,
} from './waveform';
import type { MediaJob, MediaJobStep } from './jobs';
import { loadBundledContactSheetFont } from './assets/bundled-font';
import {
  FFMPEG_CORE_VERSION,
  FFMPEG_OPUS_REGRESSION_VERIFIED,
} from './version';

function timestamp(): string {
  return new Date().toISOString();
}

function canPreviewGeneratedResult(
  result: Pick<ExportResult, 'fileName' | 'mimeType'>,
  probe?: MediaProbe
): boolean {
  const element = document.createElement(
    result.mimeType.startsWith('video/') ? 'video' : 'audio'
  );
  return assessGeneratedResultPreview(
    {
      fileName: result.fileName,
      mimeType: result.mimeType,
      ...(probe ? { probe } : {}),
    },
    (mimeType) => element.canPlayType(mimeType)
  ).previewable;
}

interface RuntimeResourceContext {
  readonly deviceMemoryGiB?: number;
  readonly policy: ResourcePolicy;
}

function createRuntimeResourceContext(): RuntimeResourceContext {
  const reportedDeviceMemory =
    typeof globalThis.navigator === 'undefined'
      ? undefined
      : (
          globalThis.navigator as Navigator & {
            readonly deviceMemory?: unknown;
          }
        ).deviceMemory;
  const deviceMemoryGiB =
    typeof reportedDeviceMemory === 'number' &&
    Number.isFinite(reportedDeviceMemory) &&
    reportedDeviceMemory > 0
      ? reportedDeviceMemory
      : undefined;
  return {
    ...(deviceMemoryGiB === undefined ? {} : { deviceMemoryGiB }),
    policy: policyForDeviceMemory(DEFAULT_RESOURCE_POLICY, deviceMemoryGiB),
  };
}

function fileDescriptor(file: File) {
  return {
    name: file.name,
    size: file.size,
    lastModified: file.lastModified,
    mimeType: file.type,
  };
}

function extensionFromName(fileName: string): string {
  const extension = fileName.split('.').at(-1)?.toLowerCase();
  return extension && /^[a-z0-9]{1,10}$/u.test(extension) ? extension : 'mkv';
}

function muxerForExtension(extension: string): string {
  const muxers: Readonly<Record<string, string>> = {
    m4a: 'ipod',
    mkv: 'matroska',
    jpg: 'image2',
    jpeg: 'image2',
    png: 'image2',
  };
  return muxers[extension] ?? extension;
}

function outputWithOptionalNumber(
  output: OutputSettings,
  field: 'width' | 'height' | 'frameRate',
  rawValue: string
): OutputSettings {
  const next = { ...output };
  if (rawValue.trim() === '') {
    delete next[field];
    return next;
  }
  const value = Number(rawValue);
  if (!Number.isFinite(value)) return output;
  if (field === 'frameRate') {
    next.frameRate = Math.min(240, Math.max(0.01, value));
  } else {
    next[field] = Math.min(8192, Math.max(2, Math.round(value / 2) * 2));
  }
  return next;
}

function subtitleCodecForFormat(format: 'srt' | 'vtt' | 'ass'): string {
  return format === 'srt' ? 'subrip' : format === 'vtt' ? 'webvtt' : 'ass';
}

function projectMetadataFromEdits(
  edits: MetadataEdits
): AvProjectV1['metadata'] {
  const format = edits.format ?? {};
  const text = (key: string) => {
    const value = format[key];
    return value === null || value === undefined ? undefined : String(value);
  };
  const known = new Set(['title', 'artist', 'album', 'comment']);
  return {
    ...(text('title') ? { title: text('title') } : {}),
    ...(text('artist') ? { artist: text('artist') } : {}),
    ...(text('album') ? { album: text('album') } : {}),
    ...(text('comment') ? { comment: text('comment') } : {}),
    custom: Object.fromEntries(
      Object.entries(format)
        .filter(([key, value]) => !known.has(key) && value !== null)
        .map(([key, value]) => [key, String(value)])
    ),
  };
}

function metadataEditsFromProject(
  metadata: AvProjectV1['metadata']
): MetadataEdits {
  return {
    format: {
      ...(metadata.title ? { title: metadata.title } : {}),
      ...(metadata.artist ? { artist: metadata.artist } : {}),
      ...(metadata.album ? { album: metadata.album } : {}),
      ...(metadata.comment ? { comment: metadata.comment } : {}),
      ...metadata.custom,
    },
  };
}

function resultAsFile(result: ExportResult): File {
  return new File([result.blob], result.fileName, {
    type: result.mimeType,
    lastModified: Date.now(),
  });
}

function concatSourceForClip(
  clip: TimelineClip,
  asset: ImportedMediaAsset,
  sourceIndex: number
): ConcatSource {
  const durationSeconds = asset.probe?.durationSeconds;
  if (durationSeconds === undefined || durationSeconds <= 0) {
    throw new Error(`Source ${asset.file.name} has no validated duration.`);
  }
  const streams =
    asset.probe?.streams.flatMap((stream) =>
      stream.type === 'video' ||
      stream.type === 'audio' ||
      stream.type === 'subtitle'
        ? [
            {
              kind: stream.type,
              codec: stream.codecName ?? 'unknown',
              ...(stream.width === undefined ? {} : { width: stream.width }),
              ...(stream.height === undefined ? {} : { height: stream.height }),
              ...(stream.pixelFormat === undefined
                ? {}
                : { pixelFormat: stream.pixelFormat }),
              ...(stream.timeBase === undefined
                ? {}
                : { timeBase: stream.timeBase }),
              ...(stream.sampleRate === undefined
                ? {}
                : { sampleRate: stream.sampleRate }),
              ...(stream.channelLayout === undefined
                ? {}
                : { channelLayout: stream.channelLayout }),
            },
          ]
        : []
    ) ?? [];
  return {
    id: clip.id,
    sourceIndex,
    fileName: asset.file.name,
    durationSeconds,
    sourceInSeconds: clip.sourceInSeconds,
    sourceOutSeconds: clip.sourceOutSeconds,
    streams,
  };
}

function remuxStreamsFromProbe(probe: MediaProbe): readonly RemuxStream[] {
  return probe.streams.flatMap((stream) =>
    stream.type === 'video' ||
    stream.type === 'audio' ||
    stream.type === 'subtitle' ||
    stream.type === 'attachment' ||
    stream.type === 'data'
      ? [
          {
            index: stream.index,
            kind: stream.type,
            codec: stream.codecName ?? 'unknown',
          },
        ]
      : []
  );
}

function createPresetRegistry(): {
  readonly registry: UserPresetRegistry;
  readonly persistent: boolean;
} {
  try {
    return {
      registry: new UserPresetRegistry(new IndexedDbUserPresetPersistence()),
      persistent: true,
    };
  } catch {
    return {
      registry: new UserPresetRegistry(new MemoryUserPresetPersistence()),
      persistent: false,
    };
  }
}

function replaceVirtualPaths(
  plan: FFmpegCommandPlan,
  context: EngineJobContext
): readonly string[] {
  const replacements = new Map<string, string>();
  plan.inputs.forEach((input, index) => {
    const actual = context.inputPaths[index];
    if (actual) replacements.set(input.path, actual);
  });
  plan.outputs.forEach((output, index) => {
    const actual = context.outputPaths[index];
    if (actual) replacements.set(output.path, actual);
  });
  plan.temporaryFiles.forEach((temporary, index) => {
    const actual = context.temporaryPaths[index];
    if (actual) replacements.set(temporary.path, actual);
  });
  return plan.args.map((argument) =>
    [...replacements].reduce(
      (resolved, [virtualPath, actualPath]) =>
        resolved.replaceAll(virtualPath, actualPath),
      argument
    )
  );
}

function replaceTemporaryContentPaths(
  content: string | Uint8Array,
  plan: FFmpegCommandPlan,
  context: EngineJobContext
): string | Uint8Array {
  if (typeof content !== 'string') return content;
  const replacements = new Map<string, string>();
  plan.inputs.forEach((input, index) => {
    const actual = context.inputPaths[index];
    if (actual) replacements.set(input.path, actual);
  });
  plan.outputs.forEach((output, index) => {
    const actual = context.outputPaths[index];
    if (actual) replacements.set(output.path, actual);
  });
  plan.temporaryFiles.forEach((temporary, index) => {
    const actual = context.temporaryPaths[index];
    if (actual) replacements.set(temporary.path, actual);
  });
  return [...replacements].reduce(
    (resolved, [virtualPath, actualPath]) =>
      resolved.replaceAll(virtualPath, actualPath),
    content
  );
}

export interface OutputVerification {
  readonly probe?: MediaProbe;
  readonly warning?: string;
}

interface PlanExecution {
  readonly results: readonly ExportResult[];
  readonly logText: string;
  readonly verifications?: Readonly<Record<string, OutputVerification>>;
  readonly report?: ExportReport;
}

type ExecutePlan = (
  plan: FFmpegCommandPlan,
  inputs: readonly File[],
  operation: string,
  onStage?: (stage: 'reading-output') => void
) => Promise<PlanExecution>;

interface ScheduledWorkDefinition {
  readonly operation: string;
  readonly projectId: string;
  readonly totalSteps: number;
  readonly retryCount: number;
  readonly work: (executeStep: ExecutePlan) => Promise<unknown>;
  cancelled: boolean;
  counted: boolean;
  started: boolean;
}

function createQueuedJob(
  id: string,
  operation: string,
  totalSteps: number,
  createdAt: string,
  retryCount: number
): MediaJob {
  return {
    id,
    operation,
    status: 'queued',
    steps: Array.from({ length: totalSteps }, (_, index) => ({
      id: `${id}:step-${index + 1}`,
      name: totalSteps === 1 ? operation : `Step ${index + 1}`,
      weight: 1 / totalSteps,
      status: 'queued',
      progress: 0,
      planId: 'pending',
    })),
    progress: 0,
    createdAt,
    updatedAt: createdAt,
    retryCount,
  };
}

function replaceJob(
  jobs: readonly MediaJob[],
  id: string,
  update: (job: MediaJob) => MediaJob
): readonly MediaJob[] {
  return jobs.map((job) => (job.id === id ? update(job) : job));
}

export function AvToolsApplication() {
  const [mode, setMode] = useState<WorkspaceMode>('quick-convert');
  const [assets, setAssets] = useState<ImportedMediaAsset[]>([]);
  const [selectedAssetId, setSelectedAssetId] = useState<string>();
  const [selectedClipId, setSelectedClipId] = useState<string>();
  const [project, setProject] = useState<AvProjectV1>(() =>
    createEmptyProject()
  );
  const [subtitleFiles, setSubtitleFiles] = useState<ReadonlyMap<string, File>>(
    () => new Map()
  );
  const [waveformByAsset, setWaveformByAsset] = useState<
    Readonly<Record<string, WaveformPeakData>>
  >({});
  const [splitMarkersByAsset, setSplitMarkersByAsset] = useState<
    Readonly<Record<string, readonly number[]>>
  >({});
  const [splitBatch, setSplitBatch] = useState<AdvancedSplitBatchStatus>();
  const [loudnessByAsset, setLoudnessByAsset] = useState<
    Readonly<Record<string, LoudnessMeasurement>>
  >({});
  const [waveformProgress, setWaveformProgress] = useState<number>();
  const [playheadByAsset, setPlayheadByAsset] = useState<
    Readonly<Record<string, number>>
  >({});
  const [previewProxySettings, setPreviewProxySettings] =
    useState<PreviewProxySettings>({
      maxDurationSeconds: 30,
      maxWidth: 960,
    });
  const [presetSetup] = useState(createPresetRegistry);
  const [userPresets, setUserPresets] = useState<readonly UserExportPreset[]>(
    []
  );
  const [waveformRuntime] = useState(createWaveformRuntime);
  const [engineState, setEngineState] = useState<EngineState>(
    engineManager.state
  );
  const [enginePreference, setEnginePreference] =
    useState<EnginePreference>('automatic');
  const [resourceContext] = useState(createRuntimeResourceContext);
  const [logs, setLogs] = useState<string[]>([]);
  const [resultCollection] = useState(() => new ExportResultCollection());
  const [results, setResults] = useState<readonly ExportResult[]>([]);
  const [previewResultId, setPreviewResultId] = useState<string>();
  const [outputVerifications, setOutputVerifications] = useState<
    Readonly<Record<string, OutputVerification>>
  >({});
  const [latestReport, setLatestReport] = useState<ExportReport>();
  const [operationError, setOperationError] = useState<string>();
  const [projectNotice, setProjectNotice] = useState<string>();
  const [sourceProbeBusy, setSourceProbeBusy] = useState(false);
  const [scheduledPlanCount, setScheduledPlanCount] = useState(0);
  const [scheduledJobs, setScheduledJobs] = useState<readonly MediaJob[]>([]);
  const [editDrawer, setEditDrawer] = useState<
    'media' | 'inspector' | undefined
  >();
  const projectInput = useRef<HTMLInputElement>(null);
  const mediaDrawerTrigger = useRef<HTMLButtonElement>(null);
  const inspectorDrawerTrigger = useRef<HTMLButtonElement>(null);
  const assetsRef = useRef(assets);
  const projectRef = useRef(project);
  const sourceProbeTail = useRef<Promise<void>>(Promise.resolve());
  const sourceProbePendingRef = useRef(0);
  const sourceInspectionRegistry = useRef(new SourceInspectionRegistry());
  const planExecutionTail = useRef<Promise<void>>(Promise.resolve());
  const scheduledPlanCountRef = useRef(0);
  const scheduledWorkRef = useRef(new Map<string, ScheduledWorkDefinition>());
  const activeScheduledJobIdRef = useRef<string | undefined>(undefined);
  const activeScheduledStepIndexRef = useRef<number | undefined>(undefined);

  useEffect(() => {
    assetsRef.current = assets;
  }, [assets]);

  useEffect(() => {
    projectRef.current = project;
  }, [project]);

  useEffect(() => {
    const activeJobId = activeScheduledJobIdRef.current;
    const activeStepIndex = activeScheduledStepIndexRef.current;
    if (
      !activeJobId ||
      activeStepIndex === undefined ||
      engineState.status !== 'running' ||
      engineState.progress === undefined
    ) {
      return;
    }
    setScheduledJobs((current) =>
      replaceJob(current, activeJobId, (job) => {
        const steps = job.steps.map((step, index) =>
          index === activeStepIndex
            ? {
                ...step,
                progress: Math.min(
                  0.99,
                  Math.max(0, engineState.progress ?? 0)
                ),
              }
            : step
        );
        const progress = Math.min(
          0.99,
          steps.reduce(
            (sum, step) =>
              sum +
              step.weight * (step.status === 'completed' ? 1 : step.progress),
            0
          )
        );
        return {
          ...job,
          status: 'running',
          steps,
          progress,
          updatedAt: timestamp(),
        };
      })
    );
  }, [engineState]);

  useEffect(() => {
    const activeJobId = activeScheduledJobIdRef.current;
    if (!activeJobId) return;
    const status =
      engineState.status === 'recovering'
        ? ('recovering' as const)
        : engineState.status === 'loading'
          ? ('preparing' as const)
          : undefined;
    if (!status) return;
    setScheduledJobs((current) =>
      replaceJob(current, activeJobId, (job) => ({
        ...job,
        status,
        updatedAt: timestamp(),
      }))
    );
  }, [engineState.status]);

  const closeEditDrawer = useCallback(() => {
    const closing = editDrawer;
    setEditDrawer(undefined);
    globalThis.queueMicrotask(() => {
      (closing === 'media'
        ? mediaDrawerTrigger.current
        : inspectorDrawerTrigger.current
      )?.focus();
    });
  }, [editDrawer]);

  const selectWorkspaceMode = useCallback((nextMode: WorkspaceMode) => {
    setEditDrawer(undefined);
    setMode(nextMode);
  }, []);

  useEffect(() => {
    if (!editDrawer) return;
    const closeOnEscape = (event: KeyboardEvent) => {
      if (event.key === 'Escape') {
        event.preventDefault();
        closeEditDrawer();
      }
    };
    globalThis.addEventListener('keydown', closeOnEscape);
    const closeButton = document.querySelector<HTMLButtonElement>(
      editDrawer === 'media'
        ? '#edit-media-drawer .mobile-edit-drawer__close'
        : '#edit-inspector-drawer .mobile-edit-drawer__close'
    );
    closeButton?.focus();
    return () => globalThis.removeEventListener('keydown', closeOnEscape);
  }, [closeEditDrawer, editDrawer]);

  useEffect(
    () =>
      engineManager.subscribe((state) => {
        setEngineState(state);
      }),
    []
  );

  useEffect(() => {
    let active = true;
    void presetSetup.registry
      .initialize()
      .then(() => {
        if (active) setUserPresets(presetSetup.registry.list());
      })
      .catch((error: unknown) => {
        if (active) {
          setProjectNotice(
            error instanceof Error
              ? `User presets could not be loaded: ${error.message}`
              : 'User presets could not be loaded.'
          );
        }
      });
    return () => {
      active = false;
    };
  }, [presetSetup]);

  useEffect(
    () =>
      engineManager.onLog(({ message }) => {
        setLogs((current) => [...current.slice(-399), message]);
      }),
    []
  );

  useEffect(() => {
    const inspectionRegistry = sourceInspectionRegistry.current;
    return () => {
      const cancelActiveInspection = inspectionRegistry.clear();
      if (cancelActiveInspection) void engineManager.cancelActive();
      for (const asset of assetsRef.current) {
        URL.revokeObjectURL(asset.objectUrl);
      }
      resultCollection.dispose();
      waveformRuntime.terminate();
    };
  }, [resultCollection, waveformRuntime]);

  const applyProjectAction = useCallback((action: ProjectAction) => {
    setProject((current) => projectReducer(current, action));
  }, []);

  const updateAssetState = useCallback(
    (id: string, changes: Partial<ImportedMediaAsset>) => {
      setAssets((current) =>
        current.map((asset) =>
          asset.id === id ? { ...asset, ...changes } : asset
        )
      );
    },
    []
  );

  const runSourceProbe = useCallback(
    <T,>(probe: () => Promise<T>): Promise<T> => {
      sourceProbePendingRef.current += 1;
      setSourceProbeBusy(true);
      const execution = sourceProbeTail.current.then(probe, probe);
      sourceProbeTail.current = execution.then(
        () => undefined,
        () => undefined
      );
      void execution
        .finally(() => {
          sourceProbePendingRef.current = Math.max(
            0,
            sourceProbePendingRef.current - 1
          );
          setSourceProbeBusy(sourceProbePendingRef.current > 0);
        })
        .catch(() => undefined);
      return execution;
    },
    []
  );

  const inspectAsset = useCallback(
    async (
      asset: ImportedMediaAsset,
      existingAsset: boolean,
      token: SourceInspectionToken
    ) => {
      if (!sourceInspectionRegistry.current.isCurrent(token)) return;
      updateAssetState(asset.id, {
        phase: 'probing',
        error: undefined,
      });
      try {
        const probeResult = await runSourceProbe(async () => {
          if (!sourceInspectionRegistry.current.activate(token)) {
            return undefined;
          }
          try {
            return await engineManager.probe(
              asset.file,
              undefined,
              token.signal
            );
          } finally {
            sourceInspectionRegistry.current.finish(token);
          }
        });
        if (
          !probeResult ||
          !sourceInspectionRegistry.current.isCurrent(token)
        ) {
          return;
        }
        const probe = normalizeFfprobeReport(probeResult.json);
        const rawProbe = `${JSON.stringify(probeResult.json, null, 2)}\n`;
        const importedChapters = probe.chapters.map((chapter) => ({
          id: `${asset.id}-chapter-${chapter.id}`,
          startSeconds: chapter.startSeconds,
          endSeconds: chapter.endSeconds,
          title: chapter.title ?? `Chapter ${chapter.id + 1}`,
          ...(chapter.timeBase ? { timeBase: chapter.timeBase } : {}),
          ...(Object.keys(chapter.tags).length > 0
            ? { metadata: chapter.tags }
            : {}),
        }));
        if (!sourceInspectionRegistry.current.isCurrent(token)) return;
        updateAssetState(asset.id, { phase: 'ready', probe, rawProbe });
        setProject((current) => {
          if (
            !sourceInspectionRegistry.current.isCurrent(token) ||
            !current.assets.some((entry) => entry.id === asset.id)
          ) {
            return current;
          }
          let next = projectReducer(current, {
            type: 'asset/update',
            assetId: asset.id,
            changes: { probe, mimeType: asset.file.type },
            updatedAt: timestamp(),
          });
          if (
            existingAsset &&
            next.assets.find((entry) => entry.id === asset.id)?.sourceStatus ===
              'missing'
          ) {
            next = projectReducer(next, {
              type: 'asset/set-source-status',
              assetId: asset.id,
              sourceStatus: 'attached',
              updatedAt: timestamp(),
            });
          }
          const hasClip = next.timeline.some(
            (clip) => clip.assetId === asset.id
          );
          if (
            !hasClip &&
            probe.durationSeconds !== undefined &&
            probe.durationSeconds >= 0.001
          ) {
            next = projectReducer(next, {
              type: 'clip/add',
              clip: {
                id: crypto.randomUUID(),
                assetId: asset.id,
                sourceInSeconds: 0,
                sourceOutSeconds: probe.durationSeconds,
                audio: { enabled: true },
                video: { enabled: true },
              },
              updatedAt: timestamp(),
            });
          }
          if (next.chapters.length === 0 && importedChapters.length > 0) {
            next = projectReducer(next, {
              type: 'chapters/set',
              chapters: importedChapters,
              updatedAt: timestamp(),
            });
          }
          return next;
        });
      } catch (error) {
        if (!sourceInspectionRegistry.current.isCurrent(token)) return;
        updateAssetState(asset.id, {
          phase: 'error',
          error:
            error instanceof Error
              ? error.message
              : 'The file could not be inspected.',
        });
      }
    },
    [runSourceProbe, updateAssetState]
  );

  const addFiles = useCallback(
    async (files: File[]) => {
      setOperationError(undefined);
      setProjectNotice(undefined);
      if (
        scheduledPlanCountRef.current > 0 ||
        (engineManager.state.status === 'running' &&
          sourceProbePendingRef.current === 0)
      ) {
        setOperationError(
          'Wait for the active export or analysis job before importing media.'
        );
        return;
      }
      const importDecision = preflightResources(
        {
          inputBytes: [
            ...assetsRef.current.map((asset) => asset.file.size),
            ...files.map((file) => file.size),
          ],
        },
        resourceContext.policy
      );
      if (importDecision.status === 'blocked') {
        setOperationError(
          importDecision.issues
            .map((issue) => `${issue.message} ${issue.suggestions.join(' / ')}`)
            .join(' ')
        );
        return;
      }
      if (
        importDecision.status === 'warning' &&
        !globalThis.confirm(
          `${importDecision.issues
            .map((issue) => issue.message)
            .join(
              '\n'
            )}\n\n${importDecision.estimateDisclaimer}\n\nImport and inspect anyway?`
        )
      ) {
        return;
      }
      const pending: Array<{
        asset: ImportedMediaAsset;
        existingAsset: boolean;
        token: SourceInspectionToken;
      }> = [];
      const claimedIds = new Set(assetsRef.current.map((asset) => asset.id));

      for (const file of files) {
        const candidateMatches = project.assets
          .filter(
            (entry) =>
              entry.sourceStatus === 'missing' && !claimedIds.has(entry.id)
          )
          .map((entry) => ({
            entry,
            match: rankReattachmentCandidates(entry, [fileDescriptor(file)])[0],
          }))
          .filter(
            (
              value
            ): value is {
              entry: MediaAssetReference;
              match: NonNullable<(typeof value)['match']>;
            } => value.match?.confidence !== 'none'
          )
          .sort((left, right) => right.match.score - left.match.score);

        const match = candidateMatches[0];
        const reattach =
          match !== undefined &&
          globalThis.confirm(
            `Reattach “${file.name}” to the missing project source “${match.entry.originalName}”?\n\n${match.match.evidence
              .map((evidence) => evidence.message)
              .join(' ')}`
          );
        const asset = createAsset(file);
        if (reattach && match) {
          asset.id = match.entry.id;
          claimedIds.add(match.entry.id);
          pending.push({
            asset,
            existingAsset: true,
            token: sourceInspectionRegistry.current.register(asset.id),
          });
        } else {
          setProject((current) =>
            projectReducer(current, {
              type: 'asset/add',
              asset: {
                id: asset.id,
                originalName: file.name,
                size: file.size,
                lastModified: file.lastModified,
                mimeType: file.type,
                sourceStatus: 'attached',
              },
              updatedAt: timestamp(),
            })
          );
          pending.push({
            asset,
            existingAsset: false,
            token: sourceInspectionRegistry.current.register(asset.id),
          });
        }
      }

      setAssets((current) => {
        const next = [...current, ...pending.map(({ asset }) => asset)];
        assetsRef.current = next;
        return next;
      });
      setSelectedAssetId((current) => current ?? pending[0]?.asset.id);
      for (const item of pending) {
        await inspectAsset(item.asset, item.existingAsset, item.token);
      }
    },
    [inspectAsset, project.assets, resourceContext.policy]
  );

  const removeAsset = useCallback(
    (id: string) => {
      const asset = assets.find((entry) => entry.id === id);
      if (asset) URL.revokeObjectURL(asset.objectUrl);
      const cancelActiveInspection =
        sourceInspectionRegistry.current.remove(id);
      setAssets((current) => {
        const next = current.filter((entry) => entry.id !== id);
        assetsRef.current = next;
        return next;
      });
      setWaveformByAsset((current) =>
        Object.fromEntries(
          Object.entries(current).filter(([assetId]) => assetId !== id)
        )
      );
      setSplitMarkersByAsset((current) =>
        Object.fromEntries(
          Object.entries(current).filter(([assetId]) => assetId !== id)
        )
      );
      setLoudnessByAsset((current) =>
        Object.fromEntries(
          Object.entries(current).filter(([assetId]) => assetId !== id)
        )
      );
      setPlayheadByAsset((current) =>
        Object.fromEntries(
          Object.entries(current).filter(([assetId]) => assetId !== id)
        )
      );
      if (selectedAssetId === id) {
        setSelectedAssetId(assets.find((entry) => entry.id !== id)?.id);
      }
      applyProjectAction({
        type: 'asset/remove',
        assetId: id,
        updatedAt: timestamp(),
      });
      if (cancelActiveInspection) void engineManager.cancelActive();
    },
    [applyProjectAction, assets, selectedAssetId]
  );

  const selectedAsset = assets.find((asset) => asset.id === selectedAssetId);
  const selectedClip = project.timeline.find(
    (clip) => clip.id === selectedClipId
  );
  const inspectedClipAsset = selectedClip
    ? assets.find((asset) => asset.id === selectedClip.assetId)
    : selectedAsset;
  const previewOutput = results.find((entry) => entry.id === previewResultId);
  const previewProbe = previewOutput
    ? outputVerifications[previewOutput.id]?.probe
    : undefined;
  const previewResult = previewOutput
    ? {
        name: previewOutput.fileName,
        mimeType: previewOutput.mimeType,
        objectUrl: resultCollection.objectUrl(previewOutput.id),
        ...(previewProbe ? { probe: previewProbe } : {}),
      }
    : undefined;

  const refreshResults = useCallback(() => {
    const current = resultCollection.list();
    setResults(current);
    setPreviewResultId((selected) =>
      selected && current.some((entry) => entry.id === selected)
        ? selected
        : current.find((entry) => canPreviewGeneratedResult(entry))?.id
    );
  }, [resultCollection]);

  const clearResult = useCallback(() => {
    resultCollection.clear();
    setResults([]);
    setPreviewResultId(undefined);
    setOutputVerifications({});
    setLatestReport(undefined);
  }, [resultCollection]);

  const executePlan = useCallback(
    async (
      plan: FFmpegCommandPlan,
      inputs: readonly File[],
      operation: string,
      onStage?: (stage: 'reading-output') => void
    ): Promise<PlanExecution> => {
      if (
        plan.diagnostics.some((diagnostic) => diagnostic.severity === 'error')
      ) {
        throw new Error(
          plan.diagnostics
            .filter((diagnostic) => diagnostic.severity === 'error')
            .map((diagnostic) => diagnostic.message)
            .join(' ')
        );
      }
      if (sourceProbePendingRef.current > 0) {
        throw new EngineError(
          'busy',
          'Wait for media inspection to finish before starting an export.'
        );
      }
      const resourceSources = inputs.map((file) => {
        const asset = assetsRef.current.find((entry) => entry.file === file);
        return {
          size: file.size,
          ...(asset?.probe ? { probe: asset.probe } : {}),
        };
      });
      const resourceDecision = preflightResources(
        {
          inputBytes: resourceSources.map((source) => source.size),
          ...estimatePlanResources(plan, resourceSources),
          retainedOutputs: resultCollection.size,
          streamsPerInput: resourceSources.map(
            (source) => source.probe?.streams.length ?? 0
          ),
        },
        resourceContext.policy
      );
      if (resourceDecision.status === 'blocked') {
        throw new Error(
          resourceDecision.issues
            .map((issue) => `${issue.message} ${issue.suggestions.join(' / ')}`)
            .join(' ')
        );
      }
      if (
        resourceDecision.status === 'warning' &&
        !globalThis.confirm(
          `${resourceDecision.issues
            .map((issue) => issue.message)
            .join('\n')}\n\n${resourceDecision.estimateDisclaimer}\n\nContinue?`
        )
      ) {
        throw new EngineError('cancelled', 'The operation was not started.');
      }
      setOperationError(undefined);
      setLogs([]);
      await engineManager.initialize();
      const readyState = engineManager.state;
      if (readyState.status !== 'ready') {
        throw new Error('The local FFmpeg engine did not become ready.');
      }
      const missing = (
        [
          ['muxers', plan.requiredCapabilities.muxers],
          ['encoders', plan.requiredCapabilities.encoders],
          ['decoders', plan.requiredCapabilities.decoders],
          ['filters', plan.requiredCapabilities.filters],
        ] as const
      ).flatMap(([kind, required]) =>
        (required ?? [])
          .filter((name) => !readyState.capabilities[kind].has(name))
          .map((name) => `${kind.slice(0, -1)} ${name}`)
      );
      if (missing.length > 0) {
        throw new Error(
          `The pinned FFmpeg core is missing required capabilities: ${missing.join(', ')}.`
        );
      }
      const completed = await engineManager.runJob({
        id: plan.id.split(':')[0] ?? crypto.randomUUID(),
        operation,
        coreWorkload: plan.operation,
        inputs,
        temporaryFiles: plan.temporaryFiles.map((temporary) => ({
          name: temporary.path.split('/').at(-1) ?? 'temporary.dat',
          content: (context: EngineJobContext) =>
            replaceTemporaryContentPaths(temporary.content, plan, context),
        })),
        outputs: plan.outputs.map((output) => ({
          name: output.fileName,
          mimeType: output.mediaType,
        })),
        expectedDurationSeconds: plan.expectedDurationSeconds,
        timeoutMilliseconds: plan.timeoutMs,
        buildArguments: (context) => replaceVirtualPaths(plan, context),
      });
      onStage?.('reading-output');
      const logText = completed.logs.map((entry) => entry.message).join('\n');
      if (plan.outputs.length === 0) {
        return { results: [], logText };
      }
      const outputMap = new Map(
        completed.outputs.flatMap((output, index) => {
          const planned = plan.outputs[index];
          return planned
            ? ([[planned.id, Uint8Array.from(output.bytes)] as const] as const)
            : [];
        })
      );
      const collected = collectCommandOutputs(
        plan,
        outputMap,
        resultCollection
      );
      const verifications: Record<string, OutputVerification> = {};
      const probeLimit = 8;
      for (const [index, output] of collected.entries()) {
        if (
          !output.mimeType.startsWith('video/') &&
          !output.mimeType.startsWith('audio/')
        ) {
          continue;
        }
        if (index >= probeLimit) {
          verifications[output.id] = {
            warning:
              'This batch item was not re-probed because output verification is bounded to the first eight results.',
          };
          continue;
        }
        try {
          const probeResult = await engineManager.probe(
            new File([output.blob], output.fileName, {
              type: output.mimeType,
              lastModified: Date.now(),
            })
          );
          verifications[output.id] = {
            probe: normalizeFfprobeReport(probeResult.json),
          };
        } catch (error) {
          verifications[output.id] = {
            warning:
              error instanceof Error
                ? `Output was created, but its verification probe failed: ${error.message}`
                : 'Output was created, but its verification probe failed.',
          };
        }
      }
      setOutputVerifications((current) => ({
        ...current,
        ...verifications,
      }));
      const readyStateAfterRun = engineManager.state;
      const report = createExportReport({
        plan,
        results: collected,
        execution: {
          status: 'completed',
          exitCode: completed.exitCode,
          elapsedSeconds:
            (completed.timings.conversionMilliseconds +
              completed.timings.outputReadMilliseconds +
              completed.timings.cleanupMilliseconds) /
            1_000,
          conversionMilliseconds: completed.timings.conversionMilliseconds,
          outputReadMilliseconds: completed.timings.outputReadMilliseconds,
          cleanupMilliseconds: completed.timings.cleanupMilliseconds,
          ...(readyStateAfterRun.status === 'ready'
            ? {
                engineMode:
                  readyStateAfterRun.mode === 'multithread'
                    ? ('multi-thread' as const)
                    : ('single-thread' as const),
                ffmpegVersion: readyStateAfterRun.capabilities.versionText,
                coreVersion: FFMPEG_CORE_VERSION,
              }
            : {}),
        },
        diagnostics: Object.values(verifications).flatMap((verification) =>
          verification.warning
            ? [
                {
                  code: 'output-probe-failed',
                  severity: 'warning' as const,
                  message: verification.warning,
                },
              ]
            : []
        ),
      });
      setLatestReport(report);
      refreshResults();
      setPreviewResultId(
        collected.find((entry) =>
          canPreviewGeneratedResult(entry, verifications[entry.id]?.probe)
        )?.id
      );
      return { results: collected, logText, verifications, report };
    },
    [refreshResults, resourceContext.policy, resultCollection]
  );

  const enqueueWork = useCallback(
    <T,>(
      operation: string,
      totalSteps: number,
      work: (executeStep: ExecutePlan) => Promise<T>,
      retryCount = 0
    ): Promise<T> => {
      if (sourceProbePendingRef.current > 0) {
        return Promise.reject(
          new EngineError(
            'busy',
            'Wait for media inspection to finish before adding an export.'
          )
        );
      }
      if (scheduledPlanCountRef.current >= 8) {
        return Promise.reject(
          new EngineError(
            'busy',
            'The local queue already contains eight operations. Wait for one to finish or cancel a waiting job.'
          )
        );
      }
      const id = crypto.randomUUID();
      const createdAt = timestamp();
      const definition: ScheduledWorkDefinition = {
        operation,
        projectId: projectRef.current.id,
        totalSteps: Math.max(1, Math.floor(totalSteps)),
        retryCount,
        work: work as (executeStep: ExecutePlan) => Promise<unknown>,
        cancelled: false,
        counted: true,
        started: false,
      };
      scheduledWorkRef.current.set(id, definition);
      setScheduledJobs((current) => {
        const retained = current.slice(-23);
        const retainedIds = new Set(retained.map((job) => job.id));
        for (const job of current) {
          if (!retainedIds.has(job.id)) {
            scheduledWorkRef.current.delete(job.id);
          }
        }
        return [
          ...retained,
          createQueuedJob(
            id,
            operation,
            definition.totalSteps,
            createdAt,
            definition.retryCount
          ),
        ];
      });
      scheduledPlanCountRef.current += 1;
      setScheduledPlanCount(scheduledPlanCountRef.current);

      const start = async (): Promise<T> => {
        definition.started = true;
        activeScheduledJobIdRef.current = id;
        if (definition.cancelled) {
          activeScheduledJobIdRef.current = undefined;
          throw new EngineError('cancelled', 'The queued job was cancelled.');
        }
        setScheduledJobs((current) =>
          replaceJob(current, id, (job) => ({
            ...job,
            status: 'preparing',
            startedAt: timestamp(),
            updatedAt: timestamp(),
          }))
        );
        let stepIndex = 0;
        const executeTrackedStep: ExecutePlan = async (
          plan,
          inputs,
          stepOperation
        ) => {
          const currentStepIndex = stepIndex;
          stepIndex += 1;
          activeScheduledStepIndexRef.current = currentStepIndex;
          setScheduledJobs((current) =>
            replaceJob(current, id, (job) => {
              const steps = [...job.steps];
              const existing = steps[currentStepIndex];
              const nextStep: MediaJobStep = {
                id: existing?.id ?? `${id}:step-${currentStepIndex + 1}`,
                name: stepOperation,
                weight: existing?.weight ?? 1 / definition.totalSteps,
                status: 'running',
                progress: 0,
                planId: plan.id,
              };
              steps[currentStepIndex] = nextStep;
              return {
                ...job,
                status: 'running',
                steps,
                updatedAt: timestamp(),
              };
            })
          );
          try {
            const result = await executePlan(
              plan,
              inputs,
              stepOperation,
              () => {
                setScheduledJobs((current) =>
                  replaceJob(current, id, (job) => ({
                    ...job,
                    status: 'reading-output',
                    updatedAt: timestamp(),
                  }))
                );
              }
            );
            setScheduledJobs((current) =>
              replaceJob(current, id, (job) => {
                const steps = job.steps.map((step, index) =>
                  index === currentStepIndex
                    ? { ...step, status: 'completed' as const, progress: 1 }
                    : step
                );
                return {
                  ...job,
                  steps,
                  progress: Math.min(
                    0.99,
                    steps.reduce(
                      (sum, step) =>
                        sum +
                        step.weight *
                          (step.status === 'completed' ? 1 : step.progress),
                      0
                    )
                  ),
                  updatedAt: timestamp(),
                };
              })
            );
            return result;
          } catch (error) {
            const cancelled =
              definition.cancelled ||
              (error instanceof EngineError && error.code === 'cancelled');
            setScheduledJobs((current) =>
              replaceJob(current, id, (job) => ({
                ...job,
                steps: job.steps.map((step, index) =>
                  index === currentStepIndex
                    ? {
                        ...step,
                        status: cancelled
                          ? ('cancelled' as const)
                          : ('failed' as const),
                        progress: Math.min(step.progress, 0.99),
                      }
                    : step
                ),
                updatedAt: timestamp(),
              }))
            );
            throw error;
          }
        };

        try {
          const result = await work(executeTrackedStep);
          setScheduledJobs((current) =>
            replaceJob(current, id, (job) => ({
              ...job,
              status: 'completed',
              progress: 1,
              completedAt: timestamp(),
              updatedAt: timestamp(),
            }))
          );
          return result;
        } catch (error) {
          const cancelled =
            definition.cancelled ||
            (error instanceof EngineError && error.code === 'cancelled');
          setScheduledJobs((current) =>
            replaceJob(current, id, (job) => ({
              ...job,
              status: cancelled ? 'cancelled' : 'failed',
              completedAt: timestamp(),
              updatedAt: timestamp(),
              error: cancelled
                ? undefined
                : {
                    code: 'execution-failed',
                    message:
                      error instanceof Error
                        ? error.message
                        : 'The local job failed.',
                    recoverable: true,
                  },
              steps: job.steps.map((step) =>
                step.status === 'queued'
                  ? {
                      ...step,
                      status: cancelled
                        ? ('cancelled' as const)
                        : ('failed' as const),
                    }
                  : step
              ),
            }))
          );
          throw error;
        } finally {
          if (activeScheduledJobIdRef.current === id) {
            activeScheduledJobIdRef.current = undefined;
            activeScheduledStepIndexRef.current = undefined;
          }
        }
      };

      const execution = planExecutionTail.current.then(start, start);
      planExecutionTail.current = execution.then(
        () => undefined,
        () => undefined
      );
      void execution
        .finally(() => {
          if (definition.counted) {
            definition.counted = false;
            scheduledPlanCountRef.current = Math.max(
              0,
              scheduledPlanCountRef.current - 1
            );
            setScheduledPlanCount(scheduledPlanCountRef.current);
          }
        })
        .catch(() => undefined);
      return execution;
    },
    [executePlan]
  );

  const runPlan = useCallback(
    (
      plan: FFmpegCommandPlan,
      inputs: readonly File[],
      operation: string
    ): Promise<PlanExecution> =>
      enqueueWork(operation, 1, (executeStep) =>
        executeStep(plan, inputs, operation)
      ),
    [enqueueWork]
  );

  const runWorkflow = useCallback(
    <T,>(
      operation: string,
      totalSteps: number,
      work: (executeStep: ExecutePlan) => Promise<T>
    ): Promise<T> => enqueueWork(operation, totalSteps, work),
    [enqueueWork]
  );

  const cancelScheduledJob = useCallback(async (id: string) => {
    const definition = scheduledWorkRef.current.get(id);
    if (!definition) return;
    definition.cancelled = true;
    setScheduledJobs((current) =>
      replaceJob(current, id, (job) => ({
        ...job,
        status: job.status === 'queued' ? 'cancelled' : 'cancelling',
        completedAt: job.status === 'queued' ? timestamp() : job.completedAt,
        updatedAt: timestamp(),
        steps: job.steps.map((step) =>
          step.status === 'queued'
            ? { ...step, status: 'cancelled' as const }
            : step
        ),
      }))
    );
    if (!definition.started && definition.counted) {
      definition.counted = false;
      scheduledPlanCountRef.current = Math.max(
        0,
        scheduledPlanCountRef.current - 1
      );
      setScheduledPlanCount(scheduledPlanCountRef.current);
      return;
    }
    if (activeScheduledJobIdRef.current === id) {
      await engineManager.cancelActive();
    }
  }, []);

  const retryScheduledJob = useCallback(
    (id: string) => {
      const definition = scheduledWorkRef.current.get(id);
      if (!definition || definition.projectId !== projectRef.current.id) {
        setOperationError(
          'This job cannot be retried after its project has been replaced.'
        );
        return;
      }
      void enqueueWork(
        definition.operation,
        definition.totalSteps,
        definition.work,
        definition.retryCount + 1
      ).catch(() => undefined);
    },
    [enqueueWork]
  );

  const clearScheduledJobHistory = useCallback(() => {
    setScheduledJobs((current) => {
      const retained = current.filter(
        (job) =>
          job.status !== 'completed' &&
          job.status !== 'failed' &&
          job.status !== 'cancelled'
      );
      const retainedIds = new Set(retained.map((job) => job.id));
      for (const id of scheduledWorkRef.current.keys()) {
        if (!retainedIds.has(id)) scheduledWorkRef.current.delete(id);
      }
      return retained;
    });
  }, []);

  const exportQuick = useCallback(
    async (configuration: QuickExportConfiguration) => {
      if (!selectedAsset?.probe) return;
      const jobId = crypto.randomUUID();
      try {
        let plan: FFmpegCommandPlan;
        if (configuration.operation === 'remux') {
          const container = configuration.remuxContainer ?? 'matroska';
          plan = buildRemuxPlan({
            jobId,
            source: {
              id: selectedAsset.id,
              sourceIndex: 0,
              fileName: selectedAsset.file.name,
            },
            targetContainer: container,
            fileExtension:
              container === 'matroska'
                ? 'mkv'
                : container === 'ogg'
                  ? 'ogg'
                  : container,
            description: {
              streams: selectedAsset.probe.streams.flatMap((stream) =>
                stream.type === 'video' ||
                stream.type === 'audio' ||
                stream.type === 'subtitle' ||
                stream.type === 'attachment' ||
                stream.type === 'data'
                  ? [
                      {
                        index: stream.index,
                        kind: stream.type,
                        codec: stream.codecName ?? 'unknown',
                      },
                    ]
                  : []
              ),
              hasChapters: selectedAsset.probe.chapters.length > 0,
              hasMetadata: Object.keys(selectedAsset.probe.tags).length > 0,
            },
            streamSelection: configuration.streamSelection,
            metadataPolicy: configuration.removeMetadata ? 'remove' : 'copy',
            chapterPolicy: configuration.removeChapters ? 'remove' : 'keep',
            expectedDurationSeconds: selectedAsset.probe.durationSeconds,
          });
        } else {
          if (!configuration.preset) return;
          plan = buildConvertPlan({
            jobId,
            source: {
              id: selectedAsset.id,
              sourceIndex: 0,
              fileName: selectedAsset.file.name,
            },
            preset: {
              ...configuration.preset,
              metadataPolicy: configuration.removeMetadata ? 'remove' : 'copy',
              chapterPolicy: configuration.removeChapters ? 'remove' : 'keep',
            },
            streamSelection: configuration.streamSelection,
            expectedDurationSeconds: selectedAsset.probe.durationSeconds,
          });
        }
        await runPlan(plan, [selectedAsset.file], plan.operation);
      } catch (error) {
        setOperationError(
          error instanceof EngineError && error.code === 'cancelled'
            ? 'The operation was cancelled and the engine was recreated.'
            : error instanceof Error
              ? error.message
              : 'The output could not be generated.'
        );
      }
    },
    [runPlan, selectedAsset]
  );

  const extractThumbnail = useCallback(
    async (request: ThumbnailRequest) => {
      const asset = inspectedClipAsset;
      if (!asset) return;
      try {
        const plan = buildSingleThumbnailPlan({
          jobId: crypto.randomUUID(),
          source: {
            id: asset.id,
            sourceIndex: 0,
            fileName: asset.file.name,
          },
          timeSeconds: request.timeSeconds,
          size: {
            ...(request.width === undefined ? {} : { width: request.width }),
            ...(request.height === undefined ? {} : { height: request.height }),
            maintainAspect: request.maintainAspect,
          },
          format: request.format === 'jpg' ? 'jpeg' : request.format,
          quality: request.quality,
        });
        const execution = await runPlan(
          plan,
          [asset.file],
          'Extract thumbnail'
        );
        const derivative = execution.results[0];
        if (!derivative) {
          throw new Error('The thumbnail output was not returned.');
        }
        try {
          await cacheDerivative(
            asset.file,
            'thumbnail',
            'thumbnail',
            project.id,
            derivative.blob,
            {
              timeSeconds: request.timeSeconds,
              width: request.width,
              height: request.height,
              maintainAspect: request.maintainAspect,
              format: request.format,
              quality: request.quality,
            }
          );
        } catch {
          setProjectNotice(
            'Thumbnail created, but this browser could not cache the derivative.'
          );
        }
      } catch (error) {
        setOperationError(
          error instanceof Error ? error.message : 'Frame extraction failed.'
        );
      }
    },
    [inspectedClipAsset, project.id, runPlan]
  );

  const createPreviewProxy = useCallback(
    async (asset: ImportedMediaAsset | undefined) => {
      const duration = asset?.probe?.durationSeconds;
      if (!asset || duration === undefined || duration <= 0) return;
      try {
        const includeAudio =
          asset.probe?.streams.some((stream) => stream.type === 'audio') ===
          true;
        const hasVideo =
          asset.probe?.streams.some(
            (stream) =>
              stream.type === 'video' &&
              stream.disposition.attached_pic !== true
          ) === true;
        const cacheSettings = {
          ...previewProxySettings,
          includeAudio,
          hasVideo,
        };
        const plan = buildPreviewProxyPlan({
          jobId: crypto.randomUUID(),
          source: {
            id: asset.id,
            sourceIndex: 0,
            fileName: asset.file.name,
          },
          sourceDurationSeconds: duration,
          ...previewProxySettings,
          includeAudio,
          hasVideo,
        });
        let cached: Blob | undefined;
        try {
          cached = await readCachedDerivative(
            asset.file,
            'preview-proxy',
            cacheSettings
          );
        } catch {
          // Cache availability is optional; generation remains the fallback.
        }
        const plannedOutput = plan.outputs[0];
        if (cached && plannedOutput) {
          const cachedResult = resultCollection.add({
            id: `${plan.id}:${plannedOutput.id}:cached`,
            planId: plan.id,
            outputId: plannedOutput.id,
            fileName: plannedOutput.fileName,
            blob: cached,
            mimeType: plannedOutput.mediaType,
            role: plannedOutput.role,
          });
          refreshResults();
          setPreviewResultId(
            canPreviewGeneratedResult(cachedResult)
              ? cachedResult.id
              : undefined
          );
          setOutputVerifications((current) => ({
            ...current,
            [cachedResult.id]: {
              warning:
                'Reused the matching local preview derivative; it was not re-probed in this run.',
            },
          }));
          setProjectNotice('Reused the matching local preview proxy.');
          return;
        }
        const execution = await runPlan(
          plan,
          [asset.file],
          'Create preview proxy'
        );
        const derivative = execution.results[0];
        if (!derivative) {
          throw new Error('The preview proxy output was not returned.');
        }
        try {
          await cacheDerivative(
            asset.file,
            'preview-proxy',
            'preview-proxy',
            project.id,
            derivative.blob,
            cacheSettings
          );
        } catch {
          setProjectNotice(
            'Preview proxy created, but this browser could not cache the derivative.'
          );
        }
      } catch (error) {
        setOperationError(
          error instanceof Error
            ? error.message
            : 'The preview proxy could not be generated.'
        );
      }
    },
    [
      previewProxySettings,
      project.id,
      refreshResults,
      resultCollection,
      runPlan,
    ]
  );

  const exportTimeline = useCallback(async () => {
    const preset =
      findBuiltInPreset(project.output.presetId) ??
      userPresets.find((entry) => entry.id === project.output.presetId);
    if (!preset?.video) {
      setOperationError(
        'Choose an available video preset in the timeline output settings.'
      );
      return;
    }
    const timelineVideoPreset = preset.video;
    if (!['mp4', 'webm', 'matroska'].includes(preset.container)) {
      setOperationError(
        'Timeline export currently supports MP4, WebM, or Matroska video presets.'
      );
      return;
    }
    const timelineContainer = preset.container as 'mp4' | 'webm' | 'matroska';
    try {
      const enabledSubtitleTracks = project.subtitles.filter(
        (entry) => entry.mode !== 'exclude'
      );
      const timelineStepCount =
        2 +
        enabledSubtitleTracks.length +
        enabledSubtitleTracks.filter(
          (entry) => (entry.offsetSeconds ?? 0) !== 0
        ).length +
        (project.chapters.length > 0 ? 1 : 0);
      await runWorkflow(
        'Render timeline project',
        timelineStepCount,
        async (executeStep) => {
          const resolved = project.timeline.map((clip, index) => {
            const asset = assets.find((entry) => entry.id === clip.assetId);
            const video = asset?.probe?.streams.find(
              (stream) =>
                stream.type === 'video' &&
                stream.disposition.attached_pic !== true
            );
            if (!asset || !video || !video.width || !video.height) {
              throw new Error(
                `Clip ${index + 1} has no attached, inspected video source.`
              );
            }
            if (clip.video?.enabled === false) {
              throw new Error(
                `Clip ${index + 1} has video disabled. The sequential video timeline requires video in every clip; use Quick Convert for an audio-only export.`
              );
            }
            const crop = clip.crop
              ? validateCrop({
                  ...clip.crop,
                  sourceWidth: video.width,
                  sourceHeight: video.height,
                  requireEvenDimensions: true,
                })
              : undefined;
            const croppedWidth = crop?.width ?? video.width;
            const croppedHeight = crop?.height ?? video.height;
            const rotationSwapsDimensions =
              clip.rotation === 90 || clip.rotation === 270;
            const resizeSourceWidth = rotationSwapsDimensions
              ? croppedHeight
              : croppedWidth;
            const resizeSourceHeight = rotationSwapsDimensions
              ? croppedWidth
              : croppedHeight;
            const resize = clip.resize
              ? {
                  sourceWidth: resizeSourceWidth,
                  sourceHeight: resizeSourceHeight,
                  width: clip.resize.width,
                  height: clip.resize.height,
                  mode:
                    clip.resize.mode === 'fit'
                      ? ('contain' as const)
                      : clip.resize.mode === 'fill'
                        ? ('cover' as const)
                        : ('stretch' as const),
                  noUpscaling: clip.resize.allowUpscale === false,
                  algorithm: clip.resize.algorithm,
                  paddingColor: clip.resize.paddingColor,
                }
              : undefined;
            const audioNormalization = clip.audio?.normalization
              ? (() => {
                  const measurement = loudnessByAsset[asset.id];
                  if (!measurement) {
                    throw new Error(
                      `Clip ${index + 1} requests two-pass loudness normalization. Measure its source in Advanced operations first.`
                    );
                  }
                  return {
                    mode: 'loudness' as const,
                    targets: {
                      integratedLufs: clip.audio.normalization.targetLufs,
                      truePeakDbtp: clip.audio.normalization.truePeakDb,
                      loudnessRangeLu:
                        clip.audio.normalization.loudnessRangeLufs ?? 11,
                    },
                    measurement,
                  };
                })()
              : undefined;
            const calculatedResize = resize
              ? calculateResize(resize)
              : undefined;
            const targetBoxIsFinal =
              resize !== undefined &&
              resize.width !== undefined &&
              resize.height !== undefined &&
              (resize.mode === 'contain' || resize.mode === 'cover');
            const transformedWidth = targetBoxIsFinal
              ? (resize.width as number)
              : (calculatedResize?.width ?? resizeSourceWidth);
            const transformedHeight = targetBoxIsFinal
              ? (resize.height as number)
              : (calculatedResize?.height ?? resizeSourceHeight);
            return {
              clip: {
                id: clip.id,
                source: {
                  id: asset.id,
                  sourceIndex: index,
                  fileName: asset.file.name,
                },
                sourceInSeconds: clip.sourceInSeconds,
                sourceOutSeconds: clip.sourceOutSeconds,
                sourceDurationSeconds: asset.probe?.durationSeconds,
                hasVideo: true,
                hasAudio:
                  project.output.audioEnabled &&
                  clip.audio?.enabled !== false &&
                  asset.probe?.streams.some(
                    (stream) => stream.type === 'audio'
                  ) === true,
                transform:
                  crop || resize || clip.rotation
                    ? {
                        crop,
                        resize,
                        rotation: clip.rotation,
                      }
                    : undefined,
                audioGainDb: clip.audio?.gainDb,
                audioNormalization,
                audioFadeInSeconds: clip.audio?.fadeInSeconds,
                audioFadeOutSeconds: clip.audio?.fadeOutSeconds,
                audioFadeCurve: clip.audio?.fadeCurve,
                videoFadeInSeconds: clip.video?.fadeInSeconds,
                videoFadeOutSeconds: clip.video?.fadeOutSeconds,
                videoFadeCurve: clip.video?.fadeCurve,
              },
              file: asset.file,
              width: transformedWidth,
              height: transformedHeight,
              requestedFrameRate: clip.frameRate,
              sourceFrameRate: video.frameRate,
            };
          });
          const first = resolved[0];
          if (!first) throw new Error('Add at least one timeline clip.');
          const even = (value: number) =>
            Math.max(2, Math.round(value / 2) * 2);
          const requestedWidth =
            project.output.width ?? timelineVideoPreset.width ?? undefined;
          const requestedHeight =
            project.output.height ?? timelineVideoPreset.height ?? undefined;
          let outputWidth: number;
          let outputHeight: number;
          if (requestedWidth && requestedHeight) {
            outputWidth = even(requestedWidth);
            outputHeight = even(requestedHeight);
          } else if (requestedWidth) {
            outputWidth = even(requestedWidth);
            outputHeight = even((requestedWidth * first.height) / first.width);
          } else if (requestedHeight) {
            outputHeight = even(requestedHeight);
            outputWidth = even((requestedHeight * first.width) / first.height);
          } else {
            const scale = Math.min(1, 1920 / first.width, 1080 / first.height);
            outputWidth = even(first.width * scale);
            outputHeight = even(first.height * scale);
          }
          const requestedClipFrameRates = [
            ...new Set(
              resolved.flatMap((entry) =>
                entry.requestedFrameRate === undefined
                  ? []
                  : [entry.requestedFrameRate]
              )
            ),
          ];
          if (
            project.output.frameRate === undefined &&
            timelineVideoPreset.frameRate === undefined &&
            requestedClipFrameRates.length > 1
          ) {
            throw new Error(
              'Timeline clips contain conflicting legacy frame-rate settings. Choose one frame rate in Timeline output.'
            );
          }
          const frameRate =
            project.output.frameRate ??
            timelineVideoPreset.frameRate ??
            requestedClipFrameRates[0] ??
            first.sourceFrameRate ??
            30;
          const sampleRate =
            project.output.sampleRate ?? preset.audio?.sampleRate ?? 48_000;
          const channelLayout =
            project.output.channelLayout ??
            (preset.audio?.channels === 1
              ? 'mono'
              : preset.audio?.channels === 6
                ? '5.1'
                : 'stereo');
          const missingAudioPolicy =
            !project.output.audioEnabled || !preset.audio
              ? ('drop-all' as const)
              : (project.output.missingAudioPolicy ?? 'insert-silence');
          const outputFileName = safeExportFileName(project.output.fileName, {
            extension: preset.fileExtension,
            fallback: 'timeline',
          });
          const plan = buildTimelineExportPlan({
            jobId: crypto.randomUUID(),
            clips: resolved.map(({ clip }) => clip),
            preset,
            outputWidth,
            outputHeight,
            frameRate,
            sampleRate,
            channelLayout,
            missingAudioPolicy,
            outputFileName,
          });
          const rendered = await executeStep(
            plan,
            resolved.map(({ file }) => file),
            'Render timeline'
          );
          const renderedResult = rendered.results[0];
          if (!renderedResult) {
            throw new Error('The rendered timeline output was not returned.');
          }
          let currentResult = renderedResult;
          let currentFile = resultAsFile(currentResult);
          const totalDuration = resolved.reduce(
            (sum, entry) =>
              sum + entry.clip.sourceOutSeconds - entry.clip.sourceInSeconds,
            0
          );

          const activeSubtitleTracks = project.subtitles
            .filter((entry) => entry.mode !== 'exclude')
            .sort((left, right) => {
              if (left.mode === right.mode) return 0;
              return left.mode === 'burn-in' ? -1 : 1;
            });
          for (const track of activeSubtitleTracks) {
            const originalSubtitle = subtitleFiles.get(track.id);
            if (!originalSubtitle || !track.sourceFormat) {
              throw new Error(
                `Reattach subtitle ${track.sourceName ?? track.id} before rendering the project.`
              );
            }
            let subtitleFile = originalSubtitle;
            let shiftedResultForCleanup: ExportResult | undefined;
            if ((track.offsetSeconds ?? 0) !== 0) {
              const shifted = await executeStep(
                buildSubtitleConversionPlan({
                  jobId: crypto.randomUUID(),
                  subtitle: {
                    id: track.id,
                    sourceIndex: 0,
                    fileName: originalSubtitle.name,
                  },
                  outputFormat: track.sourceFormat,
                  offsetSeconds: track.offsetSeconds ?? 0,
                }),
                [originalSubtitle],
                `Shift subtitle ${track.sourceName ?? track.id}`
              );
              const shiftedResult = shifted.results[0];
              if (!shiftedResult) {
                throw new Error(
                  'The shifted subtitle output was not returned.'
                );
              }
              shiftedResultForCleanup = shiftedResult;
              subtitleFile = resultAsFile(shiftedResult);
            }

            const mediaSource = {
              id: `timeline-${project.id}`,
              sourceIndex: 0,
              fileName: currentFile.name,
            };
            const subtitleSource = {
              id: track.id,
              sourceIndex: 1,
              fileName: subtitleFile.name,
            };
            const sourceStreams =
              track.mode === 'burn-in'
                ? []
                : remuxStreamsFromProbe(
                    normalizeFfprobeReport(
                      (await engineManager.probe(currentFile)).json
                    )
                  );
            const subtitlePlan =
              track.mode === 'burn-in'
                ? buildSubtitleBurnPlan({
                    jobId: crypto.randomUUID(),
                    source: mediaSource,
                    subtitle: subtitleSource,
                    preset,
                    expectedDurationSeconds: totalDuration,
                  })
                : buildSubtitleMuxPlan({
                    jobId: crypto.randomUUID(),
                    source: mediaSource,
                    subtitle: subtitleSource,
                    subtitleCodec: subtitleCodecForFormat(track.sourceFormat),
                    sourceStreams,
                    targetContainer: timelineContainer,
                    targetExtension: preset.fileExtension,
                    ...(track.language ? { language: track.language } : {}),
                    ...(track.title ? { title: track.title } : {}),
                    default: track.default ?? false,
                    forced: track.forced ?? false,
                    expectedDurationSeconds: totalDuration,
                  });
            const subtitled = await executeStep(
              subtitlePlan,
              [currentFile, subtitleFile],
              track.mode === 'burn-in'
                ? 'Burn project subtitle'
                : 'Mux project subtitle'
            );
            const subtitledResult = subtitled.results[0];
            if (!subtitledResult) {
              throw new Error(
                'The subtitled timeline output was not returned.'
              );
            }
            resultCollection.remove(currentResult.id);
            if (shiftedResultForCleanup)
              resultCollection.remove(shiftedResultForCleanup.id);
            currentResult = subtitledResult;
            currentFile = resultAsFile(subtitledResult);
          }

          if (project.chapters.length > 0) {
            const chaptered = await executeStep(
              buildChapterMuxPlan({
                jobId: crypto.randomUUID(),
                source: {
                  id: `timeline-${project.id}`,
                  sourceIndex: 0,
                  fileName: currentFile.name,
                },
                chapters: project.chapters.map((chapter) => ({
                  id: chapter.id,
                  title: chapter.title,
                  startSeconds: chapter.startSeconds,
                  endSeconds: chapter.endSeconds,
                  timeBase: chapter.timeBase ?? '1/1000',
                })),
                targetExtension: preset.fileExtension,
                targetMuxer: preset.container,
                durationSeconds: totalDuration,
              }),
              [currentFile],
              'Mux project chapters'
            );
            const chapteredResult = chaptered.results[0];
            if (!chapteredResult) {
              throw new Error(
                'The chaptered timeline output was not returned.'
              );
            }
            resultCollection.remove(currentResult.id);
            currentResult = chapteredResult;
            currentFile = resultAsFile(chapteredResult);
          }

          const metadataEdits = metadataEditsFromProject(project.metadata);
          const finalized = await executeStep(
            buildMetadataEditPlan({
              jobId: crypto.randomUUID(),
              source: {
                id: `timeline-${project.id}`,
                sourceIndex: 0,
                fileName: currentFile.name,
              },
              edits: metadataEdits,
              targetExtension: preset.fileExtension,
              targetMuxer: preset.container,
              sourceMetadataPolicy:
                preset.metadataPolicy === 'remove' ? 'remove' : 'copy',
              chapterPolicy: 'keep',
              expectedDurationSeconds: totalDuration,
              outputFileName,
            }),
            [currentFile],
            'Finalize timeline output'
          );
          if (!finalized.results[0]) {
            throw new Error('The finalized timeline output was not returned.');
          }
          resultCollection.remove(currentResult.id);
          refreshResults();
        }
      );
    } catch (error) {
      setOperationError(
        error instanceof Error
          ? error.message
          : 'The timeline could not be rendered.'
      );
    }
  }, [
    assets,
    loudnessByAsset,
    project,
    refreshResults,
    resultCollection,
    runWorkflow,
    subtitleFiles,
    userPresets,
  ]);

  const resetProject = useCallback(() => {
    for (const asset of assets) URL.revokeObjectURL(asset.objectUrl);
    const cancelActiveInspection = sourceInspectionRegistry.current.clear();
    if (cancelActiveInspection) void engineManager.cancelActive();
    assetsRef.current = [];
    clearResult();
    setAssets([]);
    setSelectedAssetId(undefined);
    setSelectedClipId(undefined);
    setSubtitleFiles(new Map());
    setWaveformByAsset({});
    setSplitMarkersByAsset({});
    setSplitBatch(undefined);
    setLoudnessByAsset({});
    setPlayheadByAsset({});
    setScheduledJobs([]);
    scheduledWorkRef.current.clear();
    setProject(createEmptyProject());
    setProjectNotice('Started a new empty project.');
  }, [assets, clearResult]);

  const exportProject = useCallback(() => {
    const json = serializeProject(project, {
      pretty: true,
      includeUiState: true,
    });
    downloadBlob(
      new Blob([json], { type: 'application/json' }),
      projectDocumentFileName(project)
    );
    setProjectNotice(
      'Project document downloaded. Source files are not embedded.'
    );
  }, [project]);

  const importProject = useCallback(
    async (file: File) => {
      try {
        const imported = importProjectDocument(await file.text());
        for (const asset of assets) URL.revokeObjectURL(asset.objectUrl);
        const cancelActiveInspection = sourceInspectionRegistry.current.clear();
        if (cancelActiveInspection) void engineManager.cancelActive();
        assetsRef.current = [];
        clearResult();
        setAssets([]);
        setSelectedAssetId(undefined);
        setSelectedClipId(imported.project.timeline[0]?.id);
        setSubtitleFiles(new Map());
        setWaveformByAsset({});
        setSplitMarkersByAsset({});
        setSplitBatch(undefined);
        setLoudnessByAsset({});
        setPlayheadByAsset({});
        setScheduledJobs([]);
        scheduledWorkRef.current.clear();
        setProject(imported.project);
        selectWorkspaceMode('edit');
        setProjectNotice(
          imported.warnings.length > 0
            ? imported.warnings.map((warning) => warning.message).join(' ')
            : 'Project loaded.'
        );
      } catch (error) {
        setProjectNotice(
          error instanceof Error ? error.message : 'Project import failed.'
        );
      }
    },
    [assets, clearResult, selectWorkspaceMode]
  );

  const moveClip = useCallback(
    (clipId: string, toIndex: number) => {
      if (toIndex < 0 || toIndex >= project.timeline.length) return;
      applyProjectAction({
        type: 'clip/move',
        clipId,
        toIndex,
        updatedAt: timestamp(),
      });
    },
    [applyProjectAction, project.timeline.length]
  );

  const updateClip = useCallback(
    (clipId: string, changes: Partial<TimelineClip>) => {
      const clip = project.timeline.find((entry) => entry.id === clipId);
      if (!clip) return;
      const sourceIn = changes.sourceInSeconds ?? clip.sourceInSeconds;
      const sourceOut = changes.sourceOutSeconds ?? clip.sourceOutSeconds;
      if (
        !Number.isFinite(sourceIn) ||
        !Number.isFinite(sourceOut) ||
        sourceIn < 0 ||
        sourceOut - sourceIn < 0.001
      ) {
        setProjectNotice('Clip out-point must remain after its in-point.');
        return;
      }
      applyProjectAction({
        type: 'clip/update',
        clipId,
        changes,
        updatedAt: timestamp(),
      });
    },
    [applyProjectAction, project.timeline]
  );

  const changeSubtitles = useCallback(
    (subtitles: AvProjectV1['subtitles']) => {
      const retainedIds = new Set(subtitles.map((track) => track.id));
      setSubtitleFiles(
        (current) =>
          new Map([...current].filter(([trackId]) => retainedIds.has(trackId)))
      );
      applyProjectAction({
        type: 'subtitles/set',
        subtitles,
        updatedAt: timestamp(),
      });
    },
    [applyProjectAction]
  );

  const importSubtitleFile = useCallback(
    (file: File) => {
      const extension = file.name.split('.').at(-1)?.toLowerCase();
      if (extension !== 'srt' && extension !== 'vtt' && extension !== 'ass') {
        setProjectNotice('Choose an SRT, WebVTT, or ASS subtitle file.');
        return;
      }
      if (file.size > 20 * 1024 * 1024) {
        setProjectNotice('Subtitle files are limited to 20 MiB.');
        return;
      }
      const missing = project.subtitles.find(
        (track) =>
          track.sourceStatus === 'missing' &&
          track.sourceName?.toLocaleLowerCase() ===
            file.name.toLocaleLowerCase()
      );
      const trackId = missing?.id ?? crypto.randomUUID();
      const tracks: AvProjectV1['subtitles'] = missing
        ? project.subtitles.map((track) =>
            track.id === missing.id
              ? {
                  ...track,
                  sourceName: file.name,
                  sourceFormat: extension,
                  sourceStatus: 'attached' as const,
                }
              : track
          )
        : [
            ...project.subtitles,
            {
              id: trackId,
              sourceName: file.name,
              sourceFormat: extension,
              mode: 'mux' as const,
              sourceStatus: 'attached' as const,
            },
          ];
      setSubtitleFiles((current) => new Map(current).set(trackId, file));
      applyProjectAction({
        type: 'subtitles/set',
        subtitles: tracks,
        updatedAt: timestamp(),
      });
      setProjectNotice(
        missing
          ? `Reattached subtitle ${file.name}.`
          : `Imported subtitle ${file.name}.`
      );
    },
    [applyProjectAction, project.subtitles]
  );

  const resolvePreset = useCallback(
    (presetId: string) =>
      findBuiltInPreset(presetId) ??
      userPresets.find((preset) => preset.id === presetId),
    [userPresets]
  );

  const handleStructuralTrim = useCallback(
    async (request: StructuralTrimRequest) => {
      const clip = project.timeline.find(
        (entry) => entry.id === request.clipId
      );
      const asset = clip
        ? assets.find((entry) => entry.id === clip.assetId)
        : undefined;
      if (!clip || !asset?.probe) {
        throw new Error('The selected clip source is not attached and probed.');
      }
      const preset =
        request.mode === 'accurate'
          ? resolvePreset(request.presetId)
          : undefined;
      if (request.mode === 'accurate' && !preset) {
        throw new Error('The accurate trim preset is unavailable.');
      }
      const selection =
        request.mode === 'accurate' && preset
          ? {
              video: preset.video
                ? asset.probe.streams
                    .filter(
                      (stream) =>
                        stream.type === 'video' &&
                        stream.disposition.attached_pic !== true
                    )
                    .slice(0, 1)
                    .map((stream) => stream.index)
                : [],
              audio: preset.audio
                ? asset.probe.streams
                    .filter((stream) => stream.type === 'audio')
                    .slice(0, 1)
                    .map((stream) => stream.index)
                : [],
              subtitles: [],
              attachments: [],
            }
          : undefined;
      const plan = buildTrimPlan({
        jobId: crypto.randomUUID(),
        source: {
          id: asset.id,
          sourceIndex: 0,
          fileName: asset.file.name,
        },
        mode: request.mode,
        startSeconds: request.startSeconds,
        endSeconds: request.endSeconds,
        sourceDurationSeconds: asset.probe.durationSeconds,
        ...(selection ? { streamSelection: selection } : {}),
        ...(preset ? { preset } : {}),
        ...(request.mode === 'fast'
          ? { targetExtension: request.targetExtension }
          : {}),
      });
      await runPlan(
        plan,
        [asset.file],
        request.mode === 'fast' ? 'Fast keyframe trim' : 'Accurate trim'
      );
    },
    [assets, project.timeline, resolvePreset, runPlan]
  );

  const handleStructuralConcat = useCallback(
    async (request: StructuralConcatRequest) => {
      const resolved = request.clipIds.map((clipId, index) => {
        const clip = project.timeline.find((entry) => entry.id === clipId);
        const asset = clip
          ? assets.find((entry) => entry.id === clip.assetId)
          : undefined;
        if (!clip || !asset?.probe) {
          throw new Error(
            `Timeline clip ${index + 1} has no attached, probed source.`
          );
        }
        return {
          clip,
          asset,
          source: concatSourceForClip(clip, asset, index),
        };
      });
      if (resolved.length < 2) {
        throw new Error('Concatenation requires at least two timeline clips.');
      }
      const plan =
        request.mode === 'fast'
          ? buildFastConcatPlan({
              jobId: crypto.randomUUID(),
              sources: resolved.map((entry) => entry.source),
              targetExtension: request.targetExtension,
              targetMuxer: request.targetMuxer,
            })
          : (() => {
              const preset = resolvePreset(request.presetId);
              if (!preset?.video) {
                throw new Error(
                  'The normalized concat video preset is unavailable.'
                );
              }
              const firstVideo = resolved[0]?.asset.probe?.streams.find(
                (stream) =>
                  stream.type === 'video' &&
                  stream.disposition.attached_pic !== true
              );
              if (!firstVideo?.width || !firstVideo.height) {
                throw new Error(
                  'The first concat source has no validated video dimensions.'
                );
              }
              const even = (value: number) =>
                Math.max(2, Math.round(value / 2) * 2);
              const scale = Math.min(
                1,
                1920 / firstVideo.width,
                1080 / firstVideo.height
              );
              return buildNormalizedConcatPlan({
                jobId: crypto.randomUUID(),
                sources: resolved.map((entry) => entry.source),
                targetExtension: preset.fileExtension,
                targetMuxer: preset.container,
                preset,
                width: even(firstVideo.width * scale),
                height: even(firstVideo.height * scale),
                frameRate: firstVideo.frameRate ?? 30,
                sampleRate: 48_000,
                channelLayout: 'stereo',
                missingAudioPolicy: request.missingAudioPolicy,
                subtitlePolicy: request.subtitlePolicy,
                crossfadeSeconds: request.crossfadeSeconds,
              });
            })();
      await runPlan(
        plan,
        resolved.map((entry) => entry.asset.file),
        request.mode === 'fast' ? 'Fast compatible concat' : 'Normalized concat'
      );
    },
    [assets, project.timeline, resolvePreset, runPlan]
  );

  const handleAdvancedSplit = useCallback(
    async (request: AdvancedSplitRequest) => {
      const asset = inspectedClipAsset;
      const duration = asset?.probe?.durationSeconds;
      if (!asset || duration === undefined) {
        throw new Error(
          'Select an attached, inspected source before splitting.'
        );
      }
      const sourceExtension = extensionFromName(asset.file.name);
      const preset =
        request.mode === 'accurate'
          ? resolvePreset(request.presetId)
          : undefined;
      if (request.mode === 'accurate' && !preset) {
        throw new Error('The accurate split preset is unavailable.');
      }
      if (
        request.mode === 'accurate' &&
        preset &&
        request.targetExtension !== preset.fileExtension
      ) {
        throw new Error(
          `Accurate split output must use the preset extension .${preset.fileExtension}.`
        );
      }
      if (
        request.mode === 'fast' &&
        request.targetExtension !== sourceExtension
      ) {
        throw new Error(
          `Fast stream-copy split keeps the source container .${sourceExtension}; choose accurate mode to change format.`
        );
      }
      const plan = buildSplitPlan({
        jobId: crypto.randomUUID(),
        source: {
          id: asset.id,
          sourceIndex: 0,
          fileName: asset.file.name,
        },
        durationSeconds: duration,
        definition: request.definition,
        mode: request.mode,
        targetExtension: request.targetExtension,
        ...(preset ? { preset } : {}),
      });
      const pendingBatch: AdvancedSplitBatchStatus = {
        planId: plan.id,
        segments: plan.outputs.map((output) => {
          if (!output.timeRange) {
            throw new Error(
              `Split output ${output.id} has no declared segment range.`
            );
          }
          return {
            outputId: output.id,
            fileName: output.fileName,
            startSeconds: output.timeRange.startSeconds,
            endSeconds: output.timeRange.endSeconds,
            state: 'queued',
          };
        }),
      };
      setSplitBatch(pendingBatch);
      try {
        const execution = await runWorkflow(
          'Split media',
          1,
          async (executeStep) => {
            setSplitBatch((current) =>
              current?.planId === plan.id
                ? {
                    ...current,
                    segments: current.segments.map((segment) => ({
                      ...segment,
                      state: 'running',
                    })),
                  }
                : current
            );
            return executeStep(plan, [asset.file], 'Split media');
          }
        );
        const resultIds = new Set(
          execution.results.map((result) => result.outputId)
        );
        setSplitBatch((current) =>
          current?.planId === plan.id
            ? {
                ...current,
                segments: current.segments.map((segment) => {
                  const result = execution.results.find(
                    (entry) => entry.outputId === segment.outputId
                  );
                  if (!result || !resultIds.has(segment.outputId)) {
                    return {
                      ...segment,
                      state: 'failed',
                      message:
                        'FFmpeg returned successfully, but this expected segment was not retained.',
                    };
                  }
                  const verification = execution.verifications?.[result.id];
                  if (verification?.warning) {
                    return {
                      ...segment,
                      state: 'warning',
                      message: verification.warning,
                    };
                  }
                  return {
                    ...segment,
                    state: verification?.probe ? 'verified' : 'completed',
                  };
                }),
              }
            : current
        );
      } catch (error) {
        const cancelled =
          error instanceof EngineError && error.code === 'cancelled';
        const message =
          error instanceof Error
            ? error.message
            : 'The shared FFmpeg split execution failed.';
        setSplitBatch((current) =>
          current?.planId === plan.id
            ? {
                ...current,
                segments: current.segments.map((segment) => ({
                  ...segment,
                  state: cancelled ? 'cancelled' : 'failed',
                  message,
                })),
              }
            : current
        );
        throw error;
      }
    },
    [inspectedClipAsset, resolvePreset, runWorkflow]
  );

  const handleAdvancedAudio = useCallback(
    async (request: AdvancedAudioRequest) => {
      const asset = inspectedClipAsset;
      const duration = asset?.probe?.durationSeconds;
      if (!asset || duration === undefined) {
        throw new Error('Select an attached, inspected source first.');
      }
      const firstAudioIndex = asset.probe?.streams.find(
        (stream) => stream.type === 'audio'
      )?.index;
      const audioStreamIndex = request.audioStreamIndex ?? firstAudioIndex;
      if (audioStreamIndex === undefined) {
        throw new Error('The source has no selected audio stream.');
      }
      const source = {
        id: asset.id,
        sourceIndex: 0,
        fileName: asset.file.name,
      };
      if (request.type === 'static-waveform') {
        const plan = buildStaticWaveformPlan({
          jobId: crypto.randomUUID(),
          source,
          audioStreamIndex,
          width: request.width,
          height: request.height,
          color: request.foreground,
          background: request.background,
          expectedDurationSeconds: duration,
        });
        const execution = await runPlan(
          plan,
          [asset.file],
          'Create static waveform'
        );
        const output = execution.results[0];
        if (!output) throw new Error('The waveform image was not returned.');
        try {
          await cacheDerivative(
            asset.file,
            'waveform-image',
            'waveform-image',
            project.id,
            output.blob,
            {
              audioStreamIndex,
              width: request.width,
              height: request.height,
              foreground: request.foreground,
              background: request.background,
            }
          );
        } catch {
          setProjectNotice(
            'Waveform image created, but this browser could not cache the derivative.'
          );
        }
        return;
      }
      if (request.type === 'waveform-peaks') {
        const cacheSettings = {
          audioStreamIndex,
          sampleRate: request.sampleRate,
          bucketCount: request.bucketCount,
        };
        try {
          const cached = await readCachedDerivative(
            asset.file,
            'waveform-peaks',
            cacheSettings
          );
          if (cached) {
            const peaks = deserializeWaveformPeaks(await cached.arrayBuffer());
            setWaveformByAsset((current) => ({
              ...current,
              [asset.id]: peaks,
            }));
            setProjectNotice('Reused matching bounded waveform peak data.');
            return;
          }
        } catch {
          // A missing or invalid derivative is safely regenerated below.
        }
        const plan = buildWaveformAnalysisPlan({
          jobId: crypto.randomUUID(),
          source,
          audioStreamIndex,
          sampleRate: request.sampleRate,
          expectedDurationSeconds: duration,
        });
        const execution = await runPlan(
          plan,
          [asset.file],
          'Extract reduced waveform audio'
        );
        const output = execution.results[0];
        if (!output) {
          throw new Error('The reduced PCM analysis output was not returned.');
        }
        setWaveformProgress(0);
        try {
          const peaks = await waveformRuntime.aggregate(
            {
              container: 'wav',
              data: new Uint8Array(await output.blob.arrayBuffer()),
            },
            {
              bucketCount: request.bucketCount,
              onProgress: setWaveformProgress,
            }
          );
          setWaveformByAsset((current) => ({
            ...current,
            [asset.id]: peaks,
          }));
          const serialized = serializeWaveformPeaks(peaks);
          try {
            await cacheDerivative(
              asset.file,
              'waveform-peaks',
              'waveform-peaks',
              project.id,
              new Blob([Uint8Array.from(serialized)], {
                type: WAVEFORM_PEAKS_MEDIA_TYPE,
              }),
              cacheSettings
            );
          } catch {
            setProjectNotice(
              'Waveform peaks created, but this browser could not cache the derivative.'
            );
          }
        } finally {
          setWaveformProgress(undefined);
          resultCollection.remove(output.id);
          refreshResults();
        }
        return;
      }
      if (request.type === 'loudness-measurement') {
        const plan = buildLoudnessAnalysisPlan({
          jobId: crypto.randomUUID(),
          source,
          targets: request.targets,
          audioStreamIndex,
          expectedDurationSeconds: duration,
        });
        const execution = await runPlan(
          plan,
          [asset.file],
          'Measure EBU R128 loudness'
        );
        const measurement = parseLoudnessMeasurement(execution.logText);
        setLoudnessByAsset((current) => ({
          ...current,
          [asset.id]: measurement,
        }));
        setProjectNotice(
          `Measured ${measurement.inputIntegratedLufs.toFixed(1)} LUFS, ${measurement.inputTruePeakDbtp.toFixed(1)} dBTP, LRA ${measurement.inputLoudnessRangeLu.toFixed(1)} LU.`
        );
        return;
      }
      const preset = resolvePreset(request.presetId);
      if (!preset) throw new Error('The selected audio preset is unavailable.');
      if (request.type === 'peak-normalization') {
        const analysis = await runWorkflow(
          'Peak-normalize audio',
          2,
          async (executeStep) => {
            const measured = await executeStep(
              buildPeakAnalysisPlan({
                jobId: crypto.randomUUID(),
                source,
                audioStreamIndex,
                preset,
                expectedDurationSeconds: duration,
              }),
              [asset.file],
              'Measure source peak'
            );
            const measurement = parsePeakMeasurement(measured.logText);
            await executeStep(
              buildPeakNormalizationPlan({
                jobId: crypto.randomUUID(),
                source,
                audioStreamIndex,
                targetPeakDb: request.targetPeakDb,
                measurement,
                preset,
                expectedDurationSeconds: duration,
              }),
              [asset.file],
              'Apply measured peak normalization'
            );
            return measured;
          }
        );
        setLogs((current) =>
          [
            ...analysis.logText.split('\n').filter(Boolean).slice(-120),
            ...current,
          ].slice(-400)
        );
        return;
      }
      const plan = buildLoudnessApplyPlan({
        jobId: crypto.randomUUID(),
        source,
        audioStreamIndex,
        targets: request.targets,
        measurement: request.measurement,
        preset,
        expectedDurationSeconds: duration,
      });
      await runPlan(
        plan,
        [asset.file],
        'Apply measured EBU R128 normalization'
      );
    },
    [
      inspectedClipAsset,
      project.id,
      refreshResults,
      resultCollection,
      resolvePreset,
      runPlan,
      runWorkflow,
      waveformRuntime,
    ]
  );

  const handleThumbnailSeries = useCallback(
    async (request: ThumbnailSeriesRequest) => {
      const asset = inspectedClipAsset;
      const duration = asset?.probe?.durationSeconds;
      if (!asset || duration === undefined) {
        throw new Error('Select an attached, inspected video source first.');
      }
      const source = {
        id: asset.id,
        sourceIndex: 0,
        fileName: asset.file.name,
      };
      const size = {
        ...(request.width ? { width: request.width } : {}),
        ...(request.height ? { height: request.height } : {}),
      };
      const sceneDistribution =
        request.distribution.type === 'scene-changes'
          ? request.distribution
          : undefined;
      const execution = sceneDistribution
        ? await runWorkflow(
            'Create scene-change thumbnails',
            2,
            async (executeStep) => {
              const analysis = await executeStep(
                buildSceneChangeAnalysisPlan({
                  jobId: crypto.randomUUID(),
                  source,
                  durationSeconds: duration,
                  threshold: sceneDistribution.threshold,
                  maxFrames: sceneDistribution.count,
                }),
                [asset.file],
                'Analyze scene changes'
              );
              const frames = parseSceneChangeFrames(analysis.logText).slice(
                0,
                sceneDistribution.count
              );
              if (frames.length === 0) {
                throw new Error(
                  'No scene changes met this threshold. Lower the threshold or use evenly spaced frames.'
                );
              }
              return executeStep(
                buildSceneThumbnailSeriesPlan({
                  jobId: crypto.randomUUID(),
                  source,
                  durationSeconds: duration,
                  frames,
                  size,
                  format: request.format,
                  quality: request.quality,
                }),
                [asset.file],
                'Extract analyzed scene frames'
              );
            }
          )
        : await runPlan(
            buildThumbnailSeriesPlan({
              jobId: crypto.randomUUID(),
              source,
              durationSeconds: duration,
              ...(request.distribution.type === 'evenly-spaced'
                ? { count: request.distribution.count }
                : request.distribution.type === 'fixed-interval'
                  ? {
                      intervalSeconds: request.distribution.intervalSeconds,
                    }
                  : request.distribution.type === 'scene-changes'
                    ? { count: request.distribution.count }
                    : { timesSeconds: request.distribution.timesSeconds }),
              size,
              format: request.format,
              quality: request.quality,
            }),
            [asset.file],
            'Create thumbnail series'
          );
      try {
        await Promise.all(
          execution.results.map((output, index) =>
            cacheDerivative(
              asset.file,
              `thumbnail-series-${index}`,
              'thumbnail',
              project.id,
              output.blob,
              {
                distribution: request.distribution,
                index,
                width: request.width ?? null,
                height: request.height ?? null,
                format: request.format,
              }
            )
          )
        );
      } catch {
        setProjectNotice(
          'Thumbnail series created, but this browser could not cache every derivative.'
        );
      }
    },
    [inspectedClipAsset, project.id, runPlan, runWorkflow]
  );

  const handleContactSheet = useCallback(
    async (request: ContactSheetRequest) => {
      const asset = inspectedClipAsset;
      const duration = asset?.probe?.durationSeconds;
      if (!asset || duration === undefined) {
        throw new Error('Select an attached, inspected video source first.');
      }
      const source = {
        id: asset.id,
        sourceIndex: 0,
        fileName: asset.file.name,
      };
      const labelsRequested = request.timestampLabels || request.sourceLabel;
      const font = labelsRequested
        ? await loadBundledContactSheetFont()
        : undefined;
      const buildSheet = (
        sceneFrames?: ReturnType<typeof parseSceneChangeFrames>
      ) =>
        buildContactSheetPlan({
          jobId: crypto.randomUUID(),
          source,
          durationSeconds: duration,
          ...request,
          ...(sceneFrames
            ? { frameCount: sceneFrames.length, sceneFrames }
            : {}),
          drawtextAvailable: Boolean(font),
          ...(font
            ? {
                font: {
                  id: 'bundled-contact-sheet-font',
                  sourceIndex: 1,
                  fileName: font.name,
                },
              }
            : {}),
        });
      const inputs = font ? [asset.file, font] : [asset.file];
      const sceneSelection =
        request.selection.type === 'scene-changes'
          ? request.selection
          : undefined;
      const execution = sceneSelection
        ? await runWorkflow(
            'Create scene-change contact sheet',
            2,
            async (executeStep) => {
              const analysis = await executeStep(
                buildSceneChangeAnalysisPlan({
                  jobId: crypto.randomUUID(),
                  source,
                  durationSeconds: duration,
                  threshold: sceneSelection.threshold,
                  maxFrames: request.frameCount,
                }),
                [asset.file],
                'Analyze scene changes'
              );
              const frames = parseSceneChangeFrames(analysis.logText).slice(
                0,
                request.frameCount
              );
              if (frames.length === 0) {
                throw new Error(
                  'No scene changes met this threshold. Lower the threshold or use evenly spaced frames.'
                );
              }
              return executeStep(
                buildSheet(frames),
                inputs,
                'Render scene-change contact sheet'
              );
            }
          )
        : await runPlan(buildSheet(), inputs, 'Create contact sheet');
      const output = execution.results[0];
      if (!output) throw new Error('The contact sheet was not returned.');
      try {
        await cacheDerivative(
          asset.file,
          'contact-sheet',
          'contact-sheet',
          project.id,
          output.blob,
          request as unknown as Readonly<Record<string, unknown>>
        );
      } catch {
        setProjectNotice(
          'Contact sheet created, but this browser could not cache the derivative.'
        );
      }
    },
    [inspectedClipAsset, project.id, runPlan, runWorkflow]
  );

  const handleMetadataAction = useCallback(
    async (request: MetadataExecutionRequest) => {
      if (request.type === 'import') {
        applyProjectAction({
          type: 'metadata/set',
          metadata: projectMetadataFromEdits(request.edits),
          updatedAt: timestamp(),
        });
        setProjectNotice('Imported validated metadata JSON into the project.');
        return;
      }
      if (request.type === 'export') {
        downloadBlob(
          new Blob([request.json], { type: 'application/json' }),
          'av-tools-metadata.json'
        );
        return;
      }
      const asset = inspectedClipAsset;
      if (!asset?.probe) {
        throw new Error('Select an attached, inspected source first.');
      }
      const extension = extensionFromName(asset.file.name);
      const selection =
        request.coverArtPolicy === 'remove'
          ? {
              video: asset.probe.streams
                .filter(
                  (stream) =>
                    stream.type === 'video' &&
                    stream.disposition.attached_pic !== true
                )
                .map((stream) => stream.index),
              audio: asset.probe.streams
                .filter((stream) => stream.type === 'audio')
                .map((stream) => stream.index),
              subtitles: asset.probe.streams
                .filter((stream) => stream.type === 'subtitle')
                .map((stream) => stream.index),
              attachments: [],
            }
          : undefined;
      const plan = buildMetadataEditPlan({
        jobId: crypto.randomUUID(),
        source: {
          id: asset.id,
          sourceIndex: 0,
          fileName: asset.file.name,
        },
        edits: request.edits,
        targetExtension: extension,
        targetMuxer: muxerForExtension(extension),
        ...(selection ? { streamSelection: selection } : {}),
        sourceMetadataPolicy: request.sourceMetadataPolicy,
        chapterPolicy: request.chapterPolicy,
        expectedDurationSeconds: asset.probe.durationSeconds,
      });
      await runPlan(plan, [asset.file], 'Write metadata');
    },
    [applyProjectAction, inspectedClipAsset, runPlan]
  );

  const handleChapterAction = useCallback(
    async (request: ChapterExecutionRequest) => {
      if (request.type === 'import') {
        applyProjectAction({
          type: 'chapters/set',
          chapters: request.chapters.map((chapter) => ({
            id: chapter.id,
            startSeconds: chapter.startSeconds,
            endSeconds: chapter.endSeconds,
            title: chapter.title,
            timeBase: chapter.timeBase ?? '1/1000',
          })),
          updatedAt: timestamp(),
        });
        setProjectNotice('Imported validated chapter JSON into the project.');
        return;
      }
      if (request.type === 'export') {
        downloadBlob(
          new Blob([request.json], { type: 'application/json' }),
          'av-tools-chapters.json'
        );
        return;
      }
      const asset = inspectedClipAsset;
      if (!asset?.probe) {
        throw new Error('Select an attached, inspected source first.');
      }
      const extension = extensionFromName(asset.file.name);
      const source = {
        id: asset.id,
        sourceIndex: 0,
        fileName: asset.file.name,
      };
      const plan =
        request.type === 'remove'
          ? buildMetadataEditPlan({
              jobId: crypto.randomUUID(),
              source,
              edits: {},
              targetExtension: extension,
              targetMuxer: muxerForExtension(extension),
              sourceMetadataPolicy: 'copy',
              chapterPolicy: 'remove',
              expectedDurationSeconds: asset.probe.durationSeconds,
            })
          : buildChapterMuxPlan({
              jobId: crypto.randomUUID(),
              source,
              chapters: request.chapters,
              targetExtension: extension,
              targetMuxer: muxerForExtension(extension),
              durationSeconds: asset.probe.durationSeconds,
            });
      await runPlan(
        plan,
        [asset.file],
        request.type === 'remove' ? 'Remove chapters' : 'Replace chapters'
      );
    },
    [applyProjectAction, inspectedClipAsset, runPlan]
  );

  const handleSubtitleAction = useCallback(
    async (request: SubtitleExecutionRequest) => {
      const asset = inspectedClipAsset;
      if (request.type === 'extract') {
        if (!asset) throw new Error('Select an inspected media source first.');
        const plan = buildSubtitleExtractionPlan({
          jobId: crypto.randomUUID(),
          source: {
            id: asset.id,
            sourceIndex: 0,
            fileName: asset.file.name,
          },
          stream: request.stream,
          outputFormat: request.outputFormat,
        });
        await runPlan(plan, [asset.file], 'Extract text subtitle');
        return;
      }
      const attachedFile =
        [...subtitleFiles.values()].find(
          (file) => file.name === request.file.name
        ) ?? request.file;
      if (request.type === 'convert') {
        const plan = buildSubtitleConversionPlan({
          jobId: crypto.randomUUID(),
          subtitle: {
            id: crypto.randomUUID(),
            sourceIndex: 0,
            fileName: attachedFile.name,
          },
          outputFormat: request.outputFormat,
          offsetSeconds: request.offsetSeconds,
        });
        await runPlan(plan, [attachedFile], 'Convert text subtitle');
        return;
      }
      if (!asset?.probe) {
        throw new Error('Select an attached, inspected video source first.');
      }
      const mediaSource = {
        id: asset.id,
        sourceIndex: 0,
        fileName: asset.file.name,
      };
      const subtitleSource = {
        id: crypto.randomUUID(),
        sourceIndex: 1,
        fileName: attachedFile.name,
      };
      if (request.type === 'soft-mux') {
        const targetExtension =
          request.targetContainer === 'matroska'
            ? 'mkv'
            : request.targetContainer;
        const plan = buildSubtitleMuxPlan({
          jobId: crypto.randomUUID(),
          source: mediaSource,
          subtitle: subtitleSource,
          subtitleCodec:
            request.subtitleCodec ||
            subtitleCodecForFormat(request.inputFormat),
          sourceStreams: remuxStreamsFromProbe(asset.probe),
          targetContainer: request.targetContainer,
          targetExtension,
          ...(request.language ? { language: request.language } : {}),
          ...(request.title ? { title: request.title } : {}),
          default: request.default,
          forced: request.forced,
          expectedDurationSeconds: asset.probe.durationSeconds,
        });
        await runPlan(plan, [asset.file, attachedFile], 'Mux soft subtitle');
        return;
      }
      const preset = resolvePreset(request.presetId);
      if (!preset)
        throw new Error('The subtitle burn-in preset is unavailable.');
      const plan = buildSubtitleBurnPlan({
        jobId: crypto.randomUUID(),
        source: mediaSource,
        subtitle: subtitleSource,
        preset,
        expectedDurationSeconds: asset.probe.durationSeconds,
      });
      await runPlan(
        plan,
        [asset.file, attachedFile],
        'Burn subtitle into video'
      );
    },
    [inspectedClipAsset, resolvePreset, runPlan, subtitleFiles]
  );

  const handleUserPresetAction = useCallback(
    async (action: UserPresetAction) => {
      const registry = presetSetup.registry;
      if (action.type === 'create' || action.type === 'update') {
        await registry.save(action.preset);
      } else if (action.type === 'clone') {
        await registry.clone(action.presetId, action.newId, action.newName);
      } else if (action.type === 'rename') {
        await registry.rename(action.presetId, action.name);
      } else if (action.type === 'delete') {
        await registry.delete(action.presetId);
      } else if (action.type === 'reset-all') {
        if (
          !globalThis.confirm(
            'Delete every user-created export preset from this browser?'
          )
        ) {
          return;
        }
        await registry.reset();
      } else if (action.type === 'import') {
        await registry.save(action.preset);
      } else {
        downloadBlob(
          new Blob([action.json], { type: 'application/json' }),
          `${action.preset.id}.json`
        );
        return;
      }
      setUserPresets(registry.list());
      if (!presetSetup.persistent) {
        setProjectNotice(
          'IndexedDB is unavailable; user presets will last only for this page session.'
        );
      }
    },
    [presetSetup]
  );

  const saveManagedResult = useCallback(
    async (output: ExportResult) => {
      try {
        await saveCollectionResult(resultCollection, output.id);
        refreshResults();
      } catch (error) {
        setOperationError(
          error instanceof Error
            ? error.message
            : 'The result could not be saved.'
        );
      }
    },
    [refreshResults, resultCollection]
  );

  const saveManagedZip = useCallback(
    async (selected: readonly ExportResult[]) => {
      if (selected.length === 0) return;
      try {
        const saved = await saveResultsZip(selected, {
          fileName: `${project.name || 'av-tools'}-results.zip`,
          ...(latestReport ? { report: latestReport } : {}),
          // Compression finishes asynchronously, after transient picker
          // activation has expired. A normal download is the honest fallback.
          saver: async (blob, fileName) => {
            downloadBlob(blob, fileName);
            return 'downloaded';
          },
        });
        if (saved.outcome !== 'cancelled') {
          for (const result of selected) resultCollection.remove(result.id);
        }
        refreshResults();
      } catch (error) {
        setOperationError(
          error instanceof Error
            ? error.message
            : 'The ZIP could not be created.'
        );
      }
    },
    [latestReport, project.name, refreshResults, resultCollection]
  );

  const saveManagedReport = useCallback(async () => {
    if (!latestReport) return;
    try {
      await saveExportReport(latestReport);
    } catch (error) {
      setOperationError(
        error instanceof Error
          ? error.message
          : 'The validation report could not be saved.'
      );
    }
  }, [latestReport]);

  const activeCapabilities =
    engineState.status === 'ready' ? engineState.capabilities : undefined;
  const capabilityStatus = (
    requirements: {
      readonly muxers?: readonly string[];
      readonly encoders?: readonly string[];
      readonly filters?: readonly string[];
    },
    unavailableReason?: string
  ): AdvancedCapabilityStatus => {
    if (!activeCapabilities) {
      return {
        available: false,
        reason: 'Inspect a source or initialize the local FFmpeg engine first.',
      };
    }
    const missing = [
      ...(requirements.muxers ?? [])
        .filter((name) => !activeCapabilities.muxers.has(name))
        .map((name) => `muxer ${name}`),
      ...(requirements.encoders ?? [])
        .filter((name) => !activeCapabilities.encoders.has(name))
        .map((name) => `encoder ${name}`),
      ...(requirements.filters ?? [])
        .filter((name) => !activeCapabilities.filters.has(name))
        .map((name) => `filter ${name}`),
    ];
    return missing.length === 0 && !unavailableReason
      ? { available: true }
      : {
          available: false,
          reason:
            unavailableReason ??
            `The loaded core is missing ${missing.join(', ')}.`,
        };
  };

  const advancedPresetOptions: readonly AdvancedExportPresetOption[] = [
    ...BUILT_IN_PRESETS,
    ...userPresets,
  ].map((preset) => {
    const requirements =
      'builtIn' in preset
        ? preset.requirements
        : requirementsForUserPreset(preset);
    const availability = activeCapabilities
      ? presetAvailability({ requirements }, activeCapabilities)
      : {
          status: 'unavailable' as const,
          reasons: ['Initialize the engine to verify this preset.'],
        };
    const opusBlocked =
      preset.audio?.codec === 'libopus' && !FFMPEG_OPUS_REGRESSION_VERIFIED;
    return {
      id: preset.id,
      name: preset.name,
      fileExtension: preset.fileExtension,
      supportsAudio: preset.audio !== undefined,
      supportsVideo: preset.video !== undefined,
      ...(availability.status === 'unavailable' || opusBlocked
        ? {
            disabledReason: opusBlocked
              ? 'Opus output is disabled until the reviewed core passes the non-empty ST/MT regression encode and re-probe gate.'
              : availability.reasons.join(' '),
          }
        : {}),
    };
  });
  const timelinePresetOptions = advancedPresetOptions.filter((option) => {
    const preset = resolvePreset(option.id);
    return (
      option.supportsVideo &&
      preset !== undefined &&
      ['mp4', 'webm', 'matroska'].includes(preset.container)
    );
  });
  const selectedTimelinePreset = resolvePreset(project.output.presetId);
  const selectedTimelinePresetOption = timelinePresetOptions.find(
    (option) => option.id === project.output.presetId
  );
  const timelineOutputReason =
    project.timeline.length === 0
      ? 'Add at least one timeline clip.'
      : !selectedTimelinePreset?.video
        ? 'Choose a video export preset.'
        : selectedTimelinePresetOption?.disabledReason;

  const anyAccuratePreset = advancedPresetOptions.some(
    (preset) => !preset.disabledReason
  );
  const anyAudioPreset = advancedPresetOptions.some(
    (preset) => preset.supportsAudio && !preset.disabledReason
  );
  const anyVideoPreset = advancedPresetOptions.some(
    (preset) => preset.supportsVideo && !preset.disabledReason
  );
  const structuralContext = (() => {
    const diagnostics: StructuralCompatibilityDiagnostic[] = [];
    const sources: ConcatSource[] = [];
    const clips = project.timeline.map((clip, index) => {
      const asset = assets.find((entry) => entry.id === clip.assetId);
      const projectAsset = project.assets.find(
        (entry) => entry.id === clip.assetId
      );
      const label = `${index + 1}. ${
        asset?.file.name ?? projectAsset?.originalName ?? 'Missing source'
      }`;
      if (!asset?.probe) {
        diagnostics.push({
          code: 'source-unavailable',
          severity: 'error',
          message: `${label} is not attached and probed.`,
          path: `timeline.${index}.assetId`,
        });
        return {
          id: clip.id,
          label,
          hasAudio: false,
          hasVideo: false,
          hasSubtitles: false,
          durationSeconds: clip.sourceOutSeconds - clip.sourceInSeconds,
        };
      }
      const unsupportedStreams = asset.probe.streams.filter(
        (stream) =>
          stream.type === 'attachment' ||
          stream.type === 'data' ||
          stream.type === 'unknown'
      );
      if (unsupportedStreams.length > 0) {
        diagnostics.push({
          code: 'unvalidated-stream-type',
          severity: 'error',
          message: `${label} contains ${unsupportedStreams
            .map((stream) => `${stream.type} stream ${stream.index}`)
            .join(
              ', '
            )}; fast concat is disabled because those streams cannot yet be validated safely.`,
          path: `timeline.${index}.streams`,
        });
      }
      try {
        sources.push(concatSourceForClip(clip, asset, index));
      } catch (error) {
        diagnostics.push({
          code: 'source-range',
          severity: 'error',
          message:
            error instanceof Error
              ? `${label}: ${error.message}`
              : `${label} has an invalid source range.`,
          path: `timeline.${index}`,
        });
      }
      return {
        id: clip.id,
        label,
        durationSeconds: clip.sourceOutSeconds - clip.sourceInSeconds,
        hasAudio: asset.probe.streams.some((stream) => stream.type === 'audio'),
        hasVideo: asset.probe.streams.some(
          (stream) =>
            stream.type === 'video' && stream.disposition.attached_pic !== true
        ),
        hasSubtitles: asset.probe.streams.some(
          (stream) => stream.type === 'subtitle'
        ),
      };
    });
    if (
      project.timeline.length >= 2 &&
      sources.length === project.timeline.length
    ) {
      diagnostics.push(...validateConcatCompatibility(sources));
    }
    const firstAsset = project.timeline[0]
      ? assets.find((entry) => entry.id === project.timeline[0]?.assetId)
      : undefined;
    const fastTargetExtension = firstAsset
      ? extensionFromName(firstAsset.file.name)
      : '';
    return {
      clips,
      sources,
      diagnostics,
      fastTargetExtension,
      fastTargetMuxer: fastTargetExtension
        ? muxerForExtension(fastTargetExtension)
        : '',
    };
  })();
  const structuralSelectedClip =
    selectedClip && inspectedClipAsset?.probe
      ? {
          id: selectedClip.id,
          label: inspectedClipAsset.file.name,
          sourceInSeconds: selectedClip.sourceInSeconds,
          sourceOutSeconds: selectedClip.sourceOutSeconds,
          ...(inspectedClipAsset.probe.durationSeconds === undefined
            ? {}
            : {
                sourceDurationSeconds: inspectedClipAsset.probe.durationSeconds,
              }),
          sourceExtension: extensionFromName(inspectedClipAsset.file.name),
          hasAudio: inspectedClipAsset.probe.streams.some(
            (stream) => stream.type === 'audio'
          ),
          hasVideo: inspectedClipAsset.probe.streams.some(
            (stream) =>
              stream.type === 'video' &&
              stream.disposition.attached_pic !== true
          ),
        }
      : undefined;
  const structuralHasAnyAudio = structuralContext.clips.some(
    (clip) => clip.hasAudio
  );
  const structuralHasMissingAudio = structuralContext.clips.some(
    (clip) => !clip.hasAudio
  );
  const sourceExtension = inspectedClipAsset
    ? extensionFromName(inspectedClipAsset.file.name)
    : '';
  const sourceMuxer = sourceExtension
    ? muxerForExtension(sourceExtension)
    : undefined;
  const advancedAvailability: Partial<
    Readonly<Record<AdvancedCapabilityKey, AdvancedCapabilityStatus>>
  > = {
    'split-fast': sourceMuxer
      ? capabilityStatus({ muxers: [sourceMuxer] })
      : { available: false, reason: 'Select a source first.' },
    'split-accurate': capabilityStatus(
      {},
      anyAccuratePreset ? undefined : 'No verified export preset is available.'
    ),
    'waveform-static': capabilityStatus({
      muxers: ['image2'],
      encoders: ['png'],
      filters: ['color', 'aformat', 'showwavespic', 'overlay'],
    }),
    'waveform-peaks': capabilityStatus({
      muxers: ['wav'],
      encoders: ['pcm_s16le'],
    }),
    'loudness-measure': capabilityStatus({
      muxers: ['null'],
      filters: ['loudnorm'],
    }),
    'peak-normalize': capabilityStatus(
      { filters: ['volume'] },
      anyAudioPreset ? undefined : 'No verified audio preset is available.'
    ),
    'loudness-normalize': capabilityStatus(
      { filters: ['loudnorm'] },
      anyAudioPreset ? undefined : 'No verified audio preset is available.'
    ),
    'thumbnail-series': capabilityStatus({
      filters: ['split', 'select', 'setpts'],
    }),
    'contact-sheet': capabilityStatus({
      filters: ['fps', 'scale', 'tile'],
    }),
    'contact-sheet-labels': {
      ...capabilityStatus({ filters: ['drawtext'] }),
    },
    'scene-change-analysis': capabilityStatus({
      muxers: ['null'],
      filters: ['select', 'showinfo'],
    }),
    'metadata-write': sourceMuxer
      ? capabilityStatus({ muxers: [sourceMuxer] })
      : { available: false, reason: 'Select a source first.' },
    'chapter-write': sourceMuxer
      ? capabilityStatus({ muxers: [sourceMuxer] })
      : { available: false, reason: 'Select a source first.' },
    'subtitle-extract': capabilityStatus({}),
    'subtitle-convert': capabilityStatus({}),
    'subtitle-mux': capabilityStatus({}),
    'subtitle-burn': capabilityStatus(
      { filters: ['subtitles'] },
      anyVideoPreset ? undefined : 'No verified video preset is available.'
    ),
    'preset-storage': { available: true },
  };
  const structuralAvailability = {
    'trim-fast': sourceMuxer
      ? capabilityStatus({ muxers: [sourceMuxer] })
      : { available: false, reason: 'Select an attached source first.' },
    'trim-accurate': capabilityStatus(
      {},
      anyAccuratePreset ? undefined : 'No verified export preset is available.'
    ),
    'concat-fast': structuralContext.fastTargetMuxer
      ? capabilityStatus({
          muxers: [structuralContext.fastTargetMuxer],
        })
      : {
          available: false,
          reason: 'Attach and probe the first timeline source.',
        },
    'concat-normalized': capabilityStatus(
      {
        filters: [
          'trim',
          'setpts',
          'scale',
          'pad',
          'setsar',
          'fps',
          'format',
          'concat',
          ...(structuralHasAnyAudio
            ? ['atrim', 'asetpts', 'aresample', 'aformat']
            : []),
          ...(structuralHasAnyAudio && structuralHasMissingAudio
            ? ['anullsrc']
            : []),
        ],
      },
      anyVideoPreset ? undefined : 'No verified video preset is available.'
    ),
    'concat-crossfade': capabilityStatus({
      filters: ['xfade', ...(structuralHasAnyAudio ? ['acrossfade'] : [])],
    }),
  } as const;

  const advancedSource = inspectedClipAsset?.probe
    ? {
        sourceId: inspectedClipAsset.id,
        ...(inspectedClipAsset.probe.durationSeconds === undefined
          ? {}
          : {
              durationSeconds: inspectedClipAsset.probe.durationSeconds,
            }),
        sourceExtension,
        hasAudio: inspectedClipAsset.probe.streams.some(
          (stream) => stream.type === 'audio'
        ),
        hasVideo: inspectedClipAsset.probe.streams.some(
          (stream) =>
            stream.type === 'video' && stream.disposition.attached_pic !== true
        ),
        ...(() => {
          const index = inspectedClipAsset.probe?.streams.find(
            (stream) => stream.type === 'audio'
          )?.index;
          return index === undefined ? {} : { selectedAudioStreamIndex: index };
        })(),
      }
    : undefined;

  const advancedMetadataStreams =
    inspectedClipAsset?.probe?.streams.map((stream) => ({
      index: stream.index,
      type: stream.type,
      codec: stream.codecName ?? 'unknown',
      ...(stream.language ? { language: stream.language } : {}),
      ...(stream.title ? { title: stream.title } : {}),
      disposition: stream.disposition,
    })) ?? [];
  const advancedChapters = project.chapters.map((chapter) => ({
    id: chapter.id,
    title: chapter.title,
    startSeconds: chapter.startSeconds,
    endSeconds: chapter.endSeconds,
    timeBase: chapter.timeBase ?? '1/1000',
  }));
  const advancedTimelineClips = inspectedClipAsset
    ? project.timeline
        .filter((clip) => clip.assetId === inspectedClipAsset.id)
        .map((clip, index) => ({
          startSeconds: clip.sourceInSeconds,
          endSeconds: clip.sourceOutSeconds,
          label: `clip-${index + 1}`,
        }))
    : [];
  const advancedSubtitleStreams =
    inspectedClipAsset?.probe?.streams.flatMap((stream) =>
      stream.type === 'subtitle'
        ? [
            {
              index: stream.index,
              codec: stream.codecName ?? 'unknown',
              ...(stream.language ? { language: stream.language } : {}),
              ...(stream.title ? { title: stream.title } : {}),
              default: stream.disposition.default ?? false,
              forced: stream.disposition.forced ?? false,
            },
          ]
        : []
    ) ?? [];

  const quickBusy =
    engineState.status === 'loading' ||
    engineState.status === 'recovering' ||
    sourceProbeBusy ||
    waveformProgress !== undefined ||
    scheduledPlanCount >= 8;
  const sourceManagementBusy =
    sourceProbeBusy || scheduledPlanCount > 0 || waveformProgress !== undefined;

  const editWorkspace = (
    <>
      <nav
        className="mobile-edit-drawer-controls"
        aria-label="Edit workspace panels"
      >
        <button
          ref={mediaDrawerTrigger}
          className="button button--secondary"
          type="button"
          aria-controls="edit-media-drawer"
          aria-expanded={editDrawer === 'media'}
          onClick={() => setEditDrawer('media')}
        >
          <Icon name="video" />
          Sources
        </button>
        <button
          ref={inspectorDrawerTrigger}
          className="button button--secondary"
          type="button"
          aria-controls="edit-inspector-drawer"
          aria-expanded={editDrawer === 'inspector'}
          onClick={() => setEditDrawer('inspector')}
        >
          <Icon name="edit" />
          Inspector
        </button>
      </nav>
      <div className="edit-grid">
        <section
          id="edit-media-drawer"
          className={`panel media-panel mobile-edit-drawer${editDrawer === 'media' ? ' is-open' : ''}`}
          aria-labelledby="media-bin-title"
        >
          <header className="panel__header">
            <div>
              <p className="eyebrow">Local sources</p>
              <h2 id="media-bin-title">Media bin</h2>
            </div>
            <div className="mobile-edit-drawer__header-actions">
              <span>{assets.length}</span>
              <button
                className="icon-action mobile-edit-drawer__close"
                type="button"
                aria-label="Close media bin"
                onClick={closeEditDrawer}
              >
                <Icon name="cancel" />
              </button>
            </div>
          </header>
          <FileDropZone
            onFiles={addFiles}
            compact
            disabled={sourceManagementBusy}
          />
          <MediaBin
            assets={assets}
            selectedId={selectedAssetId}
            onSelect={setSelectedAssetId}
            onRemove={removeAsset}
          />
        </section>
        <section
          className="panel preview-panel"
          aria-labelledby="preview-title"
        >
          <header className="panel__header">
            <div>
              <p className="eyebrow">Browser playback</p>
              <h2 id="preview-title">Preview</h2>
            </div>
            <span className="privacy-badge">
              <span />
              Object URL
            </span>
          </header>
          <MediaPreview
            asset={inspectedClipAsset}
            result={previewResult}
            waveformPeaks={
              inspectedClipAsset
                ? waveformByAsset[inspectedClipAsset.id]
                : undefined
            }
            onCreateProxy={() => void createPreviewProxy(inspectedClipAsset)}
            proxySettings={previewProxySettings}
            onProxySettingsChange={setPreviewProxySettings}
            proxyBusy={quickBusy}
            {...(inspectedClipAsset
              ? {
                  currentTimeSeconds:
                    playheadByAsset[inspectedClipAsset.id] ?? 0,
                  onCurrentTimeChange: (timeSeconds: number) =>
                    setPlayheadByAsset((current) => ({
                      ...current,
                      [inspectedClipAsset.id]: timeSeconds,
                    })),
                }
              : {})}
          />
        </section>
        <Inspector
          asset={inspectedClipAsset}
          project={project}
          clip={selectedClip}
          disabled={sourceManagementBusy}
          onClipUpdate={(changes) => {
            if (selectedClip) updateClip(selectedClip.id, changes);
          }}
          onMetadataChange={(metadata) =>
            applyProjectAction({
              type: 'metadata/set',
              metadata,
              updatedAt: timestamp(),
            })
          }
          onChaptersChange={(chapters) =>
            applyProjectAction({
              type: 'chapters/set',
              chapters,
              updatedAt: timestamp(),
            })
          }
          onSubtitlesChange={changeSubtitles}
          onSubtitleImport={importSubtitleFile}
          onThumbnail={extractThumbnail}
          currentPreviewTimeSeconds={
            inspectedClipAsset
              ? (playheadByAsset[inspectedClipAsset.id] ?? 0)
              : undefined
          }
          drawerOpen={editDrawer === 'inspector'}
          onDrawerClose={closeEditDrawer}
        />
      </div>
      <Timeline
        project={project}
        selectedClipId={selectedClipId}
        {...(selectedClip
          ? {
              waveformPeaks: waveformByAsset[selectedClip.assetId],
              splitMarkers: splitMarkersByAsset[selectedClip.assetId] ?? [],
            }
          : {})}
        waveformDisabled={sourceManagementBusy}
        currentTimeSeconds={
          selectedClip
            ? (playheadByAsset[selectedClip.assetId] ?? 0)
            : undefined
        }
        onSeek={(timeSeconds) => {
          if (!selectedClip) return;
          setPlayheadByAsset((current) => ({
            ...current,
            [selectedClip.assetId]: timeSeconds,
          }));
        }}
        onSelect={(clipId) => {
          setSelectedClipId(clipId);
          const clip = project.timeline.find((entry) => entry.id === clipId);
          if (clip) setSelectedAssetId(clip.assetId);
        }}
        onMove={moveClip}
        onUpdate={updateClip}
        onSelectionChange={(selection) => {
          if (!selectedClip) return;
          setSplitMarkersByAsset((current) => ({
            ...current,
            [selectedClip.assetId]: selection.markers,
          }));
        }}
        onRemove={(clipId) => {
          applyProjectAction({
            type: 'clip/remove',
            clipId,
            updatedAt: timestamp(),
          });
          if (selectedClipId === clipId) setSelectedClipId(undefined);
        }}
      />
      <StructuralOperations
        {...(structuralSelectedClip
          ? { selectedClip: structuralSelectedClip }
          : {})}
        {...(project.timeline.length >= 2
          ? {
              timeline: {
                clips: structuralContext.clips,
                fastTargetExtension: structuralContext.fastTargetExtension,
                fastTargetMuxer: structuralContext.fastTargetMuxer,
                fastCompatibilityDiagnostics: structuralContext.diagnostics,
              },
            }
          : {})}
        exportPresets={advancedPresetOptions}
        availability={structuralAvailability}
        busy={quickBusy}
        onTrim={handleStructuralTrim}
        onConcat={handleStructuralConcat}
      />
      <AdvancedOperations
        {...(advancedSource ? { source: advancedSource } : {})}
        splitMarkers={
          inspectedClipAsset
            ? (splitMarkersByAsset[inspectedClipAsset.id] ?? [])
            : []
        }
        {...(splitBatch ? { splitBatch } : {})}
        chapters={advancedChapters}
        timelineClips={advancedTimelineClips}
        metadataStreams={advancedMetadataStreams}
        {...(inspectedClipAsset?.probe
          ? { metadataFormatTags: inspectedClipAsset.probe.tags }
          : {})}
        subtitleStreams={advancedSubtitleStreams}
        {...(inspectedClipAsset && loudnessByAsset[inspectedClipAsset.id]
          ? {
              loudnessMeasurement: loudnessByAsset[inspectedClipAsset.id],
            }
          : {})}
        exportPresets={advancedPresetOptions}
        userPresets={userPresets}
        availability={advancedAvailability}
        imageFormatAvailability={{
          png: capabilityStatus({
            muxers: ['image2'],
            encoders: ['png'],
          }),
          jpeg: capabilityStatus({
            muxers: ['image2'],
            encoders: ['mjpeg'],
          }),
          webp: capabilityStatus({
            muxers: ['webp'],
            encoders: ['libwebp'],
          }),
        }}
        subtitleFormatAvailability={{
          srt: capabilityStatus({
            muxers: ['srt'],
            encoders: ['srt'],
          }),
          vtt: capabilityStatus({
            muxers: ['webvtt'],
            encoders: ['webvtt'],
          }),
          ass: capabilityStatus({
            muxers: ['ass'],
            encoders: ['ass'],
          }),
        }}
        subtitleContainerAvailability={{
          matroska: capabilityStatus({ muxers: ['matroska'] }),
          mp4: capabilityStatus({
            muxers: ['mp4'],
            encoders: ['mov_text'],
          }),
          webm: capabilityStatus({
            muxers: ['webm'],
            encoders: ['webvtt'],
          }),
        }}
        busy={quickBusy}
        onSplit={handleAdvancedSplit}
        onAudioAction={handleAdvancedAudio}
        onThumbnailSeries={handleThumbnailSeries}
        onContactSheet={handleContactSheet}
        onMetadataAction={handleMetadataAction}
        onChapterAction={handleChapterAction}
        onSubtitleAction={handleSubtitleAction}
        onUserPresetAction={handleUserPresetAction}
      />
      <section className="panel edit-export">
        <header>
          <p className="eyebrow">Timeline export</p>
          <h2>Render the sequence</h2>
          <p>
            Normalize the sequential clips to these explicit typed settings. The
            source files remain local.
          </p>
        </header>
        <div className="edit-export__settings">
          <label className="field">
            <span>Timeline export preset</span>
            <select
              value={project.output.presetId}
              disabled={sourceManagementBusy}
              onChange={(event) => {
                const preset = resolvePreset(event.currentTarget.value);
                if (!preset?.video) return;
                const channels = preset.audio?.channels;
                const next: OutputSettings = {
                  ...project.output,
                  presetId: preset.id,
                  container: preset.container,
                  fileName: safeExportFileName(project.output.fileName, {
                    extension: preset.fileExtension,
                    fallback: 'timeline',
                  }),
                  videoEnabled: true,
                  audioEnabled: preset.audio !== undefined,
                  sampleRate:
                    preset.audio?.sampleRate ??
                    project.output.sampleRate ??
                    48_000,
                  channelLayout:
                    channels === 1 ? 'mono' : channels === 6 ? '5.1' : 'stereo',
                };
                applyProjectAction({
                  type: 'output/set',
                  output: next,
                  updatedAt: timestamp(),
                });
              }}
            >
              {!timelinePresetOptions.some(
                (option) => option.id === project.output.presetId
              ) ? (
                <option value="">Choose a video preset</option>
              ) : null}
              {timelinePresetOptions.map((option) => (
                <option
                  key={option.id}
                  value={option.id}
                  disabled={Boolean(option.disabledReason)}
                >
                  {option.name}
                  {option.disabledReason ? ` — ${option.disabledReason}` : ''}
                </option>
              ))}
            </select>
          </label>
          <label className="field">
            <span>Output filename</span>
            <input
              type="text"
              maxLength={120}
              value={project.output.fileName}
              disabled={sourceManagementBusy}
              onChange={(event) =>
                applyProjectAction({
                  type: 'output/set',
                  output: {
                    ...project.output,
                    fileName: event.currentTarget.value,
                  },
                  updatedAt: timestamp(),
                })
              }
              onBlur={(event) => {
                if (!selectedTimelinePreset) return;
                applyProjectAction({
                  type: 'output/set',
                  output: {
                    ...project.output,
                    fileName: safeExportFileName(event.currentTarget.value, {
                      extension: selectedTimelinePreset.fileExtension,
                      fallback: 'timeline',
                    }),
                  },
                  updatedAt: timestamp(),
                });
              }}
            />
          </label>
          <label className="field">
            <span>Canvas width</span>
            <input
              type="number"
              min="2"
              max="8192"
              step="2"
              placeholder="Auto"
              value={project.output.width ?? ''}
              disabled={sourceManagementBusy}
              onChange={(event) =>
                applyProjectAction({
                  type: 'output/set',
                  output: outputWithOptionalNumber(
                    project.output,
                    'width',
                    event.currentTarget.value
                  ),
                  updatedAt: timestamp(),
                })
              }
            />
          </label>
          <label className="field">
            <span>Canvas height</span>
            <input
              type="number"
              min="2"
              max="8192"
              step="2"
              placeholder="Auto"
              value={project.output.height ?? ''}
              disabled={sourceManagementBusy}
              onChange={(event) =>
                applyProjectAction({
                  type: 'output/set',
                  output: outputWithOptionalNumber(
                    project.output,
                    'height',
                    event.currentTarget.value
                  ),
                  updatedAt: timestamp(),
                })
              }
            />
          </label>
          <label className="field">
            <span>Output frame rate</span>
            <input
              type="number"
              list="timeline-frame-rates"
              min="0.01"
              max="240"
              step="0.001"
              placeholder="Source"
              value={project.output.frameRate ?? ''}
              disabled={sourceManagementBusy}
              onChange={(event) =>
                applyProjectAction({
                  type: 'output/set',
                  output: outputWithOptionalNumber(
                    project.output,
                    'frameRate',
                    event.currentTarget.value
                  ),
                  updatedAt: timestamp(),
                })
              }
            />
            <datalist id="timeline-frame-rates">
              <option value="23.976" />
              <option value="24" />
              <option value="25" />
              <option value="29.97" />
              <option value="30" />
              <option value="50" />
              <option value="59.94" />
              <option value="60" />
            </datalist>
          </label>
          <label className="field">
            <span>Audio sample rate</span>
            <select
              value={project.output.sampleRate ?? 48_000}
              disabled={
                sourceManagementBusy ||
                !project.output.audioEnabled ||
                !selectedTimelinePreset?.audio
              }
              onChange={(event) =>
                applyProjectAction({
                  type: 'output/set',
                  output: {
                    ...project.output,
                    sampleRate: Number(event.currentTarget.value),
                  },
                  updatedAt: timestamp(),
                })
              }
            >
              {[16_000, 22_050, 32_000, 44_100, 48_000, 96_000].map(
                (sampleRate) => (
                  <option key={sampleRate} value={sampleRate}>
                    {sampleRate.toLocaleString('en-US')} Hz
                  </option>
                )
              )}
            </select>
          </label>
          <label className="field">
            <span>Audio layout</span>
            <select
              value={project.output.channelLayout ?? 'stereo'}
              disabled={
                sourceManagementBusy ||
                !project.output.audioEnabled ||
                !selectedTimelinePreset?.audio
              }
              onChange={(event) =>
                applyProjectAction({
                  type: 'output/set',
                  output: {
                    ...project.output,
                    channelLayout: event.currentTarget.value as
                      'mono' | 'stereo' | '5.1',
                  },
                  updatedAt: timestamp(),
                })
              }
            >
              <option value="mono">Mono</option>
              <option value="stereo">Stereo</option>
              <option value="5.1">5.1</option>
            </select>
          </label>
          <label className="field">
            <span>Clips without audio</span>
            <select
              value={project.output.missingAudioPolicy ?? 'insert-silence'}
              disabled={
                sourceManagementBusy ||
                !project.output.audioEnabled ||
                !selectedTimelinePreset?.audio
              }
              onChange={(event) =>
                applyProjectAction({
                  type: 'output/set',
                  output: {
                    ...project.output,
                    missingAudioPolicy: event.currentTarget.value as
                      'insert-silence' | 'drop-all' | 'reject',
                  },
                  updatedAt: timestamp(),
                })
              }
            >
              <option value="insert-silence">Insert silence</option>
              <option value="drop-all">Drop all timeline audio</option>
              <option value="reject">Reject mixed-audio timeline</option>
            </select>
          </label>
          <label className="check-field edit-export__audio-toggle">
            <input
              type="checkbox"
              checked={
                project.output.audioEnabled &&
                selectedTimelinePreset?.audio !== undefined
              }
              disabled={sourceManagementBusy || !selectedTimelinePreset?.audio}
              onChange={(event) =>
                applyProjectAction({
                  type: 'output/set',
                  output: {
                    ...project.output,
                    audioEnabled: event.currentTarget.checked,
                  },
                  updatedAt: timestamp(),
                })
              }
            />
            <span>Include timeline audio</span>
          </label>
        </div>
        <footer>
          <p>
            Empty canvas dimensions preserve the first transformed clip up to
            1920×1080 without upscaling. Video is required for this sequential
            timeline renderer.
          </p>
          <div>
            {timelineOutputReason ? (
              <small id="timeline-output-reason">{timelineOutputReason}</small>
            ) : null}
            <button
              className="button button--primary button--large"
              type="button"
              disabled={Boolean(timelineOutputReason) || quickBusy}
              aria-describedby={
                timelineOutputReason ? 'timeline-output-reason' : undefined
              }
              onClick={() => void exportTimeline()}
            >
              <Icon name="sparkles" />
              {engineState.status === 'running' || scheduledPlanCount > 0
                ? 'Add timeline to queue'
                : 'Render timeline'}
            </button>
          </div>
        </footer>
      </section>
    </>
  );

  return (
    <div className="av-app">
      <section className="workspace-toolbar">
        <div className="segmented" role="tablist" aria-label="Workspace mode">
          <button
            type="button"
            role="tab"
            aria-selected={mode === 'quick-convert'}
            className={mode === 'quick-convert' ? 'is-active' : ''}
            onClick={() => selectWorkspaceMode('quick-convert')}
          >
            <Icon name="sparkles" />
            Quick Convert
          </button>
          <button
            type="button"
            role="tab"
            aria-selected={mode === 'edit'}
            className={mode === 'edit' ? 'is-active' : ''}
            onClick={() => selectWorkspaceMode('edit')}
          >
            <Icon name="edit" />
            Edit
          </button>
        </div>
        <div className="project-actions">
          <span title={project.name}>{project.name}</span>
          <button
            className="button button--quiet"
            type="button"
            disabled={sourceManagementBusy}
            title={
              sourceManagementBusy
                ? 'Wait for local media operations to finish before replacing the project.'
                : undefined
            }
            onClick={resetProject}
          >
            New
          </button>
          <button
            className="button button--quiet"
            type="button"
            disabled={sourceManagementBusy}
            title={
              sourceManagementBusy
                ? 'Wait for local media operations to finish before replacing the project.'
                : undefined
            }
            onClick={() => projectInput.current?.click()}
          >
            Open project
          </button>
          <button
            className="button button--quiet"
            type="button"
            onClick={exportProject}
          >
            Save project
          </button>
          <input
            ref={projectInput}
            className="visually-hidden"
            type="file"
            accept=".json,.avproject"
            disabled={sourceManagementBusy}
            onChange={(event) => {
              const file = event.currentTarget.files?.[0];
              if (file) void importProject(file);
              event.currentTarget.value = '';
            }}
          />
        </div>
      </section>

      {projectNotice ? (
        <p className="project-notice" role="status">
          <Icon name="info" />
          {projectNotice}
        </p>
      ) : null}

      {waveformProgress !== undefined ? (
        <section
          className="project-notice waveform-progress"
          aria-label="Waveform peak aggregation progress"
        >
          <Icon name="audio" />
          <span>
            Building bounded waveform peaks locally…{' '}
            {Math.round(waveformProgress * 100)}%
          </span>
          <progress value={waveformProgress} max="1" />
          <button
            className="button button--danger"
            type="button"
            onClick={() => waveformRuntime.cancelActive()}
          >
            Cancel waveform
          </button>
        </section>
      ) : null}

      {mode === 'quick-convert' ? (
        <div className="quick-workspace">
          <div className="quick-workspace__source">
            <FileDropZone onFiles={addFiles} disabled={sourceManagementBusy} />
            {assets.length > 0 ? (
              <section className="panel quick-media">
                <header className="panel__header">
                  <div>
                    <p className="eyebrow">Imported locally</p>
                    <h2>Sources</h2>
                  </div>
                  <span>{assets.length}</span>
                </header>
                <MediaBin
                  assets={assets}
                  selectedId={selectedAssetId}
                  onSelect={setSelectedAssetId}
                  onRemove={removeAsset}
                />
              </section>
            ) : null}
          </div>
          <QuickConvert
            asset={selectedAsset}
            engineState={engineState}
            busy={quickBusy}
            queueing={
              engineState.status === 'running' || scheduledPlanCount > 0
            }
            presets={[...BUILT_IN_PRESETS, ...userPresets]}
            onExport={exportQuick}
          />
          <section className="panel quick-preview">
            <header className="panel__header">
              <div>
                <p className="eyebrow">Source or latest result</p>
                <h2>Preview</h2>
              </div>
            </header>
            <MediaPreview
              asset={selectedAsset}
              result={previewResult}
              waveformPeaks={
                selectedAsset ? waveformByAsset[selectedAsset.id] : undefined
              }
              onCreateProxy={() => void createPreviewProxy(selectedAsset)}
              proxySettings={previewProxySettings}
              onProxySettingsChange={setPreviewProxySettings}
              proxyBusy={quickBusy}
              {...(selectedAsset
                ? {
                    currentTimeSeconds: playheadByAsset[selectedAsset.id] ?? 0,
                    onCurrentTimeChange: (timeSeconds: number) =>
                      setPlayheadByAsset((current) => ({
                        ...current,
                        [selectedAsset.id]: timeSeconds,
                      })),
                  }
                : {})}
            />
          </section>
        </div>
      ) : (
        editWorkspace
      )}

      <JobPanel
        engineState={engineState}
        jobs={scheduledJobs}
        results={results}
        selectedResultId={previewResultId}
        verifications={outputVerifications}
        report={latestReport}
        logs={logs}
        error={operationError}
        queuedCount={Math.max(
          0,
          scheduledPlanCount -
            (engineState.status === 'running' ||
            engineState.status === 'loading' ||
            engineState.status === 'recovering'
              ? 1
              : 0)
        )}
        onCancel={() => {
          const activeJobId = activeScheduledJobIdRef.current;
          if (activeJobId) void cancelScheduledJob(activeJobId);
          else void engineManager.cancelActive();
        }}
        onCancelJob={(job) => void cancelScheduledJob(job.id)}
        onRetryJob={(job) => retryScheduledJob(job.id)}
        onClearJobHistory={clearScheduledJobHistory}
        onSave={(output) => void saveManagedResult(output)}
        onSaveZip={(selected) => void saveManagedZip(selected)}
        onSaveReport={() => void saveManagedReport()}
        onPreview={(output) => setPreviewResultId(output.id)}
        onRemove={(output) => {
          resultCollection.remove(output.id);
          refreshResults();
        }}
        onClearResults={clearResult}
      />
      <CapabilityPanel
        state={engineState}
        preference={enginePreference}
        resourcePolicy={resourceContext.policy}
        deviceMemoryGiB={resourceContext.deviceMemoryGiB}
        onPreferenceChange={(preference) => {
          setEnginePreference(preference);
          engineManager.setPreference(preference);
        }}
        onInitialize={() => {
          if (engineManager.state.status === 'error') {
            engineManager.dispose();
          }
          void engineManager.initialize().catch(() => undefined);
        }}
      />
      <StoragePanel projectId={project.id} />
    </div>
  );
}

export default function App() {
  const [helpOpen, setHelpOpen] = useState(false);
  return (
    <AppErrorBoundary>
      <AppShell
        app={manifest}
        manifestUrl="./toolbox-app.json"
        helpAction={{ onClick: () => setHelpOpen(true) }}
        onContextError={(error) => {
          console.warn(
            'Toolbox context unavailable; continuing standalone.',
            error
          );
        }}
      >
        <AvToolsApplication />
      </AppShell>
      <HelpDialog open={helpOpen} onClose={() => setHelpOpen(false)} />
    </AppErrorBoundary>
  );
}
