'use client';

import * as React from 'react';
import { Music, Plus, Upload, Trash2, Settings, Download, FolderOpen } from 'lucide-react';
import { PlaybackControls } from './PlaybackControls';
import { MasterControls } from '@/components/controls/MasterControls';
import { ThemeToggle } from '@/components/layout/ThemeToggle';
import { CommandPalette } from '@/components/ui/CommandPalette';
import { BrowserCompatDialog } from '@/components/dialogs/BrowserCompatDialog';
import { Button } from '@/components/ui/Button';
import type { CommandAction } from '@/components/ui/CommandPalette';
import { useMultiTrack } from '@/lib/hooks/useMultiTrack';
import { useMultiTrackPlayer } from '@/lib/hooks/useMultiTrackPlayer';
import { useEffectChain } from '@/lib/hooks/useEffectChain';
import { useToast } from '@/components/ui/Toast';
import { TrackList } from '@/components/tracks/TrackList';
import type { ExportSettings } from '@/components/dialogs/ExportDialog';

// Lazy load dialogs for better performance
const GlobalSettingsDialog = React.lazy(() => import('@/components/settings/GlobalSettingsDialog').then(m => ({ default: m.GlobalSettingsDialog })));
const ExportDialog = React.lazy(() => import('@/components/dialogs/ExportDialog').then(m => ({ default: m.ExportDialog })));
const ProjectsDialog = React.lazy(() => import('@/components/dialogs/ProjectsDialog').then(m => ({ default: m.ProjectsDialog })));
const ImportTrackDialog = React.lazy(() => import('@/components/tracks/ImportTrackDialog').then(m => ({ default: m.ImportTrackDialog })));
const KeyboardShortcutsDialog = React.lazy(() => import('@/components/dialogs/KeyboardShortcutsDialog').then(m => ({ default: m.KeyboardShortcutsDialog })));
const MarkerTimeline = React.lazy(() => import('@/components/markers/MarkerTimeline').then(m => ({ default: m.MarkerTimeline })));
const MarkerDialog = React.lazy(() => import('@/components/markers/MarkerDialog').then(m => ({ default: m.MarkerDialog })));
const TimeScale = React.lazy(() => import('@/components/timeline/TimeScale').then(m => ({ default: m.TimeScale })));

// Lazy load analysis components (shown conditionally based on analyzerView)
const FrequencyAnalyzer = React.lazy(() => import('@/components/analysis/FrequencyAnalyzer').then(m => ({ default: m.FrequencyAnalyzer })));
const Spectrogram = React.lazy(() => import('@/components/analysis/Spectrogram').then(m => ({ default: m.Spectrogram })));
const PhaseCorrelationMeter = React.lazy(() => import('@/components/analysis/PhaseCorrelationMeter').then(m => ({ default: m.PhaseCorrelationMeter })));
const LUFSMeter = React.lazy(() => import('@/components/analysis/LUFSMeter').then(m => ({ default: m.LUFSMeter })));
const AudioStatistics = React.lazy(() => import('@/components/analysis/AudioStatistics').then(m => ({ default: m.AudioStatistics })));
import { formatDuration } from '@/lib/audio/decoder';
import { useHistory } from '@/lib/hooks/useHistory';
import { useRecording } from '@/lib/hooks/useRecording';
import { useSettings } from '@/lib/hooks/useSettings';
import { useMarkers } from '@/lib/hooks/useMarkers';
import { DEFAULT_TRACK_HEIGHT } from '@/types/track';
import type { EffectType } from '@/lib/audio/effects/chain';
import type { Marker } from '@/types/marker';
import {
  createMultiTrackCutCommand,
  createMultiTrackCopyCommand,
  createMultiTrackDeleteCommand,
  createMultiTrackPasteCommand,
  createMultiTrackDuplicateCommand,
} from '@/lib/history/commands/multi-track-edit-command';
import { extractBufferSegment } from '@/lib/audio/buffer-utils';
import { mixTracks, getMaxTrackDuration } from '@/lib/audio/track-utils';
import { audioBufferToWav, audioBufferToMp3, downloadArrayBuffer } from '@/lib/audio/export';
import {
  saveCurrentProject,
  loadProjectById,
  listProjects,
  removeProject,
  duplicateProject,
  exportProjectAsJSON,
  importProjectFromJSON,
  type ProjectMetadata,
} from '@/lib/storage/projects';
import { getAudioContext } from '@/lib/audio/context';
import { checkBrowserCompatibility } from '@/lib/utils/browser-compat';

