'use client';

import * as React from 'react';
import { Music, Loader2 } from 'lucide-react';
import { Waveform } from './Waveform';
import { PlaybackControls } from './PlaybackControls';
import { SidePanel } from '@/components/layout/SidePanel';
import { ThemeToggle } from '@/components/layout/ThemeToggle';
import { CommandPalette } from '@/components/ui/CommandPalette';
import type { CommandAction } from '@/components/ui/CommandPalette';
import { useAudioPlayer } from '@/lib/hooks/useAudioPlayer';
import { useHistory } from '@/lib/hooks/useHistory';
import { useEffectChain } from '@/lib/hooks/useEffectChain';
import { useMultiTrack } from '@/lib/hooks/useMultiTrack';
import { useMultiTrackPlayer } from '@/lib/hooks/useMultiTrackPlayer';
import { useToast } from '@/components/ui/Toast';
import { Slider } from '@/components/ui/Slider';
import { cn } from '@/lib/utils/cn';
import type { Selection, ClipboardData } from '@/types/selection';
import {
  extractBufferSegment,
  deleteBufferSegment,
  insertBufferSegment,
  trimBuffer,
} from '@/lib/audio/buffer-utils';
import {
  createCutCommand,
  createDeleteCommand,
  createPasteCommand,
  createTrimCommand,
} from '@/lib/history/commands/edit-command';
import {
  createGainCommand,
  createNormalizePeakCommand,
  createNormalizeRMSCommand,
  createFadeInCommand,
  createFadeOutCommand,
  createReverseCommand,
  createLowPassFilterCommand,
  createHighPassFilterCommand,
  createBandPassFilterCommand,
  EffectCommand,
} from '@/lib/history/commands/effect-command';
import { applyEffectToSelection, applyAsyncEffectToSelection } from '@/lib/audio/effects/selection';
import { normalizePeak } from '@/lib/audio/effects/normalize';
import { applyFadeIn, applyFadeOut } from '@/lib/audio/effects/fade';
import { reverseAudio } from '@/lib/audio/effects/reverse';
import { applyLowPassFilter, applyHighPassFilter, applyBandPassFilter, applyFilter } from '@/lib/audio/effects/filters';
import type { FilterType } from '@/lib/audio/effects/filters';
import { applyCompressor, applyLimiter, applyGate } from '@/lib/audio/effects/dynamics';
import { applyDelay, applyReverb, applyChorus, applyFlanger, applyPhaser } from '@/lib/audio/effects/time-based';
import { applyPitchShift, applyTimeStretch, applyDistortion, applyBitcrusher } from '@/lib/audio/effects/advanced';
import { EffectParameterDialog, type FilterParameters } from '@/components/effects/EffectParameterDialog';
import { DynamicsParameterDialog, type DynamicsParameters, type DynamicsType } from '@/components/effects/DynamicsParameterDialog';
import { TimeBasedParameterDialog, type TimeBasedParameters, type TimeBasedType } from '@/components/effects/TimeBasedParameterDialog';
import { AdvancedParameterDialog, type AdvancedParameters, type AdvancedType } from '@/components/effects/AdvancedParameterDialog';
import { TrackList } from '@/components/tracks/TrackList';
import { ImportTrackDialog } from '@/components/tracks/ImportTrackDialog';

const EFFECT_LABELS: Record<string, string> = {
  lowpass: 'Low-Pass Filter',
  highpass: 'High-Pass Filter',
  bandpass: 'Band-Pass Filter',
  notch: 'Notch Filter',
  lowshelf: 'Low Shelf Filter',
  highshelf: 'High Shelf Filter',
  peaking: 'Peaking EQ',
  compressor: 'Compressor',
  limiter: 'Limiter',
  gate: 'Gate/Expander',
  delay: 'Delay/Echo',
  reverb: 'Reverb',
  chorus: 'Chorus',
  flanger: 'Flanger',
  phaser: 'Phaser',
  pitch: 'Pitch Shifter',
  timestretch: 'Time Stretch',
  distortion: 'Distortion',
  bitcrusher: 'Bitcrusher',
};