export function AudioEditor() {
  // Settings hook
  const {
    settings,
    updateAudioSettings,
    updateUISettings,
    updateEditorSettings,
    updatePerformanceSettings,
    resetCategory,
  } = useSettings();

  const [importDialogOpen, setImportDialogOpen] = React.useState(false);
  const [selectedTrackId, setSelectedTrackId] = React.useState<string | null>(null);
  const [zoom, setZoom] = React.useState(settings.editor.defaultZoom);
  const [masterVolume, setMasterVolume] = React.useState(0.8);
  const [masterPan, setMasterPan] = React.useState(0);
  const [isMasterMuted, setIsMasterMuted] = React.useState(false);
  const [masterControlsCollapsed, setMasterControlsCollapsed] = React.useState(false);
  const [clipboard, setClipboard] = React.useState<AudioBuffer | null>(null);
  const [automationClipboard, setAutomationClipboard] = React.useState<{ points: Array<{ time: number; value: number; curve: string }> } | null>(null);
  const [recordingTrackId, setRecordingTrackId] = React.useState<string | null>(null);
  const [punchInEnabled, setPunchInEnabled] = React.useState(false);
  const [punchInTime, setPunchInTime] = React.useState(0);
  const [punchOutTime, setPunchOutTime] = React.useState(0);
  const [overdubEnabled, setOverdubEnabled] = React.useState(false);
  const [settingsDialogOpen, setSettingsDialogOpen] = React.useState(false);
  const [exportDialogOpen, setExportDialogOpen] = React.useState(false);
  const [isExporting, setIsExporting] = React.useState(false);
  const [analyzerView, setAnalyzerView] = React.useState<'frequency' | 'spectrogram' | 'phase' | 'lufs' | 'stats'>('frequency');

  // Switch away from spectrogram if it gets disabled
  React.useEffect(() => {
    if (analyzerView === 'spectrogram' && !settings.performance.enableSpectrogram) {
      setAnalyzerView('frequency');
    }
  }, [analyzerView, settings.performance.enableSpectrogram]);
  const [projectsDialogOpen, setProjectsDialogOpen] = React.useState(false);
  const [projects, setProjects] = React.useState<ProjectMetadata[]>([]);
  const [currentProjectId, setCurrentProjectId] = React.useState<string | null>(null);
  const [currentProjectName, setCurrentProjectName] = React.useState('Untitled Project');
  const [browserCompatDialogOpen, setBrowserCompatDialogOpen] = React.useState(false);
  const [shortcutsDialogOpen, setShortcutsDialogOpen] = React.useState(false);
  const [browserCompatInfo, setBrowserCompatInfo] = React.useState<{
    missingFeatures: string[];
    warnings: string[];
  }>({ missingFeatures: [], warnings: [] });

  const { addToast } = useToast();

  // Markers hook
  const {
    markers,
    addMarker,
    updateMarker,
    removeMarker,
    getNextMarker,
    getPreviousMarker,
  } = useMarkers();

  const [markerDialogOpen, setMarkerDialogOpen] = React.useState(false);
  const [editingMarker, setEditingMarker] = React.useState<Marker | undefined>(undefined);

  // Command history for undo/redo
  const { execute: executeCommand, undo, redo, state: historyState } = useHistory();
  const canUndo = historyState.canUndo;
  const canRedo = historyState.canRedo;

  // Recording hook
  const {
    state: recordingState,
    settings: recordingSettings,
    startRecording,
    stopRecording,
    requestPermission,
    setInputGain,
    setRecordMono,
    setSampleRate,
  } = useRecording();

  // Sync recording sample rate with global settings
  React.useEffect(() => {
    setSampleRate(settings.audio.sampleRate);
  }, [settings.audio.sampleRate, setSampleRate]);

  // Multi-track hooks
  const {
    tracks,
    addTrack: addTrackOriginal,
    addTrackFromBuffer: addTrackFromBufferOriginal,
    removeTrack,
    updateTrack,
    clearTracks,
    loadTracks,
  } = useMultiTrack();

  // Track whether we should auto-select on next add (when project is empty)
  const shouldAutoSelectRef = React.useRef(true);

  React.useEffect(() => {
    // Update auto-select flag based on track count
    shouldAutoSelectRef.current = tracks.length === 0;
  }, [tracks.length]);

  // Wrap addTrack to auto-select first track when adding to empty project
  const addTrack = React.useCallback((name?: string) => {
    const shouldAutoSelect = shouldAutoSelectRef.current;
    const track = addTrackOriginal(name, DEFAULT_TRACK_HEIGHT);
    if (shouldAutoSelect) {
      setSelectedTrackId(track.id);
      shouldAutoSelectRef.current = false; // Only auto-select once
    }
    return track;
  }, [addTrackOriginal]);

  // Wrap addTrackFromBuffer to auto-select first track when adding to empty project
  const addTrackFromBuffer = React.useCallback((buffer: AudioBuffer, name?: string) => {
    console.log(`[AudioEditor] addTrackFromBuffer wrapper called: ${name}, shouldAutoSelect: ${shouldAutoSelectRef.current}`);
    const shouldAutoSelect = shouldAutoSelectRef.current;
    const track = addTrackFromBufferOriginal(buffer, name, DEFAULT_TRACK_HEIGHT);
    console.log(`[AudioEditor] Track created: ${track.name} (${track.id})`);
    if (shouldAutoSelect) {
      console.log(`[AudioEditor] Auto-selecting track: ${track.id}`);
      setSelectedTrackId(track.id);
      shouldAutoSelectRef.current = false; // Only auto-select once
    }
    return track;
  }, [addTrackFromBufferOriginal]);

  // Track which parameters are being touched (for touch/latch modes)
  const [touchedParameters, setTouchedParameters] = React.useState<Set<string>>(new Set());
  const [latchTriggered, setLatchTriggered] = React.useState<Set<string>>(new Set());

  // Track last recorded values to detect changes
  const lastRecordedValuesRef = React.useRef<Map<string, { value: number; time: number }>>(new Map());

  // Time scale scroll synchronization
  const timeScaleScrollRef = React.useRef<HTMLDivElement | null>(null);
  const timeScaleScrollHandlerRef = React.useRef<(() => void) | null>(null);

  const handleTimeScaleScroll = React.useCallback(() => {
    if (timeScaleScrollHandlerRef.current) {
      timeScaleScrollHandlerRef.current();
    }
  }, []);

  // Automation recording callback
  const handleAutomationRecording = React.useCallback((
    trackId: string,
    laneId: string,
    currentTime: number,
    value: number
  ) => {
    const track = tracks.find(t => t.id === trackId);
    if (!track) return;

    const lane = track.automation.lanes.find(l => l.id === laneId);
    if (!lane) return;

    const paramKey = `${trackId}-${laneId}`;
    let shouldRecord = false;

    // Determine if we should record based on mode
    switch (lane.mode) {
      case 'write':
        // Always record in write mode
        shouldRecord = true;
        break;

      case 'touch':
        // Only record when parameter is being touched
        shouldRecord = touchedParameters.has(paramKey);
        break;

      case 'latch':
        // Record from first touch until stop
        if (touchedParameters.has(paramKey)) {
          setLatchTriggered(prev => new Set(prev).add(paramKey));
        }
        shouldRecord = latchTriggered.has(paramKey);
        break;

      default:
        shouldRecord = false;
    }

    if (!shouldRecord) return;

    // Throttle recording to avoid creating too many automation points
    // This doesn't prevent recording, just limits frequency
    const lastRecorded = lastRecordedValuesRef.current.get(paramKey);

    if (lastRecorded && currentTime - lastRecorded.time < 0.1) {
      // Check if value has changed significantly
      const valueChanged = Math.abs(lastRecorded.value - value) > 0.001;
      if (!valueChanged) {
        // Skip if value hasn't changed and we recorded recently
        return;
      }
    }

    // Update last recorded value
    lastRecordedValuesRef.current.set(paramKey, { value, time: currentTime });

    // Create new automation point
    const newPoint = {
      id: `point-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
      time: currentTime,
      value,
      curve: 'linear' as const,
    };

    // In write mode, remove existing points near this time (overwrites)
    const updatedPoints = lane.mode === 'write'
      ? [...lane.points.filter(p => Math.abs(p.time - currentTime) > 0.05), newPoint]
      : [...lane.points, newPoint];

    updatedPoints.sort((a, b) => a.time - b.time);

    // Update the lane with new points
    const updatedLanes = track.automation.lanes.map(l =>
      l.id === laneId ? { ...l, points: updatedPoints } : l
    );

    updateTrack(trackId, {
      automation: {
        ...track.automation,
        lanes: updatedLanes,
      },
    });
  }, [tracks, updateTrack, touchedParameters, latchTriggered]);

  // Helper to mark parameter as touched (for touch/latch modes)
  const setParameterTouched = React.useCallback((trackId: string, laneId: string, touched: boolean) => {
    const paramKey = `${trackId}-${laneId}`;
    setTouchedParameters(prev => {
      const next = new Set(prev);
      if (touched) {
        next.add(paramKey);
      } else {
        next.delete(paramKey);
      }
      return next;
    });
  }, []);

  const {
    isPlaying,
    currentTime,
    duration,
    trackLevels,
    masterPeakLevel,
    masterRmsLevel,
    masterIsClipping,
    masterAnalyser,
    resetClipIndicator,
    play,
    pause,
    stop,
    seek,
    togglePlayPause,
    loopEnabled,
    loopStart,
    loopEnd,
    toggleLoop,
    setLoopPoints,
    setLoopFromSelection,
    playbackRate,
    changePlaybackRate,
  } = useMultiTrackPlayer(tracks, masterVolume, handleAutomationRecording);

  // Reset latch triggered state when playback stops
  React.useEffect(() => {
    if (!isPlaying) {
      setLatchTriggered(new Set());
      lastRecordedValuesRef.current.clear();
    }
  }, [isPlaying]);

  // Record effect parameter values while touched
  React.useEffect(() => {
    if (!isPlaying) return;

    const recordEffectParams = () => {
      const time = currentTime;

      touchedParameters.forEach(paramKey => {
        const [trackId, laneId] = paramKey.split('-');
        const track = tracks.find(t => t.id === trackId);
        if (!track) return;

        const lane = track.automation.lanes.find(l => l.id === laneId);
        if (!lane || !lane.parameterId.startsWith('effect.')) return;

        // Parse effect parameter ID: effect.{effectId}.{paramName}
        const parts = lane.parameterId.split('.');
        if (parts.length !== 3) return;

        const effectId = parts[1];
        const paramName = parts[2];

        const effect = track.effectChain.effects.find(e => e.id === effectId);
        if (!effect || !effect.parameters) return;

        const currentValue = (effect.parameters as any)[paramName];
        if (currentValue === undefined) return;

        // Normalize value to 0-1 range
        const range = lane.valueRange.max - lane.valueRange.min;
        const normalizedValue = (currentValue - lane.valueRange.min) / range;

        // Record the automation
        handleAutomationRecording(trackId, laneId, time, normalizedValue);
      });
    };

    const interval = setInterval(recordEffectParams, 50); // Record every 50ms while touched
    return () => clearInterval(interval);
  }, [isPlaying, currentTime, touchedParameters, tracks, handleAutomationRecording]);

  // Master effect chain
  const {
    chain: masterEffectChain,
    presets: masterEffectPresets,
    toggleEffectEnabled: toggleMasterEffect,
    removeEffect: removeMasterEffect,
    reorder: reorderMasterEffects,
    clearChain: clearMasterChain,
    savePreset: saveMasterPreset,
    loadPresetToChain: loadMasterPreset,
    deletePreset: deleteMasterPreset,
  } = useEffectChain();

  // Multi-track handlers
  const handleImportTracks = () => {
    setImportDialogOpen(true);
  };

  const handleImportTrack = (buffer: AudioBuffer, name: string) => {
    console.log(`[AudioEditor] handleImportTrack called: ${name}`);
    addTrackFromBuffer(buffer, name);
  };

  const handleClearTracks = () => {
    clearTracks();
    setSelectedTrackId(null);
    addToast({
      title: 'Tracks Cleared',
      description: 'All tracks have been removed',
      variant: 'info',
      duration: 2000,
    });
  };

  const handleRemoveTrack = (trackId: string) => {
    removeTrack(trackId);
    if (selectedTrackId === trackId) {
      setSelectedTrackId(null);
    }
  };

  // Per-track effect chain handlers
  const handleToggleTrackEffect = (effectId: string) => {
    if (!selectedTrack) return;
    const updatedChain = {
      ...selectedTrack.effectChain,
      effects: selectedTrack.effectChain.effects.map((e) =>
        e.id === effectId ? { ...e, enabled: !e.enabled } : e
      ),
    };
    updateTrack(selectedTrack.id, { effectChain: updatedChain });
  };

  const handleRemoveTrackEffect = (effectId: string) => {
    if (!selectedTrack) return;
    const updatedChain = {
      ...selectedTrack.effectChain,
      effects: selectedTrack.effectChain.effects.filter((e) => e.id !== effectId),
    };
    updateTrack(selectedTrack.id, { effectChain: updatedChain });
  };

  const handleReorderTrackEffects = (fromIndex: number, toIndex: number) => {
    if (!selectedTrack) return;
    const effects = [...selectedTrack.effectChain.effects];
    const [removed] = effects.splice(fromIndex, 1);
    effects.splice(toIndex, 0, removed);
    const updatedChain = {
      ...selectedTrack.effectChain,
      effects,
    };
    updateTrack(selectedTrack.id, { effectChain: updatedChain });
  };

  const handleClearTrackChain = () => {
    if (!selectedTrack) return;
    const updatedChain = {
      ...selectedTrack.effectChain,
      effects: [],
    };
    updateTrack(selectedTrack.id, { effectChain: updatedChain });
  };

  // Effects Panel handlers
  const handleAddEffect = React.useCallback((effectType: EffectType) => {
    if (!selectedTrackId) return;
    const track = tracks.find((t) => t.id === selectedTrackId);
    if (!track) return;

    // Import createEffect and EFFECT_NAMES dynamically
    import('@/lib/audio/effects/chain').then(({ createEffect, EFFECT_NAMES }) => {
      const newEffect = createEffect(effectType, EFFECT_NAMES[effectType]);
      const updatedChain = {
        ...track.effectChain,
        effects: [...track.effectChain.effects, newEffect],
      };
      updateTrack(selectedTrackId, { effectChain: updatedChain });
    });
  }, [selectedTrackId, tracks, updateTrack]);

  const handleToggleEffect = React.useCallback((effectId: string) => {
    if (!selectedTrackId) return;
    const track = tracks.find((t) => t.id === selectedTrackId);
    if (!track) return;

    const updatedChain = {
      ...track.effectChain,
      effects: track.effectChain.effects.map((e) =>
        e.id === effectId ? { ...e, enabled: !e.enabled } : e
      ),
    };
    updateTrack(selectedTrackId, { effectChain: updatedChain });
  }, [selectedTrackId, tracks, updateTrack]);

  const handleRemoveEffect = React.useCallback((effectId: string) => {
    if (!selectedTrackId) return;
    const track = tracks.find((t) => t.id === selectedTrackId);
    if (!track) return;

    const updatedChain = {
      ...track.effectChain,
      effects: track.effectChain.effects.filter((e) => e.id !== effectId),
    };
    updateTrack(selectedTrackId, { effectChain: updatedChain });
  }, [selectedTrackId, tracks, updateTrack]);

  const handleUpdateEffect = React.useCallback((effectId: string, parameters: any) => {
    if (!selectedTrackId) return;
    const track = tracks.find((t) => t.id === selectedTrackId);
    if (!track) return;

    const updatedChain = {
      ...track.effectChain,
      effects: track.effectChain.effects.map((e) =>
        e.id === effectId ? { ...e, parameters } : e
      ),
    };
    updateTrack(selectedTrackId, { effectChain: updatedChain });
  }, [selectedTrackId, tracks, updateTrack]);

  const handleToggleEffectExpanded = React.useCallback((effectId: string) => {
    if (!selectedTrackId) return;
    const track = tracks.find((t) => t.id === selectedTrackId);
    if (!track) return;

    const updatedChain = {
      ...track.effectChain,
      effects: track.effectChain.effects.map((e) =>
        e.id === effectId ? { ...e, expanded: !e.expanded } : e
      ),
    };
    updateTrack(selectedTrackId, { effectChain: updatedChain });
  }, [selectedTrackId, tracks, updateTrack]);

  // Preserve effects panel state - don't auto-open/close on track selection

  // Selection handler
  const handleSelectionChange = (trackId: string, selection: { start: number; end: number } | null) => {
    updateTrack(trackId, { selection });
  };

  // Recording handlers
  const handleToggleRecordEnable = React.useCallback((trackId: string) => {
    const track = tracks.find((t) => t.id === trackId);
    if (!track) return;

    // Toggle record enable
    updateTrack(trackId, { recordEnabled: !track.recordEnabled });
  }, [tracks, updateTrack]);

  const handleStartRecording = React.useCallback(async () => {
    // Find first armed track
    const armedTrack = tracks.find((t) => t.recordEnabled);
    if (!armedTrack) {
      addToast({
        title: 'No Track Armed',
        description: 'Please arm a track for recording first',
        variant: 'warning',
        duration: 3000,
      });
      return;
    }

    // Request permission if needed
    const hasPermission = await requestPermission();
    if (!hasPermission) {
      addToast({
        title: 'Microphone Access Denied',
        description: 'Please allow microphone access to record',
        variant: 'error',
        duration: 3000,
      });
      return;
    }

    try {
      await startRecording();
      setRecordingTrackId(armedTrack.id);
      addToast({
        title: 'Recording Started',
        description: `Recording to ${armedTrack.name}`,
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      console.error('Failed to start recording:', error);
      addToast({
        title: 'Recording Failed',
        description: 'Failed to start recording',
        variant: 'error',
        duration: 3000,
      });
    }
  }, [tracks, startRecording, requestPermission, addToast]);

  const handleStopRecording = React.useCallback(async () => {
    if (!recordingTrackId) return;

    try {
      const recordedBuffer = await stopRecording();

      if (recordedBuffer) {
        const track = tracks.find((t) => t.id === recordingTrackId);

        // Check if overdub mode is enabled and track has existing audio
        if (overdubEnabled && track?.audioBuffer) {
          // Mix recorded audio with existing audio
          const audioContext = new AudioContext();
          const existingBuffer = track.audioBuffer;

          // Create a new buffer that's long enough for both
          const maxDuration = Math.max(existingBuffer.duration, recordedBuffer.duration);
          const maxChannels = Math.max(existingBuffer.numberOfChannels, recordedBuffer.numberOfChannels);
          const mixedBuffer = audioContext.createBuffer(
            maxChannels,
            Math.floor(maxDuration * existingBuffer.sampleRate),
            existingBuffer.sampleRate
          );

          // Mix each channel
          for (let channel = 0; channel < maxChannels; channel++) {
            const mixedData = mixedBuffer.getChannelData(channel);
            const existingData = channel < existingBuffer.numberOfChannels
              ? existingBuffer.getChannelData(channel)
              : new Float32Array(mixedData.length);
            const recordedData = channel < recordedBuffer.numberOfChannels
              ? recordedBuffer.getChannelData(channel)
              : new Float32Array(mixedData.length);

            // Mix the samples (average them to avoid clipping)
            for (let i = 0; i < mixedData.length; i++) {
              const existingSample = i < existingData.length ? existingData[i] : 0;
              const recordedSample = i < recordedData.length ? recordedData[i] : 0;
              mixedData[i] = (existingSample + recordedSample) / 2;
            }
          }

          updateTrack(recordingTrackId, { audioBuffer: mixedBuffer });

          addToast({
            title: 'Recording Complete (Overdub)',
            description: `Mixed ${recordedBuffer.duration.toFixed(2)}s with existing audio`,
            variant: 'success',
            duration: 3000,
          });
        } else {
          // Normal mode - replace existing audio
          updateTrack(recordingTrackId, { audioBuffer: recordedBuffer });

          addToast({
            title: 'Recording Complete',
            description: `Recorded ${recordedBuffer.duration.toFixed(2)}s of audio`,
            variant: 'success',
            duration: 3000,
          });
        }
      }

      setRecordingTrackId(null);
    } catch (error) {
      console.error('Failed to stop recording:', error);
      addToast({
        title: 'Recording Error',
        description: 'Failed to save recording',
        variant: 'error',
        duration: 3000,
      });
      setRecordingTrackId(null);
    }
  }, [recordingTrackId, stopRecording, updateTrack, addToast, overdubEnabled, tracks]);

  // Edit handlers
  const handleCut = React.useCallback(() => {
    const track = tracks.find((t) => t.selection);
    if (!track || !track.audioBuffer || !track.selection) return;

    // Extract to clipboard
    const extracted = extractBufferSegment(
      track.audioBuffer,
      track.selection.start,
      track.selection.end
    );
    setClipboard(extracted);

    // Ensure the track is selected so paste works
    setSelectedTrackId(track.id);

    // Execute cut command
    const command = createMultiTrackCutCommand(
      track.id,
      track.audioBuffer,
      track.selection,
      (trackId, buffer, selection) => {
        updateTrack(trackId, { audioBuffer: buffer, selection });
      }
    );
    executeCommand(command);

    addToast({
      title: 'Cut',
      description: 'Selection cut to clipboard',
      variant: 'success',
      duration: 2000,
    });
  }, [tracks, executeCommand, updateTrack, addToast]);

  const handleCopy = React.useCallback(() => {
    const track = tracks.find((t) => t.selection);
    if (!track || !track.audioBuffer || !track.selection) return;

    // Extract to clipboard
    const extracted = extractBufferSegment(
      track.audioBuffer,
      track.selection.start,
      track.selection.end
    );
    setClipboard(extracted);

    // Ensure the track is selected so paste works
    setSelectedTrackId(track.id);

    // Execute copy command (doesn't modify buffer, just for undo history)
    const command = createMultiTrackCopyCommand(
      track.id,
      track.audioBuffer,
      track.selection,
      (trackId, buffer, selection) => {
        updateTrack(trackId, { audioBuffer: buffer, selection });
      }
    );
    executeCommand(command);

    addToast({
      title: 'Copy',
      description: 'Selection copied to clipboard',
      variant: 'success',
      duration: 2000,
    });
  }, [tracks, executeCommand, updateTrack, addToast]);

  const handlePaste = React.useCallback(() => {
    if (!clipboard) {
      addToast({
        title: 'Nothing to Paste',
        description: 'Clipboard is empty. Copy or cut a selection first.',
        variant: 'error',
        duration: 2000,
      });
      return;
    }

    if (!selectedTrackId) {
      addToast({
        title: 'No Track Selected',
        description: 'Select a track to paste into.',
        variant: 'error',
        duration: 2000,
      });
      return;
    }

    const track = tracks.find((t) => t.id === selectedTrackId);
    if (!track) return;

    // Paste at current time or at end of buffer
    const pastePosition = currentTime || track.audioBuffer?.duration || 0;

    const command = createMultiTrackPasteCommand(
      track.id,
      track.audioBuffer,
      clipboard,
      pastePosition,
      (trackId, buffer, selection) => {
        updateTrack(trackId, { audioBuffer: buffer, selection });
      }
    );
    executeCommand(command);

    addToast({
      title: 'Paste',
      description: 'Clipboard content pasted',
      variant: 'success',
      duration: 2000,
    });
  }, [clipboard, selectedTrackId, tracks, currentTime, executeCommand, updateTrack, addToast]);

  const handleDelete = React.useCallback(() => {
    const track = tracks.find((t) => t.selection);
    if (!track || !track.audioBuffer || !track.selection) return;

    const command = createMultiTrackDeleteCommand(
      track.id,
      track.audioBuffer,
      track.selection,
      (trackId, buffer, selection) => {
        updateTrack(trackId, { audioBuffer: buffer, selection });
      }
    );
    executeCommand(command);

    addToast({
      title: 'Delete',
      description: 'Selection deleted',
      variant: 'success',
      duration: 2000,
    });
  }, [tracks, executeCommand, updateTrack, addToast]);

  const handleDuplicate = React.useCallback(() => {
    const track = tracks.find((t) => t.selection);
    if (!track || !track.audioBuffer || !track.selection) return;

    const command = createMultiTrackDuplicateCommand(
      track.id,
      track.audioBuffer,
      track.selection,
      (trackId, buffer, selection) => {
        updateTrack(trackId, { audioBuffer: buffer, selection });
      }
    );
    executeCommand(command);

    addToast({
      title: 'Duplicate',
      description: 'Selection duplicated',
      variant: 'success',
      duration: 2000,
    });
  }, [tracks, executeCommand, updateTrack, addToast]);

  const handleSplitAtCursor = React.useCallback(() => {
    if (!selectedTrackId) {
      addToast({
        title: 'No Track Selected',
        description: 'Select a track to split',
        variant: 'error',
        duration: 2000,
      });
      return;
    }

    const track = tracks.find((t) => t.id === selectedTrackId);
    if (!track || !track.audioBuffer) {
      addToast({
        title: 'No Audio',
        description: 'Selected track has no audio to split',
        variant: 'error',
        duration: 2000,
      });
      return;
    }

    const splitTime = currentTime;
    const duration = track.audioBuffer.duration;

    // Can't split at the very beginning or end
    if (splitTime <= 0 || splitTime >= duration) {
      addToast({
        title: 'Invalid Split Position',
        description: 'Cannot split at the beginning or end of the track',
        variant: 'error',
        duration: 2000,
      });
      return;
    }

    // Extract two segments
    const firstSegment = extractBufferSegment(track.audioBuffer, 0, splitTime);
    const secondSegment = extractBufferSegment(track.audioBuffer, splitTime, duration);

    // Create two new tracks
    const trackIndex = tracks.indexOf(track);
    const firstName = `${track.name} (1)`;
    const secondName = `${track.name} (2)`;

    // Add the two new tracks
    addTrackFromBuffer(firstSegment, firstName);
    addTrackFromBuffer(secondSegment, secondName);

    // Remove the original track
    removeTrack(track.id);

    addToast({
      title: 'Track Split',
      description: `Split track at ${formatDuration(splitTime)}`,
      variant: 'success',
      duration: 2000,
    });
  }, [selectedTrackId, tracks, currentTime, addTrackFromBuffer, removeTrack, addToast]);

  const handleCopyAutomation = React.useCallback((trackId: string, laneId: string) => {
    const track = tracks.find((t) => t.id === trackId);
    if (!track) return;

    const lane = track.automation.lanes.find((l) => l.id === laneId);
    if (!lane || lane.points.length === 0) {
      addToast({
        title: 'No Automation Data',
        description: 'Selected automation lane has no points',
        variant: 'error',
        duration: 2000,
      });
      return;
    }

    // Copy the automation points
    setAutomationClipboard({
      points: lane.points.map(p => ({
        time: p.time,
        value: p.value,
        curve: p.curve,
      })),
    });

    addToast({
      title: 'Automation Copied',
      description: `Copied ${lane.points.length} automation point(s)`,
      variant: 'success',
      duration: 2000,
    });
  }, [tracks, addToast]);

  const handlePasteAutomation = React.useCallback((trackId: string, laneId: string) => {
    if (!automationClipboard) {
      addToast({
        title: 'Nothing to Paste',
        description: 'No automation data in clipboard',
        variant: 'error',
        duration: 2000,
      });
      return;
    }

    const track = tracks.find((t) => t.id === trackId);
    if (!track) return;

    const lane = track.automation.lanes.find((l) => l.id === laneId);
    if (!lane) return;

    // Generate new IDs for pasted points and shift them to current time
    const timeOffset = currentTime;
    const newPoints = automationClipboard.points.map((p) => ({
      id: `point-${Date.now()}-${Math.random()}`,
      time: p.time + timeOffset,
      value: p.value,
      curve: p.curve as 'linear' | 'bezier' | 'step',
    }));

    // Merge with existing points and sort by time
    const updatedLanes = track.automation.lanes.map((l) => {
      if (l.id === laneId) {
        return {
          ...l,
          points: [...l.points, ...newPoints].sort((a, b) => a.time - b.time),
        };
      }
      return l;
    });

    updateTrack(trackId, {
      automation: {
        ...track.automation,
        lanes: updatedLanes,
      },
    });

    addToast({
      title: 'Automation Pasted',
      description: `Pasted ${newPoints.length} automation point(s) at ${formatDuration(currentTime)}`,
      variant: 'success',
      duration: 2000,
    });
  }, [automationClipboard, tracks, currentTime, updateTrack, addToast]);

  // Marker handlers
  const handleAddMarker = React.useCallback(() => {
    setEditingMarker(undefined);
    setMarkerDialogOpen(true);
  }, []);

  const handleEditMarker = React.useCallback((marker: Marker) => {
    setEditingMarker(marker);
    setMarkerDialogOpen(true);
  }, []);

  const handleSaveMarker = React.useCallback((markerData: Partial<Marker>) => {
    if (editingMarker) {
      // Update existing marker
      updateMarker(editingMarker.id, markerData);
      addToast({
        title: 'Marker Updated',
        description: `Updated marker "${markerData.name}"`,
        variant: 'success',
        duration: 2000,
      });
    } else {
      // Add new marker
      addMarker(markerData as any);
      addToast({
        title: 'Marker Added',
        description: `Added marker "${markerData.name}"`,
        variant: 'success',
        duration: 2000,
      });
    }
  }, [editingMarker, addMarker, updateMarker, addToast]);

  const handleDeleteMarker = React.useCallback((markerId: string) => {
    removeMarker(markerId);
    addToast({
      title: 'Marker Deleted',
      description: 'Marker removed from timeline',
      variant: 'success',
      duration: 2000,
    });
  }, [removeMarker, addToast]);

  const handleGoToNextMarker = React.useCallback(() => {
    const nextMarker = getNextMarker(currentTime);
    if (nextMarker) {
      seek(nextMarker.time);
    }
  }, [currentTime, getNextMarker, seek]);

  const handleGoToPreviousMarker = React.useCallback(() => {
    const prevMarker = getPreviousMarker(currentTime);
    if (prevMarker) {
      seek(prevMarker.time);
    }
  }, [currentTime, getPreviousMarker, seek]);

  // Export handler
  const handleExport = React.useCallback(async (settings: ExportSettings) => {
    if (tracks.length === 0) {
      addToast({
        title: 'No Tracks',
        description: 'Add some tracks before exporting',
        variant: 'warning',
        duration: 3000,
      });
      return;
    }

    setIsExporting(true);

    try {
      const sampleRate = tracks[0]?.audioBuffer?.sampleRate || 44100;

      // Helper function to convert and download a buffer
      const convertAndDownload = async (buffer: AudioBuffer, filename: string) => {
        let exportedBuffer: ArrayBuffer;
        let mimeType: string;
        let fileExtension: string;

        if (settings.format === 'mp3') {
          exportedBuffer = await audioBufferToMp3(buffer, {
            format: 'mp3',
            bitrate: settings.bitrate,
            normalize: settings.normalize,
          });
          mimeType = 'audio/mpeg';
          fileExtension = 'mp3';
        } else {
          // WAV export
          exportedBuffer = audioBufferToWav(buffer, {
            format: 'wav',
            bitDepth: settings.bitDepth,
            normalize: settings.normalize,
          });
          mimeType = 'audio/wav';
          fileExtension = 'wav';
        }

        const fullFilename = `${filename}.${fileExtension}`;
        downloadArrayBuffer(exportedBuffer, fullFilename, mimeType);
        return fullFilename;
      };

      if (settings.scope === 'tracks') {
        // Export each track individually
        let exportedCount = 0;
        for (const track of tracks) {
          if (!track.audioBuffer) continue;

          const trackFilename = `${settings.filename}_${track.name.replace(/[^a-z0-9]/gi, '_')}`;
          await convertAndDownload(track.audioBuffer, trackFilename);
          exportedCount++;
        }

        addToast({
          title: 'Export Complete',
          description: `Exported ${exportedCount} track${exportedCount !== 1 ? 's' : ''}`,
          variant: 'success',
          duration: 3000,
        });
      } else if (settings.scope === 'selection') {
        // Export selected region
        const selectedTrack = tracks.find(t => t.selection);
        if (!selectedTrack || !selectedTrack.selection) {
          addToast({
            title: 'No Selection',
            description: 'No region selected for export',
            variant: 'warning',
            duration: 3000,
          });
          setIsExporting(false);
          return;
        }

        // Extract selection from all tracks and mix
        const selectionStart = selectedTrack.selection.start;
        const selectionEnd = selectedTrack.selection.end;
        const selectionDuration = selectionEnd - selectionStart;

        // Create tracks with only the selected region
        const selectedTracks = tracks.map(track => ({
          ...track,
          audioBuffer: track.audioBuffer
            ? extractBufferSegment(track.audioBuffer, selectionStart, selectionEnd)
            : null,
        }));

        const mixedBuffer = mixTracks(selectedTracks, sampleRate, selectionDuration);
        const filename = await convertAndDownload(mixedBuffer, settings.filename);

        addToast({
          title: 'Export Complete',
          description: `Exported ${filename}`,
          variant: 'success',
          duration: 3000,
        });
      } else {
        // Export entire project (mix all tracks)
        const maxDuration = getMaxTrackDuration(tracks);
        const mixedBuffer = mixTracks(tracks, sampleRate, maxDuration);
        const filename = await convertAndDownload(mixedBuffer, settings.filename);

        addToast({
          title: 'Export Complete',
          description: `Exported ${filename}`,
          variant: 'success',
          duration: 3000,
        });
      }

      setExportDialogOpen(false);
    } catch (error) {
      console.error('Export failed:', error);
      addToast({
        title: 'Export Failed',
        description: 'Failed to export audio',
        variant: 'error',
        duration: 3000,
      });
    } finally {
      setIsExporting(false);
    }
  }, [tracks, addToast]);

  // Load projects list when dialog opens
  const loadProjectsList = React.useCallback(async () => {
    try {
      const projectsList = await listProjects();
      setProjects(projectsList);
    } catch (error) {
      console.error('Failed to load projects:', error);
      addToast({
        title: 'Failed to Load Projects',
        description: 'Could not retrieve project list',
        variant: 'error',
        duration: 3000,
      });
    }
  }, [addToast]);

  // Open projects dialog
  const handleOpenProjectsDialog = React.useCallback(async () => {
    await loadProjectsList();
    setProjectsDialogOpen(true);
  }, [loadProjectsList]);

  // Save current project
  // Use ref to capture latest currentTime without triggering callback recreation
  const currentTimeRef = React.useRef(currentTime);
  React.useEffect(() => {
    currentTimeRef.current = currentTime;
  }, [currentTime]);

  const handleSaveProject = React.useCallback(async (showToast = false) => {
    if (tracks.length === 0) return;

    try {
      const audioContext = getAudioContext();

      console.log('[Project Save] Saving project:', {
        id: currentProjectId,
        name: currentProjectName,
        trackCount: tracks.length,
        tracks: tracks.map(t => ({
          name: t.name,
          effectsCount: t.effectChain?.effects?.length || 0,
          automationLanes: t.automation?.lanes?.length || 0,
        }))
      });

      const projectId = await saveCurrentProject(
        currentProjectId,
        currentProjectName,
        tracks,
        {
          zoom,
          currentTime: currentTimeRef.current, // Use ref value
          sampleRate: audioContext.sampleRate,
        }
      );

      setCurrentProjectId(projectId);

      // Save last project ID to localStorage for auto-load on next visit
      localStorage.setItem('audio-ui-last-project', projectId);

      // Only show toast for manual saves
      if (showToast) {
        addToast({
          title: 'Project Saved',
          description: `"${currentProjectName}" saved successfully`,
          variant: 'success',
          duration: 2000,
        });
      }
    } catch (error) {
      console.error('Failed to save project:', error);
      // Always show error toasts
      addToast({
        title: 'Save Failed',
        description: 'Could not save project',
        variant: 'error',
        duration: 3000,
      });
    }
  }, [tracks, currentProjectId, currentProjectName, zoom, addToast]); // Removed currentTime from deps

  // Auto-save effect (saves on track or name changes after 3 seconds of no changes)
  React.useEffect(() => {
    if (tracks.length === 0) return;

    console.log('[Auto-save] Scheduling auto-save in 3 seconds...', {
      trackCount: tracks.length,
      projectName: currentProjectName,
    });

    const autoSaveTimer = setTimeout(() => {
      console.log('[Auto-save] Triggering auto-save now');
      handleSaveProject();
    }, 3000); // Auto-save after 3 seconds of no changes

    return () => {
      console.log('[Auto-save] Clearing auto-save timer');
      clearTimeout(autoSaveTimer);
    };
  }, [tracks, currentProjectName, handleSaveProject]);

  // Create new project
  const handleNewProject = React.useCallback(() => {
    if (tracks.length > 0) {
      if (!confirm('Create new project? Unsaved changes will be lost.')) {
        return;
      }
    }

    clearTracks();
    setCurrentProjectId(null);
    setCurrentProjectName('Untitled Project');
    setProjectsDialogOpen(false);

    addToast({
      title: 'New Project',
      description: 'Started new project',
      variant: 'success',
      duration: 2000,
    });
  }, [tracks, clearTracks, addToast]);

  // Load project
  const handleLoadProject = React.useCallback(async (projectId: string) => {
    try {
      const projectData = await loadProjectById(projectId);
      if (!projectData) {
        throw new Error('Project not found');
      }

      console.log('[Project Load] Loading project:', {
        id: projectData.metadata.id,
        name: projectData.metadata.name,
        trackCount: projectData.tracks.length,
        tracks: projectData.tracks.map(t => ({
          name: t.name,
          hasAudioBuffer: !!t.audioBuffer,
          effectsCount: t.effectChain?.effects?.length || 0,
          automationLanes: t.automation?.lanes?.length || 0,
        }))
      });

      // Load tracks with all their properties restored
      loadTracks(projectData.tracks);

      // Restore settings
      setZoom(projectData.settings.zoom);
      // Note: currentTime is managed by player, will start at 0

      // Set project metadata
      setCurrentProjectId(projectData.metadata.id);
      setCurrentProjectName(projectData.metadata.name);
      setProjectsDialogOpen(false);

      addToast({
        title: 'Project Loaded',
        description: `"${projectData.metadata.name}" loaded successfully (${projectData.tracks.length} track${projectData.tracks.length !== 1 ? 's' : ''})`,
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      console.error('Failed to load project:', error);
      addToast({
        title: 'Load Failed',
        description: 'Could not load project',
        variant: 'error',
        duration: 3000,
      });
    }
  }, [loadTracks, addToast]);

  // Check browser compatibility on mount
  React.useEffect(() => {
    const { isSupported, missingFeatures, warnings } = checkBrowserCompatibility();

    if (!isSupported || warnings.length > 0) {
      setBrowserCompatInfo({ missingFeatures, warnings });
      setBrowserCompatDialogOpen(true);
    }
  }, []);

  // Auto-load last project on mount
  const [hasAutoLoaded, setHasAutoLoaded] = React.useState(false);
  React.useEffect(() => {
    if (hasAutoLoaded) return; // Only run once

    const loadLastProject = async () => {
      const lastProjectId = localStorage.getItem('audio-ui-last-project');
      if (lastProjectId) {
        try {
          console.log('[Auto-load] Loading last project:', lastProjectId);
          await handleLoadProject(lastProjectId);
        } catch (error) {
          console.error('[Auto-load] Failed to load last project:', error);
          // Clear invalid project ID
          localStorage.removeItem('audio-ui-last-project');
        }
      }
      setHasAutoLoaded(true);
    };

    loadLastProject();
  }, [hasAutoLoaded, handleLoadProject]);

  // Delete project
  const handleDeleteProject = React.useCallback(async (projectId: string) => {
    try {
      await removeProject(projectId);
      await loadProjectsList();

      // If deleted current project, reset
      if (projectId === currentProjectId) {
        setCurrentProjectId(null);
        setCurrentProjectName('Untitled Project');
      }

      addToast({
        title: 'Project Deleted',
        description: 'Project deleted successfully',
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      console.error('Failed to delete project:', error);
      addToast({
        title: 'Delete Failed',
        description: 'Could not delete project',
        variant: 'error',
        duration: 3000,
      });
    }
  }, [currentProjectId, loadProjectsList, addToast]);

  // Duplicate project
  const handleDuplicateProject = React.useCallback(async (projectId: string) => {
    try {
      const sourceProject = projects.find(p => p.id === projectId);
      if (!sourceProject) return;

      const newName = `${sourceProject.name} (Copy)`;
      await duplicateProject(projectId, newName);
      await loadProjectsList();

      addToast({
        title: 'Project Duplicated',
        description: `"${newName}" created successfully`,
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      console.error('Failed to duplicate project:', error);
      addToast({
        title: 'Duplicate Failed',
        description: 'Could not duplicate project',
        variant: 'error',
        duration: 3000,
      });
    }
  }, [projects, loadProjectsList, addToast]);

  // Export project
  const handleExportProject = React.useCallback(async (projectId: string) => {
    try {
      const project = projects.find(p => p.id === projectId);
      if (!project) return;

      await exportProjectAsJSON(projectId);

      addToast({
        title: 'Project Exported',
        description: `"${project.name}" exported successfully`,
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      console.error('Failed to export project:', error);
      addToast({
        title: 'Export Failed',
        description: 'Could not export project',
        variant: 'error',
        duration: 3000,
      });
    }
  }, [projects, addToast]);

  // Import project
  const handleImportProject = React.useCallback(async () => {
    try {
      // Create file input
      const input = document.createElement('input');
      input.type = 'file';
      input.accept = '.zip';

      input.onchange = async (e) => {
        const file = (e.target as HTMLInputElement).files?.[0];
        if (!file) return;

        try {
          const projectId = await importProjectFromJSON(file);
          await loadProjectsList();

          addToast({
            title: 'Project Imported',
            description: 'Project imported successfully',
            variant: 'success',
            duration: 2000,
          });
        } catch (error) {
          console.error('Failed to import project:', error);
          addToast({
            title: 'Import Failed',
            description: 'Could not import project file',
            variant: 'error',
            duration: 3000,
          });
        }
      };

      input.click();
    } catch (error) {
      console.error('Failed to open file picker:', error);
    }
  }, [loadProjectsList, addToast]);

  // Zoom controls
  const handleZoomIn = () => {
    setZoom((prev) => Math.min(20, prev + 1));
  };

  const handleZoomOut = () => {
    setZoom((prev) => Math.max(1, prev - 1));
  };

  const handleFitToView = () => {
    setZoom(1);
  };

  // Keyboard shortcuts
  React.useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      // Spacebar for play/pause - only if not interacting with form elements
      if (e.code === 'Space') {
        const target = e.target as HTMLElement;
        // Don't trigger if user is typing or interacting with buttons/form elements
        if (
          target instanceof HTMLInputElement ||
          target instanceof HTMLTextAreaElement ||
          target instanceof HTMLButtonElement ||
          target.getAttribute('role') === 'button'
        ) {
          return;
        }
        e.preventDefault();
        togglePlayPause();
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [togglePlayPause]);

  // Find selected track
  const selectedTrack = tracks.find((t) => t.id === selectedTrackId);

  // Command palette actions
  const commandActions: CommandAction[] = React.useMemo(() => {
    const actions: CommandAction[] = [
      // Playback
      {
        id: 'play',
        label: 'Play',
        description: 'Start playback',
        shortcut: 'Space',
        category: 'playback',
        action: play,
      },
      {
        id: 'pause',
        label: 'Pause',
        description: 'Pause playback',
        shortcut: 'Space',
        category: 'playback',
        action: pause,
      },
      {
        id: 'stop',
        label: 'Stop',
        description: 'Stop playback',
        category: 'playback',
        action: stop,
      },
      // Edit
      {
        id: 'undo',
        label: 'Undo',
        description: 'Undo last action',
        shortcut: 'Ctrl+Z',
        category: 'edit',
        action: undo,
      },
      {
        id: 'redo',
        label: 'Redo',
        description: 'Redo last undone action',
        shortcut: 'Ctrl+Shift+Z',
        category: 'edit',
        action: redo,
      },
      {
        id: 'cut',
        label: 'Cut',
        description: 'Cut selection to clipboard',
        shortcut: 'Ctrl+X',
        category: 'edit',
        action: handleCut,
      },
      {
        id: 'copy',
        label: 'Copy',
        description: 'Copy selection to clipboard',
        shortcut: 'Ctrl+C',
        category: 'edit',
        action: handleCopy,
      },
      {
        id: 'paste',
        label: 'Paste',
        description: 'Paste clipboard content',
        shortcut: 'Ctrl+V',
        category: 'edit',
        action: handlePaste,
      },
      {
        id: 'delete',
        label: 'Delete',
        description: 'Delete selection',
        shortcut: 'Delete',
        category: 'edit',
        action: handleDelete,
      },
      {
        id: 'duplicate',
        label: 'Duplicate',
        description: 'Duplicate selection',
        shortcut: 'Ctrl+D',
        category: 'edit',
        action: handleDuplicate,
      },
      {
        id: 'split-at-cursor',
        label: 'Split at Cursor',
        description: 'Split selected track at current playback position',
        shortcut: 'S',
        category: 'edit',
        action: handleSplitAtCursor,
      },
      // Markers
      {
        id: 'add-marker',
        label: 'Add Marker',
        description: 'Add marker at current time',
        shortcut: 'M',
        category: 'view',
        action: handleAddMarker,
      },
      {
        id: 'next-marker',
        label: 'Go to Next Marker',
        description: 'Jump to next marker',
        shortcut: 'Shift+M',
        category: 'view',
        action: handleGoToNextMarker,
      },
      {
        id: 'previous-marker',
        label: 'Go to Previous Marker',
        description: 'Jump to previous marker',
        shortcut: 'Shift+Ctrl+M',
        category: 'view',
        action: handleGoToPreviousMarker,
      },
      {
        id: 'select-all',
        label: 'Select All',
        description: 'Select all content on current track',
        shortcut: 'Ctrl+A',
        category: 'edit',
        action: () => {
          if (selectedTrackId) {
            const track = tracks.find(t => t.id === selectedTrackId);
            if (track?.audioBuffer) {
              updateTrack(selectedTrackId, {
                selection: { start: 0, end: track.audioBuffer.duration }
              });
            }
          }
        },
      },
      // Project
      {
        id: 'save-project',
        label: 'Save Project',
        description: 'Save current project',
        shortcut: 'Ctrl+S',
        category: 'file',
        action: () => handleSaveProject(true),
      },
      {
        id: 'open-projects',
        label: 'Open Projects',
        description: 'Open projects dialog',
        category: 'file',
        action: handleOpenProjectsDialog,
      },
      // View
      {
        id: 'zoom-in',
        label: 'Zoom In',
        description: 'Zoom in on waveforms',
        shortcut: 'Ctrl++',
        category: 'view',
        action: handleZoomIn,
      },
      {
        id: 'zoom-out',
        label: 'Zoom Out',
        description: 'Zoom out on waveforms',
        shortcut: 'Ctrl+-',
        category: 'view',
        action: handleZoomOut,
      },
      {
        id: 'fit-to-view',
        label: 'Fit to View',
        description: 'Reset zoom to fit all tracks',
        shortcut: 'Ctrl+0',
        category: 'view',
        action: handleFitToView,
      },
      // Navigation
      {
        id: 'seek-start',
        label: 'Go to Start',
        description: 'Seek to beginning',
        shortcut: 'Home',
        category: 'playback',
        action: () => seek(0),
      },
      {
        id: 'seek-end',
        label: 'Go to End',
        description: 'Seek to end',
        shortcut: 'End',
        category: 'playback',
        action: () => seek(duration),
      },
      {
        id: 'seek-backward',
        label: 'Seek Backward',
        description: 'Seek backward 1 second',
        shortcut: '←',
        category: 'playback',
        action: () => seek(Math.max(0, currentTime - 1)),
      },
      {
        id: 'seek-forward',
        label: 'Seek Forward',
        description: 'Seek forward 1 second',
        shortcut: '→',
        category: 'playback',
        action: () => seek(Math.min(duration, currentTime + 1)),
      },
      {
        id: 'seek-backward-5s',
        label: 'Seek Backward 5s',
        description: 'Seek backward 5 seconds',
        shortcut: 'Ctrl+←',
        category: 'playback',
        action: () => seek(Math.max(0, currentTime - 5)),
      },
      {
        id: 'seek-forward-5s',
        label: 'Seek Forward 5s',
        description: 'Seek forward 5 seconds',
        shortcut: 'Ctrl+→',
        category: 'playback',
        action: () => seek(Math.min(duration, currentTime + 5)),
      },
      // Tracks
      {
        id: 'add-track',
        label: 'Add Empty Track',
        description: 'Create a new empty track',
        category: 'tracks',
        action: () => addTrack(),
      },
      {
        id: 'import-tracks',
        label: 'Import Audio Files',
        description: 'Import multiple audio files as tracks',
        category: 'tracks',
        action: handleImportTracks,
      },
      {
        id: 'clear-tracks',
        label: 'Clear All Tracks',
        description: 'Remove all tracks',
        category: 'tracks',
        action: handleClearTracks,
      },
      // Help
      {
        id: 'keyboard-shortcuts',
        label: 'Keyboard Shortcuts',
        description: 'View all keyboard shortcuts',
        shortcut: '?',
        category: 'view',
        action: () => setShortcutsDialogOpen(true),
      },
    ];
    return actions;
  }, [play, pause, stop, undo, redo, handleCut, handleCopy, handlePaste, handleDelete, handleDuplicate, handleSaveProject, handleOpenProjectsDialog, handleZoomIn, handleZoomOut, handleFitToView, handleImportTracks, handleClearTracks, addTrack, seek, duration, currentTime, selectedTrackId, tracks, updateTrack, setShortcutsDialogOpen]);

  // Keyboard shortcuts
  React.useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      // Prevent shortcuts if typing in an input
      const isTyping = e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement;

      // Spacebar: Play/Pause (always, unless typing in an input)
      if (e.code === 'Space' && !isTyping) {
        e.preventDefault();
        togglePlayPause();
        return;
      }

      if (isTyping) return;

      // Ctrl/Cmd+Z: Undo
      if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {
        e.preventDefault();
        if (canUndo) {
          undo();
        }
        return;
      }

      // Ctrl/Cmd+Shift+Z or Ctrl/Cmd+Y: Redo
      if (((e.ctrlKey || e.metaKey) && e.key === 'z' && e.shiftKey) || ((e.ctrlKey || e.metaKey) && e.key === 'y')) {
        e.preventDefault();
        if (canRedo) {
          redo();
        }
        return;
      }

      // Ctrl/Cmd+X: Cut
      if ((e.ctrlKey || e.metaKey) && e.key === 'x') {
        e.preventDefault();
        handleCut();
        return;
      }

      // Ctrl/Cmd+C: Copy
      if ((e.ctrlKey || e.metaKey) && e.key === 'c') {
        e.preventDefault();
        handleCopy();
        return;
      }

      // Ctrl/Cmd+V: Paste
      if ((e.ctrlKey || e.metaKey) && e.key === 'v') {
        e.preventDefault();
        handlePaste();
        return;
      }

      // Ctrl/Cmd+S: Save project (manual save with toast)
      if ((e.ctrlKey || e.metaKey) && e.key === 's') {
        e.preventDefault();
        handleSaveProject(true); // Show toast for manual saves
        return;
      }

      // Ctrl/Cmd+D: Duplicate
      if ((e.ctrlKey || e.metaKey) && e.key === 'd') {
        e.preventDefault();
        handleDuplicate();
        return;
      }

      // Ctrl/Cmd++: Zoom In (also accepts Ctrl+=)
      if ((e.ctrlKey || e.metaKey) && (e.key === '=' || e.key === '+')) {
        e.preventDefault();
        handleZoomIn();
        return;
      }

      // Ctrl/Cmd+-: Zoom Out
      if ((e.ctrlKey || e.metaKey) && e.key === '-') {
        e.preventDefault();
        handleZoomOut();
        return;
      }

      // Ctrl/Cmd+0: Fit to View
      if ((e.ctrlKey || e.metaKey) && e.key === '0') {
        e.preventDefault();
        handleFitToView();
        return;
      }

      // Delete or Backspace: Delete selection
      if (e.key === 'Delete' || e.key === 'Backspace') {
        e.preventDefault();
        handleDelete();
        return;
      }

      // Escape: Clear selection
      if (e.key === 'Escape') {
        e.preventDefault();
        setSelectedTrackId(null);
        return;
      }

      // Home: Go to start
      if (e.key === 'Home') {
        e.preventDefault();
        seek(0);
        return;
      }

      // End: Go to end
      if (e.key === 'End') {
        e.preventDefault();
        seek(duration);
        return;
      }

      // Left Arrow: Seek backward 1 second
      if (e.key === 'ArrowLeft' && !e.ctrlKey && !e.metaKey) {
        e.preventDefault();
        seek(Math.max(0, currentTime - 1));
        return;
      }

      // Right Arrow: Seek forward 1 second
      if (e.key === 'ArrowRight' && !e.ctrlKey && !e.metaKey) {
        e.preventDefault();
        seek(Math.min(duration, currentTime + 1));
        return;
      }

      // Ctrl+Left Arrow: Seek backward 5 seconds
      if (e.key === 'ArrowLeft' && (e.ctrlKey || e.metaKey)) {
        e.preventDefault();
        seek(Math.max(0, currentTime - 5));
        return;
      }

      // Ctrl+Right Arrow: Seek forward 5 seconds
      if (e.key === 'ArrowRight' && (e.ctrlKey || e.metaKey)) {
        e.preventDefault();
        seek(Math.min(duration, currentTime + 5));
        return;
      }

      // Ctrl+A: Select All (select all content on current track)
      if ((e.ctrlKey || e.metaKey) && e.key === 'a') {
        e.preventDefault();
        if (!selectedTrackId) {
          // If no track selected, try to select the first track with audio
          const trackWithAudio = tracks.find(t => t.audioBuffer);
          if (trackWithAudio && trackWithAudio.audioBuffer) {
            setSelectedTrackId(trackWithAudio.id);
            updateTrack(trackWithAudio.id, {
              selection: { start: 0, end: trackWithAudio.audioBuffer.duration }
            });
          }
        } else {
          const track = tracks.find(t => t.id === selectedTrackId);
          if (track?.audioBuffer) {
            updateTrack(selectedTrackId, {
              selection: { start: 0, end: track.audioBuffer.duration }
            });
          }
        }
        return;
      }

      // S: Split at cursor
      if (e.key === 's' && !e.ctrlKey && !e.metaKey) {
        e.preventDefault();
        handleSplitAtCursor();
        return;
      }

      // M: Add marker
      if (e.key === 'm' && !e.shiftKey && !e.ctrlKey && !e.metaKey) {
        e.preventDefault();
        handleAddMarker();
        return;
      }

      // Shift+M: Go to next marker
      if (e.key === 'M' && e.shiftKey && !e.ctrlKey && !e.metaKey) {
        e.preventDefault();
        handleGoToNextMarker();
        return;
      }

      // Shift+Ctrl+M: Go to previous marker
      if (e.key === 'M' && e.shiftKey && (e.ctrlKey || e.metaKey)) {
        e.preventDefault();
        handleGoToPreviousMarker();
        return;
      }

      // ?: Open keyboard shortcuts help
      if (e.key === '?' && !e.ctrlKey && !e.metaKey) {
        e.preventDefault();
        setShortcutsDialogOpen(true);
        return;
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [togglePlayPause, canUndo, canRedo, undo, redo, handleCut, handleCopy, handlePaste, handleDelete, handleDuplicate, handleSaveProject, seek, duration, currentTime, selectedTrackId, tracks, updateTrack, handleZoomIn, handleZoomOut, handleFitToView, setSelectedTrackId, setShortcutsDialogOpen]);

  return (
    <>
      {/* Compact Header */}
      <header className="flex items-center justify-between px-2 sm:px-4 py-2 border-b border-border bg-card flex-shrink-0 gap-2 sm:gap-4">
        {/* Left: Logo */}
        <div className="flex items-center gap-2 sm:gap-4 flex-shrink-0">
          <div className="flex items-center gap-2">
            <Music className="h-5 w-5 text-primary" />
            <h1 className="text-base sm:text-lg font-bold text-foreground hidden sm:block">Audio UI</h1>
          </div>

          {/* Project Name */}
          <div className="hidden md:flex items-center gap-2 border-l border-border pl-4">
            <input
              type="text"
              value={currentProjectName}
              onChange={(e) => setCurrentProjectName(e.target.value)}
              className="bg-transparent border-none outline-none text-sm font-medium text-muted-foreground hover:text-foreground focus:text-foreground transition-colors px-2 py-1 rounded hover:bg-accent/50 focus:bg-accent"
              placeholder="Untitled Project"
              title="Click to edit project name"
              style={{ width: `${Math.max(12, currentProjectName.length)}ch` }}
            />
          </div>

          {/* Track Actions - Compact on mobile */}
          <div className="flex items-center gap-1 sm:gap-2 border-l border-border pl-2 sm:pl-4">
            <Button variant="outline" size="sm" onClick={handleOpenProjectsDialog} className="hidden sm:flex">
              <FolderOpen className="h-4 w-4 mr-1.5" />
              Projects
            </Button>
            <Button variant="outline" size="sm" onClick={handleOpenProjectsDialog} className="sm:hidden px-2">
              <FolderOpen className="h-4 w-4" />
            </Button>

            <Button variant="outline" size="sm" onClick={() => addTrack()}>
              <Plus className="h-4 w-4 sm:mr-1.5" />
              <span className="hidden sm:inline">Add Track</span>
            </Button>
            <Button variant="outline" size="sm" onClick={handleImportTracks}>
              <Upload className="h-4 w-4 sm:mr-1.5" />
              <span className="hidden sm:inline">Import</span>
            </Button>
            {tracks.length > 0 && (
              <>
                <Button variant="outline" size="sm" onClick={() => setExportDialogOpen(true)} className="hidden md:flex">
                  <Download className="h-4 w-4 mr-1.5" />
                  Export
                </Button>
                <Button variant="outline" size="sm" onClick={handleClearTracks} className="hidden lg:flex">
                  <Trash2 className="h-4 w-4 mr-1.5 text-destructive" />
                  Clear All
                </Button>
              </>
            )}
          </div>
        </div>

        {/* Right: Command Palette + Settings + Theme Toggle */}
        <div className="flex items-center gap-2 flex-shrink-0">
          <CommandPalette actions={commandActions} />
          <Button
            variant="ghost"
            size="icon"
            onClick={() => setSettingsDialogOpen(true)}
            title="Settings"
          >
            <Settings className="h-5 w-5" />
          </Button>
          <ThemeToggle />
        </div>
      </header>

      {/* Main content area */}
      <div className="flex flex-1 flex-col overflow-hidden">
        {/* Time Scale - Full width */}
        <React.Suspense fallback={null}>
          <TimeScale
            duration={duration}
            zoom={zoom}
            currentTime={currentTime}
            onSeek={seek}
            scrollRef={timeScaleScrollRef}
            onScroll={handleTimeScaleScroll}
          />
        </React.Suspense>

        <div className="flex flex-1 overflow-hidden">
          {/* Main canvas area */}
          <main className="flex-1 flex flex-col overflow-hidden bg-background">
            <TrackList
              tracks={tracks}
              zoom={zoom}
              currentTime={currentTime}
              duration={duration}
              selectedTrackId={selectedTrackId}
              onSelectTrack={setSelectedTrackId}
              onAddTrack={addTrack}
              onImportTrack={handleImportTrack}
              onRemoveTrack={handleRemoveTrack}
              onUpdateTrack={updateTrack}
              onSeek={seek}
              onSelectionChange={handleSelectionChange}
              onToggleRecordEnable={handleToggleRecordEnable}
              timeScaleScrollRef={timeScaleScrollRef}
              onTimeScaleScroll={handleTimeScaleScroll}
              timeScaleScrollHandlerRef={timeScaleScrollHandlerRef}
              recordingTrackId={recordingTrackId}
              recordingLevel={recordingState.inputLevel}
              trackLevels={trackLevels}
              onParameterTouched={setParameterTouched}
              isPlaying={isPlaying}
            />
          </main>

          {/* Right Sidebar - Master Controls & Analyzers - Hidden on mobile */}
          <aside className="hidden lg:flex flex-shrink-0 border-l border-border bg-card flex-col pt-5 px-4 pb-4 gap-4 w-60">
            {/* Master Controls */}
          <div className="flex items-center justify-center">
            <MasterControls
              volume={masterVolume}
              pan={masterPan}
              peakLevel={masterPeakLevel}
              rmsLevel={masterRmsLevel}
              isClipping={masterIsClipping}
              isMuted={isMasterMuted}
              collapsed={masterControlsCollapsed}
              onVolumeChange={setMasterVolume}
              onPanChange={setMasterPan}
              onMuteToggle={() => {
                if (isMasterMuted) {
                  setMasterVolume(0.8);
                  setIsMasterMuted(false);
                } else {
                  setMasterVolume(0);
                  setIsMasterMuted(true);
                }
              }}
              onResetClip={resetClipIndicator}
              onToggleCollapse={() => setMasterControlsCollapsed(!masterControlsCollapsed)}
            />
          </div>

          {/* Analyzer Toggle */}
          <div className={`grid ${settings.performance.enableSpectrogram ? 'grid-cols-5' : 'grid-cols-4'} gap-0.5 bg-muted/20 border border-border/50 rounded-md p-0.5 max-w-[192px] mx-auto`}>
            <button
              onClick={() => setAnalyzerView('frequency')}
              className={`px-1 py-1 rounded text-[9px] font-bold uppercase tracking-wider transition-all ${
                analyzerView === 'frequency'
                  ? 'bg-accent text-accent-foreground shadow-sm'
                  : 'text-muted-foreground hover:text-foreground'
              }`}
              title="Frequency Analyzer"
            >
              FFT
            </button>
            {settings.performance.enableSpectrogram && (
              <button
                onClick={() => setAnalyzerView('spectrogram')}
                className={`px-1 py-1 rounded text-[9px] font-bold uppercase tracking-wider transition-all ${
                  analyzerView === 'spectrogram'
                    ? 'bg-accent text-accent-foreground shadow-sm'
                    : 'text-muted-foreground hover:text-foreground'
                }`}
                title="Spectrogram"
              >
                SPEC
              </button>
            )}
            <button
              onClick={() => setAnalyzerView('phase')}
              className={`px-1 py-1 rounded text-[9px] font-bold uppercase tracking-wider transition-all ${
                analyzerView === 'phase'
                  ? 'bg-accent text-accent-foreground shadow-sm'
                  : 'text-muted-foreground hover:text-foreground'
              }`}
              title="Phase Correlation"
            >
              PHS
            </button>
            <button
              onClick={() => setAnalyzerView('lufs')}
              className={`px-1 py-1 rounded text-[9px] font-bold uppercase tracking-wider transition-all ${
                analyzerView === 'lufs'
                  ? 'bg-accent text-accent-foreground shadow-sm'
                  : 'text-muted-foreground hover:text-foreground'
              }`}
              title="LUFS Loudness"
            >
              LUFS
            </button>
            <button
              onClick={() => setAnalyzerView('stats')}
              className={`px-1 py-1 rounded text-[9px] font-bold uppercase tracking-wider transition-all ${
                analyzerView === 'stats'
                  ? 'bg-accent text-accent-foreground shadow-sm'
                  : 'text-muted-foreground hover:text-foreground'
              }`}
              title="Audio Statistics"
            >
              INFO
            </button>
          </div>

          {/* Analyzer Display */}
          <div className="flex-1 min-h-[360px] flex items-start justify-center">
            <div className="w-[178px]">
              {analyzerView === 'frequency' && (
                <React.Suspense fallback={<div className="h-[300px] flex items-center justify-center text-muted-foreground">Loading...</div>}>
                  <FrequencyAnalyzer analyserNode={masterAnalyser} />
                </React.Suspense>
              )}
              {analyzerView === 'spectrogram' && settings.performance.enableSpectrogram && (
                <React.Suspense fallback={<div className="h-[300px] flex items-center justify-center text-muted-foreground">Loading...</div>}>
                  <Spectrogram analyserNode={masterAnalyser} />
                </React.Suspense>
              )}
              {analyzerView === 'phase' && (
                <React.Suspense fallback={<div className="h-[300px] flex items-center justify-center text-muted-foreground">Loading...</div>}>
                  <PhaseCorrelationMeter analyserNode={masterAnalyser} />
                </React.Suspense>
              )}
              {analyzerView === 'lufs' && (
                <React.Suspense fallback={<div className="h-[300px] flex items-center justify-center text-muted-foreground">Loading...</div>}>
                  <LUFSMeter analyserNode={masterAnalyser} />
                </React.Suspense>
              )}
              {analyzerView === 'stats' && (
                <React.Suspense fallback={<div className="h-[300px] flex items-center justify-center text-muted-foreground">Loading...</div>}>
                  <AudioStatistics tracks={tracks} />
                </React.Suspense>
              )}
            </div>
          </div>
          </aside>
        </div>
      </div>

      {/* Bottom Bar - Stacked on mobile (Master then Transport), Side-by-side on desktop */}
      <div className="border-t border-border bg-card p-3 flex flex-col lg:flex-row gap-3">
        {/* Master Controls - Mobile only (hidden on desktop where sidebar shows master) */}
        <div className="lg:hidden flex justify-center border-b border-border pb-3 lg:border-b-0 lg:pb-0">
          <MasterControls
            volume={masterVolume}
            pan={masterPan}
            peakLevel={masterPeakLevel}
            rmsLevel={masterRmsLevel}
            isClipping={masterIsClipping}
            isMuted={isMasterMuted}
            collapsed={masterControlsCollapsed}
            onVolumeChange={setMasterVolume}
            onPanChange={setMasterPan}
            onMuteToggle={() => {
              if (isMasterMuted) {
                setMasterVolume(0.8);
                setIsMasterMuted(false);
              } else {
                setMasterVolume(0);
                setIsMasterMuted(true);
              }
            }}
            onResetClip={resetClipIndicator}
            onToggleCollapse={() => setMasterControlsCollapsed(!masterControlsCollapsed)}
          />
        </div>

        {/* Playback Controls - Bottom on mobile, centered on desktop */}
        <div className="flex-1 flex justify-center">
          <PlaybackControls
            isPlaying={isPlaying}
            isPaused={!isPlaying}
            currentTime={currentTime}
            duration={duration}
            volume={masterVolume}
            onPlay={play}
            onPause={pause}
            onStop={stop}
            onSeek={seek}
            onVolumeChange={setMasterVolume}
            currentTimeFormatted={formatDuration(currentTime)}
            durationFormatted={formatDuration(duration)}
            isRecording={recordingState.isRecording}
            onStartRecording={handleStartRecording}
            onStopRecording={handleStopRecording}
            punchInEnabled={punchInEnabled}
            punchInTime={punchInTime}
            punchOutTime={punchOutTime}
            onPunchInEnabledChange={setPunchInEnabled}
            onPunchInTimeChange={setPunchInTime}
            onPunchOutTimeChange={setPunchOutTime}
            overdubEnabled={overdubEnabled}
            onOverdubEnabledChange={setOverdubEnabled}
            loopEnabled={loopEnabled}
            loopStart={loopStart}
            loopEnd={loopEnd}
            onToggleLoop={toggleLoop}
            onSetLoopPoints={setLoopPoints}
            playbackRate={playbackRate}
            onPlaybackRateChange={changePlaybackRate}
          />
        </div>
      </div>

      {/* Import Track Dialog */}
      <React.Suspense fallback={null}>
        <ImportTrackDialog
          open={importDialogOpen}
          onClose={() => setImportDialogOpen(false)}
          onImportTrack={handleImportTrack}
        />
      </React.Suspense>

      {/* Global Settings Dialog */}
      <React.Suspense fallback={null}>
        <GlobalSettingsDialog
          open={settingsDialogOpen}
          onClose={() => setSettingsDialogOpen(false)}
          recordingSettings={recordingSettings}
          onInputGainChange={setInputGain}
          onRecordMonoChange={setRecordMono}
          onSampleRateChange={setSampleRate}
          settings={settings}
          onAudioSettingsChange={updateAudioSettings}
          onUISettingsChange={updateUISettings}
          onEditorSettingsChange={updateEditorSettings}
          onPerformanceSettingsChange={updatePerformanceSettings}
          onResetCategory={resetCategory}
        />
      </React.Suspense>

      {/* Export Dialog */}
      <React.Suspense fallback={null}>
        <ExportDialog
          open={exportDialogOpen}
          onClose={() => setExportDialogOpen(false)}
          onExport={handleExport}
          isExporting={isExporting}
          hasSelection={tracks.some(t => t.selection !== null)}
        />
      </React.Suspense>

      {/* Projects Dialog */}
      <React.Suspense fallback={null}>
        <ProjectsDialog
          open={projectsDialogOpen}
          onClose={() => setProjectsDialogOpen(false)}
          projects={projects}
          onNewProject={handleNewProject}
          onLoadProject={handleLoadProject}
          onDeleteProject={handleDeleteProject}
          onDuplicateProject={handleDuplicateProject}
          onExportProject={handleExportProject}
          onImportProject={handleImportProject}
        />
      </React.Suspense>

      {/* Browser Compatibility Dialog */}
      <BrowserCompatDialog
        open={browserCompatDialogOpen}
        missingFeatures={browserCompatInfo.missingFeatures}
        warnings={browserCompatInfo.warnings}
        onClose={() => setBrowserCompatDialogOpen(false)}
      />

      {/* Keyboard Shortcuts Dialog */}
      <React.Suspense fallback={null}>
        <KeyboardShortcutsDialog
          open={shortcutsDialogOpen}
          onClose={() => setShortcutsDialogOpen(false)}
        />
      </React.Suspense>

      {/* Marker Dialog */}
      <React.Suspense fallback={null}>
        <MarkerDialog
          open={markerDialogOpen}
          onClose={() => setMarkerDialogOpen(false)}
          onSave={handleSaveMarker}
          marker={editingMarker}
          defaultTime={currentTime}
        />
      </React.Suspense>
    </>
  );
}