export function AudioEditor() {
  // View mode state
  const [viewMode, setViewMode] = React.useState<'waveform' | 'tracks'>('waveform');
  const [importDialogOpen, setImportDialogOpen] = React.useState(false);

  // Zoom and scroll state
  const [zoom, setZoom] = React.useState(1);
  const [scrollOffset, setScrollOffset] = React.useState(0);
  const [amplitudeScale, setAmplitudeScale] = React.useState(1);

  // Effect dialog state
  const [effectDialogOpen, setEffectDialogOpen] = React.useState(false);
  const [effectDialogType, setEffectDialogType] = React.useState<'lowpass' | 'highpass' | 'bandpass' | 'notch' | 'lowshelf' | 'highshelf' | 'peaking'>('lowpass');

  // Dynamics dialog state
  const [dynamicsDialogOpen, setDynamicsDialogOpen] = React.useState(false);
  const [dynamicsDialogType, setDynamicsDialogType] = React.useState<DynamicsType>('compressor');

  // Time-based dialog state
  const [timeBasedDialogOpen, setTimeBasedDialogOpen] = React.useState(false);
  const [timeBasedDialogType, setTimeBasedDialogType] = React.useState<TimeBasedType>('delay');

  // Advanced dialog state
  const [advancedDialogOpen, setAdvancedDialogOpen] = React.useState(false);
  const [advancedDialogType, setAdvancedDialogType] = React.useState<AdvancedType>('pitch');

  // Drag and drop state
  const [isDragging, setIsDragging] = React.useState(false);
  const fileInputRef = React.useRef<HTMLInputElement>(null);

  // Selection state
  const [selection, setSelection] = React.useState<Selection | null>(null);
  const [clipboard, setClipboard] = React.useState<ClipboardData | null>(null);

  const {
    loadFile,
    loadBuffer,
    clearFile,
    play,
    pause,
    stop,
    seek,
    setVolume,
    isPlaying,
    isPaused,
    currentTime,
    duration,
    volume,
    audioBuffer,
    fileName,
    isLoading,
    error,
    currentTimeFormatted,
    durationFormatted,
  } = useAudioPlayer();

  const { execute, undo, redo, clear: clearHistory, state: historyState } = useHistory(50);
  const {
    chain: effectChain,
    presets: effectPresets,
    toggleEffectEnabled,
    removeEffect,
    reorder: reorderEffects,
    clearChain,
    savePreset,
    loadPresetToChain,
    deletePreset,
  } = useEffectChain();
  const { addToast } = useToast();

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

  const {
    isPlaying: isMultiTrackPlaying,
    currentTime: multiTrackCurrentTime,
    duration: multiTrackDuration,
    play: playMultiTrack,
    pause: pauseMultiTrack,
    stop: stopMultiTrack,
    seek: seekMultiTrack,
    togglePlayPause: toggleMultiTrackPlayPause,
  } = useMultiTrackPlayer(tracks);

  const handleFileSelect = async (file: File) => {
    try {
      await loadFile(file);
      addToast({
        title: 'File loaded',
        description: `Successfully loaded ${file.name}`,
        variant: 'success',
        duration: 3000,
      });
    } catch (err) {
      addToast({
        title: 'Error loading file',
        description: err instanceof Error ? err.message : 'Unknown error',
        variant: 'error',
        duration: 5000,
      });
    }
  };

  const handleClear = () => {
    clearFile();
    setZoom(1);
    setScrollOffset(0);
    setAmplitudeScale(1);
    setSelection(null);
    setClipboard(null);
    clearHistory();
    addToast({
      title: 'Audio cleared',
      description: 'Audio file has been removed',
      variant: 'info',
      duration: 2000,
    });
  };

  // Multi-track handlers
  const handleConvertToTrack = () => {
    if (!audioBuffer) return;

    const trackName = fileName || 'Audio Track';
    addTrackFromBuffer(audioBuffer, trackName);
    setViewMode('tracks');
    addToast({
      title: 'Converted to Track',
      description: `"${trackName}" added to tracks`,
      variant: 'success',
      duration: 2000,
    });
  };

  const handleImportTracks = () => {
    setImportDialogOpen(true);
  };

  const handleImportTrack = (buffer: AudioBuffer, name: string) => {
    addTrackFromBuffer(buffer, name);
    setViewMode('tracks');
  };

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

  // Drag and drop handlers
  const handleDragEnter = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragging(true);
  };

  const handleDragLeave = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    // Only set to false if we're leaving the drop zone entirely
    if (e.currentTarget === e.target) {
      setIsDragging(false);
    }
  };

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
  };

  const handleDrop = async (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragging(false);

    const files = Array.from(e.dataTransfer.files);
    const audioFile = files.find(file => file.type.startsWith('audio/'));

    if (audioFile) {
      await handleFileSelect(audioFile);
    } else {
      addToast({
        title: 'Invalid file',
        description: 'Please drop an audio file',
        variant: 'error',
        duration: 3000,
      });
    }
  };

  const handleDropZoneClick = () => {
    fileInputRef.current?.click();
  };

  const handleFileInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (file) {
      handleFileSelect(file);
    }
  };

  // Edit operations
  const handleCut = () => {
    if (!selection || !audioBuffer) return;

    try {
      // Copy to clipboard
      const clipData = extractBufferSegment(audioBuffer, selection.start, selection.end);
      setClipboard({
        buffer: clipData,
        start: selection.start,
        end: selection.end,
        duration: selection.end - selection.start,
      });

      // Create and execute cut command
      const command = createCutCommand(audioBuffer, selection, (buffer) => {
        loadBuffer(buffer);
      });
      execute(command);

      setSelection(null);
      addToast({
        title: 'Cut',
        description: 'Selection cut to clipboard',
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      addToast({
        title: 'Error',
        description: 'Failed to cut selection',
        variant: 'error',
        duration: 3000,
      });
    }
  };

  const handleCopy = () => {
    if (!selection || !audioBuffer) return;

    try {
      const clipData = extractBufferSegment(audioBuffer, selection.start, selection.end);
      setClipboard({
        buffer: clipData,
        start: selection.start,
        end: selection.end,
        duration: selection.end - selection.start,
      });

      addToast({
        title: 'Copied',
        description: 'Selection copied to clipboard',
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      addToast({
        title: 'Error',
        description: 'Failed to copy selection',
        variant: 'error',
        duration: 3000,
      });
    }
  };

  const handlePaste = () => {
    if (!clipboard || !audioBuffer) return;

    try {
      const insertTime = currentTime;

      // Create and execute paste command
      const command = createPasteCommand(audioBuffer, clipboard.buffer, insertTime, (buffer) => {
        loadBuffer(buffer);
      });
      execute(command);

      addToast({
        title: 'Pasted',
        description: 'Clipboard pasted at current position',
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      addToast({
        title: 'Error',
        description: 'Failed to paste clipboard',
        variant: 'error',
        duration: 3000,
      });
    }
  };

  const handleDelete = () => {
    if (!selection || !audioBuffer) return;

    try {
      // Create and execute delete command
      const command = createDeleteCommand(audioBuffer, selection, (buffer) => {
        loadBuffer(buffer);
      });
      execute(command);

      setSelection(null);
      addToast({
        title: 'Deleted',
        description: 'Selection deleted',
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      addToast({
        title: 'Error',
        description: 'Failed to delete selection',
        variant: 'error',
        duration: 3000,
      });
    }
  };

  const handleTrim = () => {
    if (!selection || !audioBuffer) return;

    try {
      // Create and execute trim command
      const command = createTrimCommand(audioBuffer, selection, (buffer) => {
        loadBuffer(buffer);
      });
      execute(command);

      setSelection(null);
      addToast({
        title: 'Trimmed',
        description: 'Audio trimmed to selection',
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      addToast({
        title: 'Error',
        description: 'Failed to trim audio',
        variant: 'error',
        duration: 3000,
      });
    }
  };

  const handleSelectAll = () => {
    if (!audioBuffer) return;
    setSelection({ start: 0, end: duration });
  };

  const handleClearSelection = () => {
    setSelection(null);
  };

  // Effect operations
  const handleNormalize = () => {
    if (!audioBuffer) return;

    try {
      // Apply to selection or entire buffer
      const modifiedBuffer = applyEffectToSelection(
        audioBuffer,
        selection,
        (buf) => normalizePeak(buf, 1.0)
      );

      const command = new EffectCommand(
        audioBuffer,
        modifiedBuffer,
        (buffer) => loadBuffer(buffer),
        selection ? 'Normalize Selection' : 'Normalize'
      );
      execute(command);

      addToast({
        title: 'Normalized',
        description: selection ? 'Selection normalized to peak' : 'Audio normalized to peak',
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      addToast({
        title: 'Error',
        description: 'Failed to normalize audio',
        variant: 'error',
        duration: 3000,
      });
    }
  };

  const handleFadeIn = () => {
    if (!audioBuffer) return;

    if (!selection) {
      addToast({
        title: 'No Selection',
        description: 'Please select a region to apply fade in',
        variant: 'info',
        duration: 2000,
      });
      return;
    }

    try {
      const fadeDuration = selection.end - selection.start;
      const modifiedBuffer = applyEffectToSelection(
        audioBuffer,
        selection,
        (buf) => applyFadeIn(buf, buf.duration)
      );

      const command = new EffectCommand(
        audioBuffer,
        modifiedBuffer,
        (buffer) => loadBuffer(buffer),
        `Fade In (${fadeDuration.toFixed(2)}s)`
      );
      execute(command);

      addToast({
        title: 'Fade In',
        description: `Applied fade in (${fadeDuration.toFixed(2)}s)`,
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      addToast({
        title: 'Error',
        description: 'Failed to apply fade in',
        variant: 'error',
        duration: 3000,
      });
    }
  };

  const handleFadeOut = () => {
    if (!audioBuffer) return;

    if (!selection) {
      addToast({
        title: 'No Selection',
        description: 'Please select a region to apply fade out',
        variant: 'info',
        duration: 2000,
      });
      return;
    }

    try {
      const fadeDuration = selection.end - selection.start;
      const modifiedBuffer = applyEffectToSelection(
        audioBuffer,
        selection,
        (buf) => applyFadeOut(buf, buf.duration)
      );

      const command = new EffectCommand(
        audioBuffer,
        modifiedBuffer,
        (buffer) => loadBuffer(buffer),
        `Fade Out (${fadeDuration.toFixed(2)}s)`
      );
      execute(command);

      addToast({
        title: 'Fade Out',
        description: `Applied fade out (${fadeDuration.toFixed(2)}s)`,
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      addToast({
        title: 'Error',
        description: 'Failed to apply fade out',
        variant: 'error',
        duration: 3000,
      });
    }
  };

  const handleReverse = () => {
    if (!audioBuffer) return;

    try {
      const modifiedBuffer = applyEffectToSelection(
        audioBuffer,
        selection,
        (buf) => reverseAudio(buf)
      );

      const command = new EffectCommand(
        audioBuffer,
        modifiedBuffer,
        (buffer) => loadBuffer(buffer),
        selection ? 'Reverse Selection' : 'Reverse'
      );
      execute(command);

      addToast({
        title: 'Reversed',
        description: selection ? 'Selection reversed' : 'Audio reversed',
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      addToast({
        title: 'Error',
        description: 'Failed to reverse audio',
        variant: 'error',
        duration: 3000,
      });
    }
  };

  const handleLowPassFilter = () => {
    setEffectDialogType('lowpass');
    setEffectDialogOpen(true);
  };

  const handleHighPassFilter = () => {
    setEffectDialogType('highpass');
    setEffectDialogOpen(true);
  };

  const handleBandPassFilter = () => {
    setEffectDialogType('bandpass');
    setEffectDialogOpen(true);
  };

  const handleCompressor = () => {
    setDynamicsDialogType('compressor');
    setDynamicsDialogOpen(true);
  };

  const handleLimiter = () => {
    setDynamicsDialogType('limiter');
    setDynamicsDialogOpen(true);
  };

  const handleGate = () => {
    setDynamicsDialogType('gate');
    setDynamicsDialogOpen(true);
  };

  const handleDelay = () => {
    setTimeBasedDialogType('delay');
    setTimeBasedDialogOpen(true);
  };

  const handleReverb = () => {
    setTimeBasedDialogType('reverb');
    setTimeBasedDialogOpen(true);
  };

  const handleChorus = () => {
    setTimeBasedDialogType('chorus');
    setTimeBasedDialogOpen(true);
  };

  const handleFlanger = () => {
    setTimeBasedDialogType('flanger');
    setTimeBasedDialogOpen(true);
  };

  const handlePhaser = () => {
    setTimeBasedDialogType('phaser');
    setTimeBasedDialogOpen(true);
  };

  const handlePitchShift = () => {
    setAdvancedDialogType('pitch');
    setAdvancedDialogOpen(true);
  };

  const handleTimeStretch = () => {
    setAdvancedDialogType('timestretch');
    setAdvancedDialogOpen(true);
  };

  const handleDistortion = () => {
    setAdvancedDialogType('distortion');
    setAdvancedDialogOpen(true);
  };

  const handleBitcrusher = () => {
    setAdvancedDialogType('bitcrusher');
    setAdvancedDialogOpen(true);
  };

  // Handle effect apply from parameter dialog
  const handleEffectApply = async (params: FilterParameters) => {
    if (!audioBuffer) return;

    try {
      const modifiedBuffer = await applyAsyncEffectToSelection(
        audioBuffer,
        selection,
        (buf) => applyFilter(buf, {
          type: params.type,
          frequency: params.frequency,
          Q: params.Q,
          gain: params.gain,
        })
      );

      const effectName = EFFECT_LABELS[params.type] || 'Filter';
      const command = new EffectCommand(
        audioBuffer,
        modifiedBuffer,
        (buffer) => loadBuffer(buffer),
        selection
          ? `${effectName} Selection (${params.frequency.toFixed(0)}Hz)`
          : `${effectName} (${params.frequency.toFixed(0)}Hz)`
      );
      execute(command);

      addToast({
        title: effectName,
        description: selection
          ? `Applied ${effectName.toLowerCase()} to selection (${params.frequency.toFixed(0)}Hz)`
          : `Applied ${effectName.toLowerCase()} (${params.frequency.toFixed(0)}Hz)`,
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      addToast({
        title: 'Error',
        description: 'Failed to apply effect',
        variant: 'error',
        duration: 3000,
      });
    }
  };

  // Handle dynamics apply from parameter dialog
  const handleDynamicsApply = async (params: DynamicsParameters) => {
    if (!audioBuffer) return;

    try {
      let modifiedBuffer: AudioBuffer;
      let effectName: string;

      switch (params.type) {
        case 'compressor':
          modifiedBuffer = await applyAsyncEffectToSelection(
            audioBuffer,
            selection,
            (buf) => applyCompressor(buf, params)
          );
          effectName = 'Compressor';
          break;
        case 'limiter':
          modifiedBuffer = await applyAsyncEffectToSelection(
            audioBuffer,
            selection,
            (buf) => applyLimiter(buf, params)
          );
          effectName = 'Limiter';
          break;
        case 'gate':
          modifiedBuffer = await applyAsyncEffectToSelection(
            audioBuffer,
            selection,
            (buf) => applyGate(buf, params)
          );
          effectName = 'Gate';
          break;
      }

      const command = new EffectCommand(
        audioBuffer,
        modifiedBuffer,
        (buffer) => loadBuffer(buffer),
        selection
          ? `${effectName} Selection (${params.threshold.toFixed(1)}dB)`
          : `${effectName} (${params.threshold.toFixed(1)}dB)`
      );
      execute(command);

      addToast({
        title: effectName,
        description: selection
          ? `Applied ${effectName.toLowerCase()} to selection`
          : `Applied ${effectName.toLowerCase()}`,
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      addToast({
        title: 'Error',
        description: 'Failed to apply dynamics effect',
        variant: 'error',
        duration: 3000,
      });
    }
  };

  // Handle time-based apply from parameter dialog
  const handleTimeBasedApply = async (params: TimeBasedParameters) => {
    if (!audioBuffer) return;

    try {
      let modifiedBuffer: AudioBuffer;
      let effectName: string;

      switch (params.type) {
        case 'delay':
          modifiedBuffer = await applyAsyncEffectToSelection(
            audioBuffer,
            selection,
            (buf) => applyDelay(buf, params)
          );
          effectName = 'Delay';
          break;
        case 'reverb':
          modifiedBuffer = await applyAsyncEffectToSelection(
            audioBuffer,
            selection,
            (buf) => applyReverb(buf, params)
          );
          effectName = 'Reverb';
          break;
        case 'chorus':
          modifiedBuffer = await applyAsyncEffectToSelection(
            audioBuffer,
            selection,
            (buf) => applyChorus(buf, params)
          );
          effectName = 'Chorus';
          break;
        case 'flanger':
          modifiedBuffer = await applyAsyncEffectToSelection(
            audioBuffer,
            selection,
            (buf) => applyFlanger(buf, params)
          );
          effectName = 'Flanger';
          break;
        case 'phaser':
          modifiedBuffer = await applyAsyncEffectToSelection(
            audioBuffer,
            selection,
            (buf) => applyPhaser(buf, params)
          );
          effectName = 'Phaser';
          break;
      }

      const command = new EffectCommand(
        audioBuffer,
        modifiedBuffer,
        (buffer) => loadBuffer(buffer),
        selection
          ? `${effectName} Selection`
          : `${effectName}`
      );
      execute(command);

      addToast({
        title: effectName,
        description: selection
          ? `Applied ${effectName.toLowerCase()} to selection`
          : `Applied ${effectName.toLowerCase()}`,
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      addToast({
        title: 'Error',
        description: 'Failed to apply time-based effect',
        variant: 'error',
        duration: 3000,
      });
    }
  };

  const handleAdvancedApply = async (params: AdvancedParameters) => {
    if (!audioBuffer) return;

    try {
      let modifiedBuffer: AudioBuffer;
      let effectName: string;

      const effectType = params.type;

      if (effectType === 'pitch') {
        modifiedBuffer = await applyAsyncEffectToSelection(
          audioBuffer,
          selection,
          (buf) => applyPitchShift(buf, params as any)
        );
        effectName = 'Pitch Shift';
      } else if (effectType === 'timestretch') {
        modifiedBuffer = await applyAsyncEffectToSelection(
          audioBuffer,
          selection,
          (buf) => applyTimeStretch(buf, params as any)
        );
        effectName = 'Time Stretch';
      } else if (effectType === 'bitcrusher') {
        modifiedBuffer = await applyAsyncEffectToSelection(
          audioBuffer,
          selection,
          (buf) => applyBitcrusher(buf, params as any)
        );
        effectName = 'Bitcrusher';
      } else {
        modifiedBuffer = await applyAsyncEffectToSelection(
          audioBuffer,
          selection,
          (buf) => applyDistortion(buf, params as any)
        );
        effectName = 'Distortion';
      }

      const command = new EffectCommand(
        audioBuffer,
        modifiedBuffer,
        (buffer) => loadBuffer(buffer),
        selection
          ? `${effectName} Selection`
          : `${effectName}`
      );
      execute(command);

      addToast({
        title: effectName,
        description: selection
          ? `Applied ${effectName.toLowerCase()} to selection`
          : `Applied ${effectName.toLowerCase()}`,
        variant: 'success',
        duration: 2000,
      });
    } catch (error) {
      addToast({
        title: 'Error',
        description: 'Failed to apply advanced effect',
        variant: 'error',
        duration: 3000,
      });
    }
  };

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

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

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

  // Auto-adjust scroll when zoom changes
  React.useEffect(() => {
    if (!audioBuffer) return;

    // Reset scroll if zoomed out completely
    if (zoom === 1) {
      setScrollOffset(0);
    }
  }, [zoom, audioBuffer]);

  // 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();
        if (isPlaying) {
          pause();
        } else {
          play();
        }
        return;
      }

      // Prevent other shortcuts if typing in an input
      if (isTyping) {
        return;
      }

      // Ctrl+Z: Undo
      if (e.ctrlKey && !e.shiftKey && e.key === 'z') {
        e.preventDefault();
        if (undo()) {
          addToast({
            title: 'Undo',
            description: 'Last action undone',
            variant: 'info',
            duration: 1500,
          });
        }
      }

      // Ctrl+Y or Ctrl+Shift+Z: Redo
      if ((e.ctrlKey && e.key === 'y') || (e.ctrlKey && e.shiftKey && e.key === 'z')) {
        e.preventDefault();
        if (redo()) {
          addToast({
            title: 'Redo',
            description: 'Last action redone',
            variant: 'info',
            duration: 1500,
          });
        }
      }

      // Ctrl+A: Select all
      if (e.ctrlKey && e.key === 'a') {
        e.preventDefault();
        handleSelectAll();
      }

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

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

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

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

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

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [selection, clipboard, audioBuffer, currentTime, undo, redo, addToast, isPlaying, play, pause]);

  // Show error toast
  React.useEffect(() => {
    if (error) {
      addToast({
        title: 'Error',
        description: error,
        variant: 'error',
        duration: 5000,
      });
    }
  }, [error, addToast]);

  // 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: '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 at current position',
        shortcut: 'Ctrl+V',
        category: 'edit',
        action: handlePaste,
      },
      {
        id: 'delete',
        label: 'Delete',
        description: 'Delete selection',
        shortcut: 'Del',
        category: 'edit',
        action: handleDelete,
      },
      {
        id: 'trim',
        label: 'Trim to Selection',
        description: 'Trim audio to selected region',
        category: 'edit',
        action: handleTrim,
      },
      {
        id: 'select-all',
        label: 'Select All',
        description: 'Select entire audio',
        shortcut: 'Ctrl+A',
        category: 'edit',
        action: handleSelectAll,
      },
      {
        id: 'clear-selection',
        label: 'Clear Selection',
        description: 'Clear current selection',
        shortcut: 'Esc',
        category: 'edit',
        action: handleClearSelection,
      },
      // View
      {
        id: 'zoom-in',
        label: 'Zoom In',
        description: 'Zoom in on waveform',
        category: 'view',
        action: handleZoomIn,
      },
      {
        id: 'zoom-out',
        label: 'Zoom Out',
        description: 'Zoom out on waveform',
        category: 'view',
        action: handleZoomOut,
      },
      {
        id: 'fit-to-view',
        label: 'Fit to View',
        description: 'Reset zoom to fit entire waveform',
        category: 'view',
        action: handleFitToView,
      },
      // File
      {
        id: 'clear',
        label: 'Clear Audio',
        description: 'Remove loaded audio file',
        category: 'file',
        action: handleClear,
      },
      // History
      {
        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+Y',
        category: 'edit',
        action: redo,
      },
      // Effects
      {
        id: 'normalize',
        label: 'Normalize',
        description: 'Normalize audio to peak amplitude',
        category: 'effects',
        action: handleNormalize,
      },
      {
        id: 'fade-in',
        label: 'Fade In',
        description: 'Apply fade in to selection',
        category: 'effects',
        action: handleFadeIn,
      },
      {
        id: 'fade-out',
        label: 'Fade Out',
        description: 'Apply fade out to selection',
        category: 'effects',
        action: handleFadeOut,
      },
      {
        id: 'reverse',
        label: 'Reverse',
        description: 'Reverse entire audio',
        category: 'effects',
        action: handleReverse,
      },
      {
        id: 'lowpass-filter',
        label: 'Low-Pass Filter',
        description: 'Remove high frequencies (1000Hz cutoff)',
        category: 'effects',
        action: handleLowPassFilter,
      },
      {
        id: 'highpass-filter',
        label: 'High-Pass Filter',
        description: 'Remove low frequencies (100Hz cutoff)',
        category: 'effects',
        action: handleHighPassFilter,
      },
      {
        id: 'bandpass-filter',
        label: 'Band-Pass Filter',
        description: 'Isolate frequency range (1000Hz center)',
        category: 'effects',
        action: handleBandPassFilter,
      },
      {
        id: 'compressor',
        label: 'Compressor',
        description: 'Reduce dynamic range',
        category: 'effects',
        action: handleCompressor,
      },
      {
        id: 'limiter',
        label: 'Limiter',
        description: 'Prevent audio from exceeding threshold',
        category: 'effects',
        action: handleLimiter,
      },
      {
        id: 'gate',
        label: 'Gate/Expander',
        description: 'Reduce volume of quiet sounds',
        category: 'effects',
        action: handleGate,
      },
      {
        id: 'delay',
        label: 'Delay/Echo',
        description: 'Add echo effects with feedback',
        category: 'effects',
        action: handleDelay,
      },
      {
        id: 'reverb',
        label: 'Reverb',
        description: 'Add acoustic space and ambience',
        category: 'effects',
        action: handleReverb,
      },
      {
        id: 'chorus',
        label: 'Chorus',
        description: 'Thicken sound with modulation',
        category: 'effects',
        action: handleChorus,
      },
      {
        id: 'flanger',
        label: 'Flanger',
        description: 'Create sweeping comb-filter effect',
        category: 'effects',
        action: handleFlanger,
      },
      {
        id: 'phaser',
        label: 'Phaser',
        description: 'Phase-shifting swoosh effect',
        category: 'effects',
        action: handlePhaser,
      },
      {
        id: 'pitch',
        label: 'Pitch Shifter',
        description: 'Change pitch without affecting duration',
        category: 'effects',
        action: handlePitchShift,
      },
      {
        id: 'timestretch',
        label: 'Time Stretch',
        description: 'Change duration without affecting pitch',
        category: 'effects',
        action: handleTimeStretch,
      },
      {
        id: 'distortion',
        label: 'Distortion',
        description: 'Add overdrive and distortion',
        category: 'effects',
        action: handleDistortion,
      },
      {
        id: 'bitcrusher',
        label: 'Bitcrusher',
        description: 'Lo-fi bit depth and sample rate reduction',
        category: 'effects',
        action: handleBitcrusher,
      },
    ];
    return actions;
  }, [play, pause, stop, handleCut, handleCopy, handlePaste, handleDelete, handleTrim, handleSelectAll, handleClearSelection, handleZoomIn, handleZoomOut, handleFitToView, handleClear, undo, redo, handleNormalize, handleFadeIn, handleFadeOut, handleReverse, handleLowPassFilter, handleHighPassFilter, handleBandPassFilter, handleCompressor, handleLimiter, handleGate, handleDelay, handleReverb, handleChorus, handleFlanger, handlePhaser, handlePitchShift, handleTimeStretch, handleDistortion, handleBitcrusher]);

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

        {/* Right: Command Palette + Theme Toggle */}
        <div className="flex items-center gap-2 flex-shrink-0">
          <CommandPalette actions={commandActions} />
          <ThemeToggle />
        </div>
      </header>

      {/* Main content area */}
      <div className="flex flex-1 overflow-hidden">
        {/* Side Panel */}
        <SidePanel
          fileName={fileName}
          audioBuffer={audioBuffer}
          onFileSelect={handleFileSelect}
          onClear={handleClear}
          selection={selection}
          historyState={historyState}
          effectChain={effectChain}
          effectPresets={effectPresets}
          onToggleEffect={toggleEffectEnabled}
          onRemoveEffect={removeEffect}
          onReorderEffects={reorderEffects}
          onSavePreset={savePreset}
          onLoadPreset={loadPresetToChain}
          onDeletePreset={deletePreset}
          onClearChain={clearChain}
          onNormalize={handleNormalize}
          onFadeIn={handleFadeIn}
          onFadeOut={handleFadeOut}
          onReverse={handleReverse}
          onLowPassFilter={handleLowPassFilter}
          onHighPassFilter={handleHighPassFilter}
          onBandPassFilter={handleBandPassFilter}
          onCompressor={handleCompressor}
          onLimiter={handleLimiter}
          onGate={handleGate}
          onDelay={handleDelay}
          onReverb={handleReverb}
          onChorus={handleChorus}
          onFlanger={handleFlanger}
          onPhaser={handlePhaser}
          onPitchShift={handlePitchShift}
          onTimeStretch={handleTimeStretch}
          onDistortion={handleDistortion}
          onBitcrusher={handleBitcrusher}
          tracks={tracks}
          onAddTrack={addTrack}
          onImportTracks={handleImportTracks}
          onConvertToTrack={handleConvertToTrack}
          onClearTracks={handleClearTracks}
        />

        {/* Main canvas area */}
        <main className="flex-1 flex flex-col overflow-hidden bg-background">
          {isLoading ? (
            <div className="flex-1 flex items-center justify-center">
              <div className="flex flex-col items-center gap-3">
                <Loader2 className="h-8 w-8 animate-spin text-primary" />
                <p className="text-sm text-muted-foreground">Loading audio file...</p>
              </div>
            </div>
          ) : viewMode === 'tracks' ? (
            <>
              {/* Multi-Track View */}
              <div className="flex-1 flex flex-col overflow-hidden">
                <TrackList
                  tracks={tracks}
                  zoom={zoom}
                  currentTime={multiTrackCurrentTime}
                  duration={multiTrackDuration}
                  onAddTrack={addTrack}
                  onImportTrack={handleImportTrack}
                  onRemoveTrack={removeTrack}
                  onUpdateTrack={updateTrack}
                  onSeek={seekMultiTrack}
                />
              </div>

              {/* Multi-Track Playback Controls */}
              <div className="border-t border-border bg-card p-3">
                <PlaybackControls
                  isPlaying={isMultiTrackPlaying}
                  isPaused={!isMultiTrackPlaying}
                  currentTime={multiTrackCurrentTime}
                  duration={multiTrackDuration}
                  volume={1}
                  onPlay={playMultiTrack}
                  onPause={pauseMultiTrack}
                  onStop={stopMultiTrack}
                  onSeek={seekMultiTrack}
                  onVolumeChange={() => {}}
                  currentTimeFormatted={`${Math.floor(multiTrackCurrentTime / 60)}:${String(Math.floor(multiTrackCurrentTime % 60)).padStart(2, '0')}`}
                  durationFormatted={`${Math.floor(multiTrackDuration / 60)}:${String(Math.floor(multiTrackDuration % 60)).padStart(2, '0')}`}
                />
              </div>
            </>
          ) : audioBuffer ? (
            <>
              {/* Waveform - takes maximum space */}
              <div className="flex-1 flex flex-col p-4 overflow-hidden">
                <Waveform
                  audioBuffer={audioBuffer}
                  currentTime={currentTime}
                  duration={duration}
                  onSeek={seek}
                  height={200}
                  zoom={zoom}
                  scrollOffset={scrollOffset}
                  amplitudeScale={amplitudeScale}
                  selection={selection}
                  onSelectionChange={setSelection}
                />

                {/* Horizontal scroll for zoomed waveform */}
                {zoom > 1 && (
                  <div className="mt-4 space-y-2">
                    <label className="text-xs font-medium text-muted-foreground">
                      Scroll Position
                    </label>
                    <Slider
                      value={scrollOffset}
                      onChange={setScrollOffset}
                      min={0}
                      max={Math.max(0, (800 * zoom) - 800)}
                      step={1}
                    />
                  </div>
                )}
              </div>

              {/* Playback Controls - fixed at bottom */}
              <div className="border-t border-border bg-card p-3">
                <PlaybackControls
                  isPlaying={isPlaying}
                  isPaused={isPaused}
                  currentTime={currentTime}
                  duration={duration}
                  volume={volume}
                  onPlay={play}
                  onPause={pause}
                  onStop={stop}
                  onSeek={seek}
                  onVolumeChange={setVolume}
                  currentTimeFormatted={currentTimeFormatted}
                  durationFormatted={durationFormatted}
                />
              </div>
            </>
          ) : (
            <div
              className={cn(
                "flex-1 flex items-center justify-center p-8 transition-colors cursor-pointer",
                isDragging && "bg-primary/5 border-2 border-dashed border-primary"
              )}
              onDragEnter={handleDragEnter}
              onDragLeave={handleDragLeave}
              onDragOver={handleDragOver}
              onDrop={handleDrop}
              onClick={handleDropZoneClick}
            >
              <input
                ref={fileInputRef}
                type="file"
                accept="audio/*"
                onChange={handleFileInputChange}
                className="hidden"
              />
              <div className="max-w-md text-center space-y-4">
                <p className="text-lg font-medium text-foreground">
                  {isDragging ? 'Drop audio file here' : 'No audio file loaded'}
                </p>
                <p className="text-sm text-muted-foreground">
                  {isDragging
                    ? 'Release to load the file'
                    : 'Click here or use the side panel to load an audio file, or drag and drop a file onto this area.'}
                </p>
              </div>
            </div>
          )}
        </main>
      </div>

      {/* Effect Parameter Dialog */}
      <EffectParameterDialog
        open={effectDialogOpen}
        onClose={() => setEffectDialogOpen(false)}
        effectType={effectDialogType}
        onApply={handleEffectApply}
        sampleRate={audioBuffer?.sampleRate}
      />

      {/* Dynamics Parameter Dialog */}
      <DynamicsParameterDialog
        open={dynamicsDialogOpen}
        onClose={() => setDynamicsDialogOpen(false)}
        effectType={dynamicsDialogType}
        onApply={handleDynamicsApply}
      />

      {/* Time-Based Parameter Dialog */}
      <TimeBasedParameterDialog
        open={timeBasedDialogOpen}
        onClose={() => setTimeBasedDialogOpen(false)}
        effectType={timeBasedDialogType}
        onApply={handleTimeBasedApply}
      />

      {/* Advanced Parameter Dialog */}
      <AdvancedParameterDialog
        open={advancedDialogOpen}
        onClose={() => setAdvancedDialogOpen(false)}
        effectType={advancedDialogType}
        onApply={handleAdvancedApply}
      />

      {/* Import Track Dialog */}
      <ImportTrackDialog
        open={importDialogOpen}
        onClose={() => setImportDialogOpen(false)}
        onImportTrack={handleImportTrack}
      />
    </>
  );
}
