import React, { useState, useEffect, useRef } from 'react';
import LandingPage from './LandingPage';
import { supabase } from './supabaseClient';
import {
  Mic,
  Upload,
  Play,
  Square,
  Volume2,
  VolumeX,
  Terminal,
  Settings,
  Radio,
  Info,
  AlertCircle,
  CheckCircle,
  Sparkles,
  Power,
  Loader2,
  Trash2,
  Podcast,
  Headset,
  Newspaper,
  Volume1,
  PlayCircle,
  Plus,
  Music,
  Edit2
} from 'lucide-react';

const SAMPLING_RATE = 24000;

function App() {
  const [currentView, setCurrentView] = useState('landing');
  const [savedVoices, setSavedVoices] = useState([]);
  const [podcastHistory, setPodcastHistory] = useState([]);

  // Model & Server Status States
  const [modelStatus, setModelStatus] = useState({
    useRealModel: true,
    modelId: 'microsoft/VibeVoice-Realtime-0.5B',
    loaded: false,
    loading: true,
    error: null,
    device: 'CPU'
  });
  const [wsConnected, setWsConnected] = useState(false);
  const [togglingModel, setTogglingModel] = useState(false);

  // Script & Synthesis States
  const [script, setScript] = useState(
    "Speaker 0: Welcome to Vibe Voice Studio. I am cloned from your custom voice sample.\nSpeaker 1: That is incredible! The transition between speakers sounds so smooth and natural.\nSpeaker 0: Yes, Microsoft's continuous acoustic tokenizers make multi-speaker podcasts sound beautiful."
  );
  const [streamMode, setStreamMode] = useState(true);
  const [agentState, setAgentState] = useState({
    status: 'idle', // idle, thinking, speaking, listening
    title: 'AGENT READY',
    sub: 'Configure scripts and trigger generation below'
  });

  // Audio Playback UI States
  const [isAudioPlayingState, setIsAudioPlayingState] = useState(false);
  const [volume, setVolume] = useState(80);
  const [speed, setSpeed] = useState('1.0');
  const [timeline, setTimeline] = useState({ elapsed: 0, total: 0 });
  const [showToolbar, setShowToolbar] = useState(false);

  // Speaker Slots States (Voice Cloning)
  const [speakers, setSpeakers] = useState([
    { id: 0, name: 'Alex', isRecording: false, voicePath: null, previewUrl: null, role: 'Primary Speaker', color: 'cyan' },
    { id: 1, name: 'Sarah', isRecording: false, voicePath: null, previewUrl: null, role: 'Dialogue Partner', color: 'purple' }
  ]);

  // Master Export Hub State
  const [compiledAudioUrl, setCompiledAudioUrl] = useState(null);
  const [compiledAudioMode, setCompiledAudioMode] = useState(null); // 'stream' or 'file'
  const accumulatedSessionChunksRef = useRef([]);

  // Preview Voice Reference Playback State
  const [playingPreviewId, setPlayingPreviewId] = useState(null);
  const previewSourceRef = useRef(null);

  // Custom Naming Modal State
  const [namingModal, setNamingModal] = useState({
    isOpen: false,
    fileBlob: null,
    speakerId: null,
    defaultName: ''
  });
  const [voiceNameInput, setVoiceNameInput] = useState('');

  // Custom Action (Rename/Delete) Modal State
  const [actionModal, setActionModal] = useState({
    isOpen: false,
    type: '', // 'rename_voice', 'delete_voice', 'rename_podcast', 'delete_podcast'
    id: null,
    oldValue: '',
    inputValue: '',
    audioUrl: '',
    profileName: ''
  });

  // Console Logs State
  const [logs, setLogs] = useState([
    { type: 'system', text: 'Welcome to VibeVoice React Studio Console. System ready.', time: new Date().toLocaleTimeString() },
    { type: 'info', text: 'VibeVoice neural weights loading directly on local CPU. Real-time zero-shot synthesis active.', time: new Date().toLocaleTimeString() }
  ]);

  // Web Audio Context & Playback References
  const audioCtxRef = useRef(null);
  const analyserNodeRef = useRef(null);
  const gainNodeRef = useRef(null);
  const wsRef = useRef(null);
  
  // Streaming Queue Refs (Gapless Playback)
  const playbackQueueRef = useRef([]);
  const nextPlayTimeRef = useRef(0);
  const isStreamingActiveRef = useRef(false);
  const scheduledSourcesRef = useRef([]);
  const doneReceivedRef = useRef(false);
  
  // Traditional REST Player Refs
  const traditionalSourceRef = useRef(null);
  const traditionalStartClockRef = useRef(0);
  const traditionalDurationRef = useRef(0);

  // Microphone Recording Refs
  const mediaRecordersRef = useRef([null, null]);
  const audioChunksRef = useRef([[], []]);

  // UI Canvas Visualizer Refs
  const canvasRef = useRef(null);

  // ==========================================================================
  // Console Log Helper
  // ==========================================================================
  const addLog = (type, text) => {
    setLogs(prev => [
      ...prev,
      { type, text, time: new Date().toLocaleTimeString() }
    ]);
  };

  // Scroll Console to Bottom
  useEffect(() => {
    const consoleBody = document.getElementById('consoleBody');
    if (consoleBody) {
      consoleBody.scrollTop = consoleBody.scrollHeight;
    }
  }, [logs]);

  // ==========================================================================
  // Server Status & WebSocket Handshakes
  // ==========================================================================
  const checkServerStatus = async () => {
    try {
      const res = await fetch('/api/status');
      const data = await res.json();
      
      setModelStatus({
        useRealModel: data.use_real_model,
        modelId: data.model_id,
        loaded: data.loaded,
        loading: data.loading,
        error: data.error,
        device: data.device
      });
    } catch (e) {
      addLog('error', 'Failed to connect to VibeVoice backend API server.');
    }
  };

  const fetchSavedVoices = async () => {
    try {
      const { data, error } = await supabase.from('voice_profiles').select('*');
      if (error) throw error;
      setSavedVoices(data || []);
      addLog('info', `Fetched ${data?.length || 0} saved voice profiles from Supabase.`);
      
      // Auto-assign matching saved voices to speakers by name to get "old audio input" instantly!
      if (data && data.length > 0) {
        setSpeakers(prev => prev.map(s => {
          const matched = data.find(v => v.name.trim().toLowerCase() === s.name.trim().toLowerCase());
          if (matched && !s.voicePath) {
            addLog('info', `Auto-loaded saved voice profile "${matched.name}" into Speaker ${s.id} slot.`);
            return {
              ...s,
              voicePath: matched.audio_url,
              previewUrl: matched.audio_url
            };
          }
          return s;
        }));
      }
    } catch (err) {
      addLog('error', 'Failed to fetch saved voice profiles from Supabase: ' + err.message);
    }
  };

  const fetchPodcastHistory = async () => {
    try {
      const { data, error } = await supabase
        .from('podcast_history')
        .select('*')
        .order('created_at', { ascending: false });
      if (error) throw error;
      setPodcastHistory(data || []);
      addLog('info', `Fetched ${data?.length || 0} archived podcasts from Supabase.`);
    } catch (err) {
      addLog('error', 'Failed to fetch podcast history: ' + err.message);
    }
  };

  const savePodcastToHistory = async (wavBlob, textScript, mode) => {
    try {
      addLog('info', 'Archiving generated podcast to Supabase permanent storage...');
      const fileName = `podcast_${Date.now()}.wav`;

      // 1. Upload to storage
      const { data: storageData, error: storageError } = await supabase
        .storage
        .from('voice_samples')
        .upload(fileName, wavBlob);

      if (storageError) throw storageError;

      // 2. Get public url
      const { data: publicUrlData } = supabase
        .storage
        .from('voice_samples')
        .getPublicUrl(fileName);

      const publicUrl = publicUrlData.publicUrl;

      // 3. Insert metadata record into DB
      const primaryVoice = speakers[0]?.voicePath || null;
      const matchingProfile = primaryVoice ? savedVoices.find(v => v.audio_url === primaryVoice) : null;
      const voiceProfileId = matchingProfile ? matchingProfile.id : null;

      const { data: dbData, error: dbError } = await supabase
        .from('podcast_history')
        .insert([{
          title: `Podcast - ${new Date().toLocaleString()} (${mode})`,
          text_script: textScript,
          audio_url: publicUrl,
          speaker_id: 0,
          voice_profile_id: voiceProfileId
        }])
        .select();

      if (dbError) throw dbError;

      addLog('success', 'Podcast archived successfully to Supabase Database!');
      fetchPodcastHistory();
    } catch (err) {
      addLog('warning', `Failed to archive podcast to Supabase (${err.message}). Storing in local session memory...`);
      
      // Fallback: Create local preview URL for the compiled podcast WAV
      const localPreviewUrl = URL.createObjectURL(wavBlob);
      
      setPodcastHistory(prev => [
        {
          id: `local_${Date.now()}`,
          title: `Podcast - ${new Date().toLocaleString()} (${mode}) [Local Session]`,
          text_script: textScript,
          audio_url: localPreviewUrl,
          speaker_id: 0,
          voice_profile_id: null,
          created_at: new Date().toISOString()
        },
        ...prev
      ]);
      addLog('success', 'Podcast successfully cached in local session memory!');
    }
  };

  const saveTraditionalPodcastToHistory = async (audioUrl, textScript, mode) => {
    try {
      const response = await fetch(audioUrl);
      const blob = await response.blob();
      await savePodcastToHistory(blob, textScript, mode);
    } catch (err) {
      addLog('error', 'Failed to download compiled audio for archiving: ' + err.message);
    }
  };

  // --- Custom Action Modal Trigger Hooks ---
  const openRenameVoiceModal = (voiceId, oldName, audioUrl) => {
    setActionModal({
      isOpen: true,
      type: 'rename_voice',
      id: voiceId,
      oldValue: oldName,
      inputValue: oldName,
      audioUrl,
      profileName: oldName
    });
  };

  const openDeleteVoiceModal = (voiceId, oldName, audioUrl) => {
    setActionModal({
      isOpen: true,
      type: 'delete_voice',
      id: voiceId,
      oldValue: oldName,
      inputValue: '',
      audioUrl,
      profileName: oldName
    });
  };

  const openRenamePodcastModal = (podcastId, oldTitle) => {
    setActionModal({
      isOpen: true,
      type: 'rename_podcast',
      id: podcastId,
      oldValue: oldTitle,
      inputValue: oldTitle,
      audioUrl: '',
      profileName: oldTitle
    });
  };

  const openDeletePodcastModal = (podcastId, title, audioUrl) => {
    setActionModal({
      isOpen: true,
      type: 'delete_podcast',
      id: podcastId,
      oldValue: title,
      inputValue: '',
      audioUrl,
      profileName: title
    });
  };

  // --- Core execution functions invoked on Custom Modal Submit ---

  const executeRenamePodcast = async (podcastId, newTitle) => {
    if (!newTitle || newTitle.trim() === '') return;
    try {
      addLog('info', `Renaming podcast to "${newTitle.trim()}"...`);

      // Local podcast session
      if (typeof podcastId === 'string' && podcastId.startsWith('local_')) {
        setPodcastHistory(prev => prev.map(p => p.id === podcastId ? { ...p, title: newTitle.trim() } : p));
        addLog('success', `Podcast successfully renamed to "${newTitle.trim()}" locally.`);
        return;
      }

      // Supabase DB podcast
      const { error } = await supabase
        .from('podcast_history')
        .update({ title: newTitle.trim() })
        .eq('id', podcastId);

      if (error) throw error;

      addLog('success', `Podcast title successfully updated in Supabase Database!`);
      fetchPodcastHistory();
    } catch (err) {
      addLog('error', 'Failed to rename podcast: ' + err.message);
    }
  };

  const executeRenameVoice = async (voiceId, newName, audioUrl) => {
    if (!newName || newName.trim() === '') return;
    try {
      addLog('info', `Renaming voice profile to "${newName.trim()}"...`);
      
      // Local voice profiles
      if (typeof voiceId === 'string' && voiceId.startsWith('local_')) {
        setSavedVoices(prev => prev.map(v => v.id === voiceId ? { ...v, name: newName.trim() } : v));
        
        // Update speakers
        setSpeakers(prev => prev.map(s => {
          if (s.voicePath === audioUrl) {
            return { ...s, name: newName.trim() };
          }
          return s;
        }));
        
        addLog('success', `Voice profile successfully renamed to "${newName.trim()}" locally.`);
        return;
      }

      // Supabase
      const { error } = await supabase
        .from('voice_profiles')
        .update({ name: newName.trim() })
        .eq('id', voiceId);

      if (error) throw error;

      addLog('success', `Voice profile successfully renamed in database!`);
      
      // Update state immediately
      setSavedVoices(prev => prev.map(v => v.id === voiceId ? { ...v, name: newName.trim() } : v));
      
      // Also update any speaker slot using it
      setSpeakers(prev => prev.map(s => {
        if (s.voicePath === audioUrl) {
          return { ...s, name: newName.trim() };
        }
        return s;
      }));
    } catch (err) {
      addLog('error', `Failed to rename voice profile: ${err.message}`);
    }
  };

  const executeDeleteVoice = async (voiceId, audioUrl, profileName) => {
    try {
      addLog('info', `Deleting voice profile "${profileName}"...`);
      
      // Clear voice path of speakers who use this profile
      setSpeakers(prev => prev.map(s => s.voicePath === audioUrl ? { ...s, voicePath: null, previewUrl: null } : s));

      // Local voice profile
      if (typeof voiceId === 'string' && (voiceId.startsWith('local_') || voiceId.endsWith('.wav'))) {
        setSavedVoices(prev => prev.filter(v => v.id !== voiceId));
        
        if (audioUrl && audioUrl.startsWith('/static/cloned_voices/')) {
          const filename = audioUrl.split('/').pop();
          try {
            await fetch(`/api/delete-voice/${filename}`, { method: 'DELETE' });
          } catch(e) {}
        }
        
        addLog('success', `Voice profile "${profileName}" removed from local session.`);
        return;
      }

      // Database profile
      const { error: dbError } = await supabase
        .from('voice_profiles')
        .delete()
        .eq('id', voiceId);

      if (dbError) throw dbError;

      // Extract filename from URL and delete from storage
      if (audioUrl) {
        try {
          const filePart = audioUrl.split('/').pop();
          if (filePart) {
            await supabase.storage.from('voice_samples').remove([filePart]);
          }
        } catch (storageErr) {
          console.warn('Failed to delete voice profile from Storage:', storageErr);
        }
      }

      addLog('success', `Voice profile "${profileName}" successfully deleted from Supabase.`);
      fetchSavedVoices();
    } catch (err) {
      addLog('error', `Failed to delete voice profile: ${err.message}`);
    }
  };

  const executeDeletePodcast = async (id, audioUrl, title) => {
    try {
      addLog('info', `Deleting podcast "${title}" from archive...`);
      
      if (typeof id === 'string' && id.startsWith('local_')) {
        setPodcastHistory(prev => prev.filter(p => p.id !== id));
        addLog('success', 'Podcast deleted successfully from local session memory.');
        return;
      }
      
      // 1. Delete from database
      const { error: dbError } = await supabase
        .from('podcast_history')
        .delete()
        .eq('id', id);
      if (dbError) throw dbError;

      // 2. Try to extract filename from URL and delete from Storage
      try {
        const filePart = audioUrl.split('/').pop();
        if (filePart) {
          await supabase.storage.from('voice_samples').remove([filePart]);
        }
      } catch (err) {
        console.warn('Failed to delete audio file from Storage:', err);
      }

      addLog('success', 'Podcast deleted successfully.');
      fetchPodcastHistory();
    } catch (err) {
      addLog('error', 'Failed to delete podcast: ' + err.message);
    }
  };

  const playHistoryPodcast = async (podcast) => {
    initAudio();
    handleStopPlayback(); // Stop any other playing sessions
    
    try {
      addLog('info', `Streaming archived podcast: "${podcast.title}"...`);
      setIsAudioPlayingState(true);
      setCompiledAudioUrl(podcast.audio_url);
      setCompiledAudioMode('file');
      loadTraditionalWav(podcast.audio_url);
    } catch (e) {
      addLog('error', 'Failed to play archived podcast.');
      handleStopPlayback();
    }
  };

  useEffect(() => {
    addLog('system', 'Initializing VibeVoice Studio environment...');
    checkServerStatus();
    fetchSavedVoices();
    fetchPodcastHistory();
    
    
    // Poll server status periodically if loading
    const interval = setInterval(() => {
      checkServerStatus();
    }, 4000);

    return () => clearInterval(interval);
  }, []);

  // WebSocket Connection Manager
  useEffect(() => {
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    const host = window.location.host;
    const wsUrl = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
      ? 'ws://127.0.0.1:8000/api/stream'
      : `${protocol}//${host}/api/stream`;
    
    addLog('system', `Opening real-time WebSocket connection to ${wsUrl}`);
    const websocket = new WebSocket(wsUrl);
    wsRef.current = websocket;

    websocket.onopen = () => {
      setWsConnected(true);
      addLog('success', 'WebSocket real-time streaming link ESTABLISHED.');
    };

    websocket.onclose = () => {
      setWsConnected(false);
      addLog('error', 'WebSocket streaming link disconnected. Retrying connection...');
    };

    websocket.onerror = () => {
      addLog('error', 'WebSocket encountered connection error.');
    };

    websocket.onmessage = async (event) => {
      if (typeof event.data === 'string') {
        const data = JSON.parse(event.data);
        if (data.type === 'word') {
          addLog('word', `Agent spoke word: "${data.word}"`);
        } else if (data.type === 'done') {
          addLog('success', 'WebSocket voice generation chunk transfer complete.');
          doneReceivedRef.current = true;
          // Generate local Object URL of the accumulated chunks for mastering
          if (accumulatedSessionChunksRef.current.length > 0) {
            try {
              const wavBlob = exportWav(accumulatedSessionChunksRef.current, SAMPLING_RATE);
              const objectUrl = URL.createObjectURL(wavBlob);
              setCompiledAudioUrl(objectUrl);
              setCompiledAudioMode('stream');
              addLog('success', 'Master podcast output audio created and mastered for local export.');
              
              // Automatically archive to Supabase history
              savePodcastToHistory(wavBlob, script, 'WebSocket Stream');
            } catch (err) {
              addLog('error', `Failed to master session output: ${err.message}`);
            }
          }
          // If no sources are playing and queue is completely empty, finalize playback
          if (scheduledSourcesRef.current.length === 0 && playbackQueueRef.current.length === 0) {
            handleStopPlayback();
          }
        } else if (data.type === 'error') {
          addLog('error', `Server stream error: ${data.message}`);
          handleStopPlayback();
        }
      } else {
        // Raw Audio Binary Chunks
        const arrayBuffer = await event.data.arrayBuffer();
        const int16Array = new Int16Array(arrayBuffer);
        const float32Array = new Float32Array(int16Array.length);
        
        for (let i = 0; i < int16Array.length; i++) {
          float32Array[i] = int16Array[i] / 32767.0;
        }

        if (isStreamingActiveRef.current) {
          playbackQueueRef.current.push(float32Array);
          // Accumulate for session download
          accumulatedSessionChunksRef.current.push(float32Array);
          scheduleNextStreamingChunk();
        }
      }
    };

    return () => {
      if (websocket) websocket.close();
    };
  }, []);

  // ==========================================================================
  // Web Audio Context & Node Setup (Pillar 2 & 3)
  // ==========================================================================
  const initAudio = () => {
    if (audioCtxRef.current) return;

    const AudioContextClass = window.AudioContext || window.webkitAudioContext;
    const context = new AudioContextClass({ sampleRate: SAMPLING_RATE });
    audioCtxRef.current = context;

    const analyser = context.createAnalyser();
    analyser.fftSize = 256;
    analyserNodeRef.current = analyser;

    const gain = context.createGain();
    gain.gain.setValueAtTime(volume / 100, context.currentTime);
    gainNodeRef.current = gain;

    // Connect pipeline
    gain.connect(analyser);
    analyser.connect(context.destination);

    addLog('system', `Browser AudioContext engine running at ${SAMPLING_RATE}Hz.`);
  };

  useEffect(() => {
    if (gainNodeRef.current && audioCtxRef.current) {
      gainNodeRef.current.gain.setValueAtTime(volume / 100, audioCtxRef.current.currentTime);
    }
  }, [volume]);

  // Streaming Gapless Playback Logic
  const startStreamingPlayback = () => {
    initAudio();
    if (audioCtxRef.current.state === 'suspended') {
      audioCtxRef.current.resume();
    }

    playbackQueueRef.current = [];
    accumulatedSessionChunksRef.current = []; // Clear previous export session chunks
    scheduledSourcesRef.current = [];
    doneReceivedRef.current = false;
    nextPlayTimeRef.current = audioCtxRef.current.currentTime + 0.15;
    isStreamingActiveRef.current = true;
    setIsAudioPlayingState(true);

    setAgentState({
      status: 'speaking',
      title: 'STREAMING SPEECH',
      sub: 'Synthesizing voice chunks in real-time over WebSocket...'
    });
    addLog('info', 'WebSocket player active. Buffering and playing...');
  };

  const scheduleNextStreamingChunk = () => {
    if (!isStreamingActiveRef.current || playbackQueueRef.current.length === 0) return;

    const chunk = playbackQueueRef.current.shift();
    if (!chunk || chunk.length === 0) return;

    const context = audioCtxRef.current;
    const buffer = context.createBuffer(1, chunk.length, SAMPLING_RATE);
    buffer.copyToChannel(chunk, 0);

    const source = context.createBufferSource();
    source.buffer = buffer;
    source.playbackRate.value = parseFloat(speed);
    source.connect(gainNodeRef.current);

    const startTime = Math.max(context.currentTime, nextPlayTimeRef.current);
    source.start(startTime);

    scheduledSourcesRef.current.push(source);
    
    const duration = buffer.duration / source.playbackRate.value;
    nextPlayTimeRef.current = startTime + duration;

    source.onended = () => {
      // Remove completed source
      scheduledSourcesRef.current = scheduledSourcesRef.current.filter(src => src !== source);
      
      // Check if queue is completely drained and done signal is received
      if (scheduledSourcesRef.current.length === 0 && playbackQueueRef.current.length === 0 && isStreamingActiveRef.current && doneReceivedRef.current) {
        handleStopPlayback();
        addLog('info', 'Agent voice stream play completed.');
      }
    };
  };

  const handleStopPlayback = () => {
    isStreamingActiveRef.current = false;
    playbackQueueRef.current = [];

    // Stop and clear all active buffers
    scheduledSourcesRef.current.forEach(src => {
      try { src.stop(); } catch(e) {}
    });
    scheduledSourcesRef.current = [];

    if (traditionalSourceRef.current) {
      try { traditionalSourceRef.current.stop(); } catch(e) {}
      traditionalSourceRef.current = null;
    }

    // Stop reference preview playback if active
    if (previewSourceRef.current) {
      try { previewSourceRef.current.stop(); } catch(e) {}
      previewSourceRef.current = null;
    }
    setPlayingPreviewId(null);

    setIsAudioPlayingState(false);
    setShowToolbar(false);
    setAgentState({
      status: 'idle',
      title: 'AGENT READY',
      sub: 'Configure scripts and trigger generation below'
    });
    addLog('system', 'Agent audio playback stopped.');
  };

  // ==========================================================================
  // Canvas Waves Drawing Loop (AnalyserNode hook)
  // ==========================================================================
  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    const width = canvas.width;
    const height = canvas.height;
    let animationFrameId;

    const renderWave = () => {
      animationFrameId = requestAnimationFrame(renderWave);

      ctx.fillStyle = 'rgba(7, 9, 14, 0.25)'; // Back-sweep fade
      ctx.fillRect(0, 0, width, height);

      let dataArray = null;
      let bufferLength = 0;

      if (analyserNodeRef.current && isAudioPlayingState) {
        bufferLength = analyserNodeRef.current.frequencyBinCount;
        dataArray = new Uint8Array(bufferLength);
        analyserNodeRef.current.getByteTimeDomainData(dataArray);
      }

      ctx.lineWidth = 2.5;
      ctx.shadowBlur = isAudioPlayingState ? 10 : 0;
      ctx.shadowColor = 'rgba(0, 242, 254, 0.4)';

      // Linear Neon color gradient across visualizer canvas
      const gradient = ctx.createLinearGradient(0, 0, width, 0);
      gradient.addColorStop(0, '#a259ff'); // Purple
      gradient.addColorStop(0.5, '#00f2fe'); // Cyan
      gradient.addColorStop(1, '#ff5c8d'); // Pink
      ctx.strokeStyle = gradient;

      ctx.beginPath();

      if (dataArray) {
        // Draw real sound wave oscillations
        const sliceWidth = width / bufferLength;
        let x = 0;
        for (let i = 0; i < bufferLength; i++) {
          const v = dataArray[i] / 128.0;
          const y = (v * height) / 2;
          if (i === 0) ctx.moveTo(x, y);
          else ctx.lineTo(x, y);
          x += sliceWidth;
        }
      } else {
        // Draw calm animated breathing flatline when quiet
        const points = 40;
        const sliceWidth = width / points;
        let x = 0;
        const time = Date.now() * 0.003;
        for (let i = 0; i < points; i++) {
          const breathing = Math.sin(time) * 0.2 + 0.8;
          const y = height / 2 + Math.sin(i * 0.15 + time * 2) * (2.5 * breathing);
          if (i === 0) ctx.moveTo(x, y);
          else ctx.lineTo(x, y);
          x += sliceWidth;
        }
      }

      ctx.lineTo(width, height / 2);
      ctx.stroke();
    };

    renderWave();

    return () => cancelAnimationFrame(animationFrameId);
  }, [isAudioPlayingState]);

  // ==========================================================================
  // Synthesis Triggers (REST vs WebSocket Stream)
  // ==========================================================================
  const handleSynthesize = async () => {
    const text = script.trim();
    if (!text) {
      addLog('error', 'Cannot synthesize. Text script field is empty!');
      return;
    }

    initAudio();
    handleStopPlayback(); // Halt ongoing audio runs

    // Map dynamic speaker voice paths
    const speakerVoices = {};
    speakers.forEach(s => {
      if (s.voicePath) {
        speakerVoices[s.id] = s.voicePath;
      }
    });

    // Reset master download url
    setCompiledAudioUrl(null);
    setCompiledAudioMode(null);

    if (streamMode) {
      // WS Streaming Mode
      if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {
        addLog('error', 'WebSocket is offline. Streaming mode disabled.');
        return;
      }

      startStreamingPlayback();
      wsRef.current.send(JSON.stringify({
        text,
        voice_sample_path: speakers[0]?.voicePath || null,
        speaker_id: 0,
        speaker_voices: speakerVoices
      }));

    } else {
      // Traditional File-based Playback Mode
      try {
        addLog('info', 'Compiling voice script... Sending POST to VibeVoice generator...');
        setAgentState({
          status: 'thinking',
          title: 'COMPILING AUDIO',
          sub: 'Running neural speech generation weights...'
        });
        setIsAudioPlayingState(true);

        const res = await fetch('/api/generate', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            text,
            voice_sample_path: speakers[0]?.voicePath || null,
            speaker_id: 0,
            speaker_voices: speakerVoices
          })
        });
        const data = await res.json();

        if (data.status === 'success') {
          addLog('success', `Voice file compiled. Method: [${data.mode}]. Playing track...`);
          loadTraditionalWav(data.audio_url);
          setCompiledAudioUrl(data.audio_url);
          setCompiledAudioMode('file');
          
          // Automatically fetch compiled file and archive to Supabase history
          saveTraditionalPodcastToHistory(data.audio_url, text, data.mode);
        } else {
          throw new Error('Server returned error response.');
        }
      } catch (e) {
        handleStopPlayback();
        addLog('error', `Synthesis failed: ${e.message}`);
      }
    }
  };

  const loadTraditionalWav = async (audioUrl) => {
    try {
      const res = await fetch(audioUrl);
      const arrayBuffer = await res.arrayBuffer();

      audioCtxRef.current.decodeAudioData(arrayBuffer, (decodedBuffer) => {
        const source = audioCtxRef.current.createBufferSource();
        source.buffer = decodedBuffer;
        source.playbackRate.value = parseFloat(speed);
        source.connect(gainNodeRef.current);
        source.start(0);

        traditionalSourceRef.current = source;
        traditionalDurationRef.current = decodedBuffer.duration;
        traditionalStartClockRef.current = audioCtxRef.current.currentTime;

        setAgentState({
          status: 'speaking',
          title: 'PLAYING FILE',
          sub: 'Streaming synthesized high-fidelity compiled audio track...'
        });
        setShowToolbar(true);
        setTimeline({ elapsed: 0, total: decodedBuffer.duration });

        const tickTimeline = () => {
          if (traditionalSourceRef.current === source) {
            const elapsed = (audioCtxRef.current.currentTime - traditionalStartClockRef.current) * parseFloat(speed);
            setTimeline(prev => ({ ...prev, elapsed: Math.min(elapsed, decodedBuffer.duration) }));
            if (elapsed < decodedBuffer.duration) {
              requestAnimationFrame(tickTimeline);
            }
          }
        };

        tickTimeline();

        source.onended = () => {
          if (traditionalSourceRef.current === source) {
            handleStopPlayback();
          }
        };

      }, (err) => {
        addLog('error', 'Failed to decode WAV file buffer.');
        handleStopPlayback();
      });
    } catch(e) {
      addLog('error', 'Error playing generated track.');
      handleStopPlayback();
    }
  };

  const formatTime = (seconds) => {
    const m = Math.floor(seconds / 60).toString().padStart(2, '0');
    const s = Math.floor(seconds % 60).toString().padStart(2, '0');
    return `${m}:${s}`;
  };

  const encodeWAV = (samples, sampleRate) => {
    const buffer = new ArrayBuffer(44 + samples.length * 2);
    const view = new DataView(buffer);

    const writeString = (view, offset, string) => {
      for (let i = 0; i < string.length; i++) {
        view.setUint8(offset + i, string.charCodeAt(i));
      }
    };

    const floatTo16BitPCM = (output, offset, input) => {
      for (let i = 0; i < input.length; i++, offset += 2) {
        let s = Math.max(-1, Math.min(1, input[i]));
        output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
      }
    };

    /* RIFF identifier */
    writeString(view, 0, 'RIFF');
    /* file length */
    view.setUint32(4, 36 + samples.length * 2, true);
    /* RIFF type */
    writeString(view, 8, 'WAVE');
    /* format chunk identifier */
    writeString(view, 12, 'fmt ');
    /* format chunk length */
    view.setUint32(16, 16, true);
    /* sample format (raw) */
    view.setUint16(20, 1, true);
    /* channel count */
    view.setUint16(22, 1, true);
    /* sample rate */
    view.setUint32(24, sampleRate, true);
    /* byte rate (sample rate * block align) */
    view.setUint32(28, sampleRate * 2, true);
    /* block align (channel count * bytes per sample) */
    view.setUint16(32, 2, true);
    /* bits per sample */
    view.setUint16(34, 16, true);
    /* data chunk identifier */
    writeString(view, 36, 'data');
    /* data chunk length */
    view.setUint32(40, samples.length * 2, true);

    floatTo16BitPCM(view, 44, samples);

    return new Blob([view], { type: 'audio/wav' });
  };

  // ==========================================================================
  // Voice Cloning Microphone Hooks (Pillar 4)
  // ==========================================================================
  const toggleRecording = async (speakerId) => {
    const speaker = speakers.find(s => s.id === speakerId);
    if (!speaker) return;

    if (speaker.isRecording) {
      // Stop recording
      const recorder = mediaRecordersRef.current[speakerId];
      if (recorder) {
        recorder.stop();
        setSpeakers(prev => prev.map(s => s.id === speakerId ? { ...s, isRecording: false } : s));
        setAgentState({
          status: 'idle',
          title: 'AGENT READY',
          sub: 'Voice profile recorded. Syncing to neural engine...'
        });
      }
    } else {
      // Start recording
      try {
        addLog('info', `Requesting mic permission for Speaker ${speakerId} (${speaker.name})...`);
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        
        setAgentState({
          status: 'listening',
          title: 'LISTENING...',
          sub: 'Speak normally for 10-15s to capture vocal signature...'
        });

        // Use independent default sample-rate AudioContext specifically for mic capture to avoid browser resampling bugs
        const RecordingContextClass = window.AudioContext || window.webkitAudioContext;
        const recContext = new RecordingContextClass();

        const source = recContext.createMediaStreamSource(stream);
        const processor = recContext.createScriptProcessor(4096, 1, 1);
        const recordingSamples = [];

        processor.onaudioprocess = (e) => {
          const channelData = e.inputBuffer.getChannelData(0);
          recordingSamples.push(new Float32Array(channelData));
        };

        source.connect(processor);
        processor.connect(recContext.destination);

        mediaRecordersRef.current[speakerId] = {
          stop: () => {
            source.disconnect(processor);
            processor.disconnect(recContext.destination);
            stream.getTracks().forEach(track => track.stop());
            recContext.close();

            addLog('info', 'Encoding microphone speech data to 16-bit PCM WAV...');
            let totalLength = 0;
            for (let i = 0; i < recordingSamples.length; i++) {
              totalLength += recordingSamples[i].length;
            }
            const flattened = new Float32Array(totalLength);
            let offset = 0;
            for (let i = 0; i < recordingSamples.length; i++) {
              flattened.set(recordingSamples[i], offset);
              offset += recordingSamples[i].length;
            }

            const wavBlob = encodeWAV(flattened, recContext.sampleRate);
            setNamingModal({
              isOpen: true,
              fileBlob: wavBlob,
              speakerId: speakerId,
              defaultName: speaker.name
            });
            setVoiceNameInput(speaker.name);
          }
        };

        setSpeakers(prev => prev.map(s => s.id === speakerId ? { ...s, isRecording: true } : s));
        addLog('success', 'Microphone recording started. Speak clearly now!');
      } catch (e) {
        addLog('error', `Microphone recording failed: ${e.message}`);
        setAgentState({
          status: 'idle',
          title: 'AGENT READY',
          sub: 'Record trigger failed or permission denied'
        });
      }
    }
  };

  const handleFileUpload = (e, speakerId) => {
    const file = e.target.files[0];
    if (!file) return;
    const speaker = speakers.find(s => s.id === speakerId);
    addLog('info', `Selected file for upload: ${file.name}`);
    const cleanFileName = file.name.replace(/\.[^/.]+$/, "");
    setNamingModal({
      isOpen: true,
      fileBlob: file,
      speakerId: speakerId,
      defaultName: cleanFileName
    });
    setVoiceNameInput(cleanFileName);
  };

  // Play/Stop Reference Voice Preview using main AudioContext pipeline
  const playPreview = async (speakerId, url) => {
    initAudio();
    handleStopPlayback(); // Stop any other playing session

    if (playingPreviewId === speakerId) {
      stopPreviewPlayback();
      return;
    }

    try {
      addLog('info', `Playing voice preview for Speaker ${speakerId}...`);
      setIsAudioPlayingState(true);
      setPlayingPreviewId(speakerId);

      const res = await fetch(url);
      const arrayBuffer = await res.arrayBuffer();

      audioCtxRef.current.decodeAudioData(arrayBuffer, (decodedBuffer) => {
        const source = audioCtxRef.current.createBufferSource();
        source.buffer = decodedBuffer;
        source.connect(gainNodeRef.current);
        source.start(0);

        previewSourceRef.current = source;
        setAgentState({
          status: 'speaking',
          title: 'PLAYING REFERENCE',
          sub: `Listening to cloned voice reference profile...`
        });

        source.onended = () => {
          stopPreviewPlayback();
        };
      }, (err) => {
        addLog('error', 'Failed to decode reference audio file buffer.');
        stopPreviewPlayback();
      });
    } catch (e) {
      addLog('error', 'Error playing reference voice.');
      stopPreviewPlayback();
    }
  };

  const stopPreviewPlayback = () => {
    if (previewSourceRef.current) {
      try { previewSourceRef.current.stop(); } catch(e) {}
      previewSourceRef.current = null;
    }
    setPlayingPreviewId(null);
    setIsAudioPlayingState(false);
    setAgentState({
      status: 'idle',
      title: 'AGENT READY',
      sub: 'Configure scripts and trigger generation below'
    });
  };

  // Add Dynamic Speaker Slot
  const addSpeaker = () => {
    const nextId = speakers.length > 0 ? Math.max(...speakers.map(s => s.id)) + 1 : 0;
    const speakerColors = ['cyan', 'purple', 'emerald', 'amber', 'rose', 'blue'];
    const color = speakerColors[nextId % speakerColors.length];
    const roles = ['Podcast Guest', 'Narrator', 'Secondary Host', 'Panelist', 'Expert Analyst'];
    const role = roles[(nextId - 2) % roles.length] || 'Guest Slot';
    
    const newSpk = {
      id: nextId,
      name: `Speaker ${nextId}`,
      isRecording: false,
      voicePath: null,
      previewUrl: null,
      role: role,
      color: color
    };

    setSpeakers(prev => [...prev, newSpk]);
    addLog('system', `Added dynamic speaker slot: [Speaker ${nextId}]`);
  };

  // Remove Dynamic Speaker Slot
  const removeSpeaker = (speakerId) => {
    if (speakerId === 0) {
      addLog('error', 'Cannot delete Speaker 0 (Primary Speaker is required).');
      return;
    }
    
    handleStopPlayback();
    setSpeakers(prev => prev.filter(s => s.id !== speakerId));
    addLog('system', `Removed speaker slot: [Speaker ${speakerId}]`);
  };

  const uploadVoiceProfile = async (fileBlob, speakerId, speakerName) => {
    try {
      addLog('info', `Uploading permanent voice profile "${speakerName}" to Supabase...`);
      
      const fileName = `voice_${Date.now()}_${speakerId}.wav`;
      
      // 1. Upload to Supabase Storage
      const { data: storageData, error: storageError } = await supabase
        .storage
        .from('voice_samples')
        .upload(fileName, fileBlob);

      if (storageError) throw storageError;

      // Get public URL
      const { data: publicUrlData } = supabase
        .storage
        .from('voice_samples')
        .getPublicUrl(fileName);

      const publicUrl = publicUrlData.publicUrl;

      // 2. Insert into Supabase Database
      const { data: dbData, error: dbError } = await supabase
        .from('voice_profiles')
        .insert([{ name: speakerName, audio_url: publicUrl }])
        .select();

      if (dbError) throw dbError;

      // 3. Update UI state
      setSpeakers(prev => prev.map(s => s.id === speakerId ? {
        ...s,
        voicePath: publicUrl,
        previewUrl: publicUrl
      } : s));
      
      addLog('success', `Voice signature for "${speakerName}" saved to Supabase successfully!`);
      
      // Refresh the saved voices list
      fetchSavedVoices();

    } catch(e) {
      addLog('warning', `Supabase upload failed (${e.message}). Falling back to local backend storage...`);
      try {
        const formData = new FormData();
        const fileToUpload = fileBlob instanceof File 
          ? fileBlob 
          : new File([fileBlob], `voice_${Date.now()}_${speakerId}.wav`, { type: 'audio/wav' });
          
        formData.append('file', fileToUpload);
        formData.append('speaker_name', speakerName);

        const res = await fetch('/api/upload-voice', {
          method: 'POST',
          body: formData
        });
        
        if (!res.ok) throw new Error(`Backend returned status ${res.status}`);
        const data = await res.json();
        
        if (data.status === 'success') {
          const localUrl = '/' + data.voice_path;
          
          setSpeakers(prev => prev.map(s => s.id === speakerId ? {
            ...s,
            voicePath: localUrl,
            previewUrl: localUrl
          } : s));
          
          addLog('success', `Voice signature for "${speakerName}" saved locally on server!`);
          
          // Instantly add this local voice to the savedVoices dropdown selection
          setSavedVoices(prev => {
            const exists = prev.some(v => v.audio_url === localUrl);
            if (exists) return prev;
            return [...prev, {
              id: data.filename,
              name: speakerName,
              audio_url: localUrl
            }];
          });
        } else {
          throw new Error(data.message || 'Local upload failed');
        }
      } catch (localErr) {
        addLog('error', `Voice signature local upload fallback failed: ${localErr.message}`);
      }
    }
  };

  // Toggle AI Model Mode on Backend
  const handleToggleModelMode = async () => {
    const enable = !modelStatus.useRealModel;
    setTogglingModel(true);
    addLog('info', `Requesting engine toggle: ${enable ? 'Enabling AI Model' : 'Enabling Demo Synthesizer'}`);

    try {
      const res = await fetch(`/api/toggle-model?enable=${enable}`, { method: 'POST' });
      const data = await res.json();
      
      setModelStatus(prev => ({
        ...prev,
        useRealModel: data.use_real_model,
        loading: enable, // starts load
        loaded: false
      }));

      setTimeout(checkServerStatus, 1500);
    } catch (e) {
      addLog('error', 'Toggle engine request failed.');
    } finally {
      setTogglingModel(false);
    }
  };

  // Presets loaders
  const loadPreset = (type) => {
    if (type === 'podcast') {
      setScript(`Speaker 0: Welcome back to the Vibe Voice podcast segment. Today we are cloning human expressions.
Speaker 1: That is right! The 0.5B model manages this dialogue transition on a local CPU extremely fast.
Speaker 0: Incredible! It sounds like two real people sitting in this glassmorphic studio together.`);
      addLog('info', 'Loaded template: [Podcast Dialogue Interview]');
    } else if (type === 'assistant') {
      setScript("Speaker 0: Hello, I am your personalized voice assistant. How can I help you customize your Dine Direct orders today?");
      addLog('info', 'Loaded template: [DineDirect AI Support Agent]');
    } else if (type === 'news') {
      setScript("Speaker 1: Breaking news from Microsoft Research. The Vibe Voice speech synthesis models are now live on local devices.");
      addLog('info', 'Loaded template: [News Bulletins Broadcast]');
    }
  };

  if (currentView === 'landing') {
    return <LandingPage onTryDemo={() => setCurrentView('studio')} />;
  }

  return (
    <div className="relative min-h-screen bg-[#07090e] text-[#f0f3fa] font-sans selection:bg-[#00f2fe]/20 select-none pb-12 overflow-x-hidden">
      {/* Background Floating Ambient Blobs */}
      <div className="fixed inset-0 overflow-hidden pointer-events-none z-0">
        <div className="absolute w-[600px] h-[600px] rounded-full top-[-200px] left-[-150px] bg-gradient-to-br from-[#00f2fe]/15 to-transparent blur-[120px] animate-float-glow-1"></div>
        <div className="absolute w-[700px] h-[700px] rounded-full bottom-[-250px] right-[-150px] bg-gradient-to-br from-[#a259ff]/15 to-transparent blur-[120px] animate-float-glow-2"></div>
      </div>

      <div className="relative z-10 max-w-[1300px] mx-auto px-4 pt-6 flex flex-col min-h-screen">
        {/* Header Widget */}
        <header className="flex flex-col md:flex-row justify-between items-center bg-glass p-4 rounded-2xl border border-white/8 backdrop-blur-xl mb-6 shadow-2xl gap-4">
          <div className="flex items-center gap-3 cursor-pointer select-none" onClick={() => setCurrentView('landing')}>
            <Sparkles className="w-8 h-8 text-neon-cyan drop-shadow-[0_0_10px_rgba(0,242,254,0.4)]" />
            <div>
              <h1 className="text-xl font-bold tracking-tight">
                VibeVoice<span className="bg-gradient-to-r from-[#00f2fe] to-[#a259ff] bg-clip-text text-transparent">Studio</span>
              </h1>
              <p className="text-[10px] text-[#8e9bb5] uppercase tracking-wider">Microsoft Frontier Speech Synthesis</p>
            </div>
          </div>

          <div className="flex items-center gap-4">
            {/* Engine Status Panel */}
            <div className="flex items-center gap-3 bg-[#00f2fe]/5 px-4 py-2 rounded-xl border border-[#00f2fe]/20 shadow-[0_0_12px_rgba(0,242,254,0.06)]">
              <span className={`w-2 h-2 rounded-full ${
                modelStatus.loading 
                  ? 'bg-[#ffb703] shadow-[0_0_8px_#ffb703] animate-pulse'
                  : modelStatus.loaded
                    ? 'bg-[#00e673] shadow-[0_0_8px_#00e673]'
                    : 'bg-[#ff5c8d] shadow-[0_0_8px_#ff5c8d]'
              }`}></span>
              
              <span className="text-xs text-[#8e9bb5]">
                VibeVoice Engine: <strong className="text-[#f0f3fa]">
                  {modelStatus.loading 
                    ? 'Loading AI...' 
                    : 'VibeVoice-1.5 AI'}
                </strong>
              </span>
            </div>

            {/* Connection badge */}
            <div className={`flex items-center gap-2 text-xs font-semibold px-4 py-2 rounded-xl border ${
              wsConnected 
                ? 'text-[#00f2fe] bg-[#00f2fe]/6 border-[#00f2fe]/20 shadow-[0_0_8px_rgba(0,242,254,0.1)]' 
                : 'text-[#8e9bb5] bg-white/4 border-white/5'
            }`}>
              <Radio className={`w-4 h-4 ${wsConnected ? 'animate-pulse' : ''}`} />
              <span>{wsConnected ? 'Connected' : 'Offline'}</span>
            </div>

            <button
              onClick={() => setCurrentView('landing')}
              className="flex items-center gap-1.5 px-4 py-2 text-xs font-bold bg-white/4 border border-white/5 hover:border-white/12 rounded-xl hover:bg-white/8 transition duration-200 cursor-pointer active:scale-95 text-white"
            >
              Back to Home
            </button>
          </div>
        </header>

        {/* Dashboard Grid Grid */}
        <main className="grid grid-cols-1 lg:grid-cols-[360px_1fr] gap-6 flex-1">
          {/* Left Column: Voice Cloning Controls */}
          <section className="bg-glass p-6 rounded-3xl flex flex-col gap-5">
            <div>
              <div className="flex items-center gap-2 mb-1">
                <Settings className="w-5 h-5 text-neon-cyan" />
                <h2 className="text-lg font-semibold">Voice Cloning Center</h2>
              </div>
              <p className="text-xs text-[#8e9bb5] leading-relaxed">Clone any voice in seconds. Record or upload a 10-30s audio sample to create a speaker profile prompt.</p>
            </div>

            {/* Speaker Slots */}
            {speakers.map((spk, idx) => {
              const colorClasses = spk.id === 0 
                ? 'bg-[#00f2fe]/6 border-[#00f2fe]/20 text-[#00f2fe]' 
                : spk.id === 1 
                  ? 'bg-[#a259ff]/6 border-[#a259ff]/20 text-[#a259ff]'
                  : spk.color === 'emerald' ? 'bg-[#00e673]/6 border-[#00e673]/20 text-[#00e673]'
                  : spk.color === 'amber' ? 'bg-[#ffb703]/6 border-[#ffb703]/20 text-[#ffb703]'
                  : spk.color === 'rose' ? 'bg-[#ff5c8d]/6 border-[#ff5c8d]/20 text-[#ff5c8d]'
                  : 'bg-[#00f2fe]/6 border-[#00f2fe]/20 text-[#00f2fe]';

              return (
                <div key={spk.id} className="bg-glass-card p-4 rounded-2xl flex flex-col gap-3 transition duration-300 relative group">
                  <div className="flex justify-between items-center">
                    <div className="flex items-center gap-2">
                      <span className="text-xs font-bold uppercase tracking-wider text-[#8e9bb5]">Speaker {spk.id}</span>
                      {spk.id > 0 && (
                        <button
                          onClick={() => removeSpeaker(spk.id)}
                          className="opacity-0 group-hover:opacity-100 text-[#ff5c8d]/60 hover:text-[#ff5c8d] p-0.5 transition duration-200 cursor-pointer"
                          title="Delete speaker slot"
                        >
                          <Trash2 className="w-3.5 h-3.5" />
                        </button>
                      )}
                    </div>
                    <span className={`text-[10px] px-2 py-0.5 rounded-full uppercase font-bold border ${colorClasses}`}>{spk.role}</span>
                  </div>

                  <div className="flex flex-col gap-1">
                    <label className="text-[10px] text-[#8e9bb5] uppercase tracking-wide">Speaker Name</label>
                    <input
                      type="text"
                      value={spk.name}
                      onChange={(e) => {
                        const val = e.target.value;
                        setSpeakers(prev => prev.map(s => s.id === spk.id ? { ...s, name: val } : s));
                      }}
                      className="bg-black/20 border border-white/6 rounded-lg px-3 py-1.5 text-xs text-[#f0f3fa] focus:border-[#00f2fe] focus:shadow-[0_0_8px_rgba(0,242,254,0.15)] outline-none"
                    />
                  </div>

                  <div className="flex flex-col gap-1">
                    <label className="text-[10px] text-[#8e9bb5] uppercase tracking-wide">Or Select Saved Voice</label>
                    <div className="flex gap-2">
                      <select
                        value={spk.voicePath ? savedVoices.find(v => v.audio_url === spk.voicePath)?.id || '' : ''}
                        onChange={(e) => {
                          const val = e.target.value;
                          const selectedVoice = savedVoices.find(v => String(v.id) === String(val));
                          if (selectedVoice) {
                            setSpeakers(prev => prev.map(s => s.id === spk.id ? { 
                              ...s, 
                              name: selectedVoice.name, 
                              voicePath: selectedVoice.audio_url,
                              previewUrl: selectedVoice.audio_url
                            } : s));
                            addLog('info', `Selected saved voice "${selectedVoice.name}" from Supabase.`);
                          } else {
                            // Clear selection
                            setSpeakers(prev => prev.map(s => s.id === spk.id ? { 
                              ...s, 
                              voicePath: null,
                              previewUrl: null
                            } : s));
                          }
                        }}
                        className="flex-1 bg-black/20 border border-white/6 rounded-lg px-3 py-1.5 text-xs text-[#f0f3fa] focus:border-[#00f2fe] focus:shadow-[0_0_8px_rgba(0,242,254,0.15)] outline-none"
                      >
                        <option value="">-- Choose a Voice --</option>
                        {savedVoices.map(v => (
                          <option key={v.id} value={v.id}>{v.name}</option>
                        ))}
                      </select>
                      
                      {spk.voicePath && (() => {
                        const matchedVoice = savedVoices.find(v => v.audio_url === spk.voicePath);
                        if (matchedVoice) {
                          return (
                            <div className="flex items-center gap-1 shrink-0">
                              <button
                                onClick={() => openRenameVoiceModal(matchedVoice.id, matchedVoice.name, matchedVoice.audio_url)}
                                className="p-1.5 rounded-lg border border-white/6 hover:border-[#00f2fe]/40 text-[#8e9bb5] hover:text-[#00f2fe] bg-white/2 hover:bg-white/5 active:scale-95 transition cursor-pointer"
                                title="Rename selected voice signature"
                              >
                                <Edit2 className="w-3.5 h-3.5" />
                              </button>
                              <button
                                onClick={() => openDeleteVoiceModal(matchedVoice.id, matchedVoice.name, matchedVoice.audio_url)}
                                className="p-1.5 rounded-lg border border-white/6 hover:border-[#ff5c8d]/40 text-[#8e9bb5] hover:text-[#ff5c8d] bg-white/2 hover:bg-[#ff5c8d]/10 active:scale-95 transition cursor-pointer"
                                title="Delete selected voice signature"
                              >
                                <Trash2 className="w-3.5 h-3.5" />
                              </button>
                            </div>
                          );
                        }
                        return null;
                      })()}
                    </div>
                  </div>

                  <div className="grid grid-cols-2 gap-2">
                    <button
                      onClick={() => toggleRecording(spk.id)}
                      className={`flex items-center justify-center gap-1.5 py-1.5 px-3 rounded-lg border text-xs cursor-pointer active:scale-95 transition duration-200 ${
                        spk.isRecording
                          ? 'bg-[#ff5c8d]/20 border-[#ff5c8d] text-[#ff5c8d] animate-pulse'
                          : 'bg-transparent border-white/10 hover:border-[#00f2fe] hover:text-[#00f2fe] text-white'
                      }`}
                    >
                      {spk.isRecording ? <Square className="w-3.5 h-3.5" /> : <Mic className="w-3.5 h-3.5" />}
                      {spk.isRecording ? 'Stop Mic' : 'Record Mic'}
                    </button>

                    <label className="flex items-center justify-center gap-1.5 py-1.5 px-3 rounded-lg border border-white/10 hover:border-[#00f2fe] hover:text-[#00f2fe] text-white text-xs cursor-pointer active:scale-95 transition duration-200">
                      <Upload className="w-3.5 h-3.5" />
                      Upload WAV
                      <input
                        type="file"
                        accept="audio/wav,audio/mp3"
                        onChange={(e) => handleFileUpload(e, spk.id)}
                        className="hidden"
                      />
                    </label>
                  </div>

                  {spk.previewUrl && (
                    <div className="flex flex-col gap-1.5 pt-2 border-t border-dashed border-white/5">
                      <span className="text-[10px] text-[#00e673] font-semibold flex items-center gap-1">
                        <CheckCircle className="w-3 h-3" /> Voice Cloned Successfully
                      </span>
                      
                      {/* Premium Custom Reference Audio Player */}
                      <div className="flex items-center gap-3 bg-white/4 p-2 rounded-xl border border-white/5 mt-1">
                        <button
                          onClick={() => playPreview(spk.id, spk.previewUrl)}
                          className="w-8 h-8 rounded-full bg-[#00f2fe]/20 border border-[#00f2fe]/30 flex items-center justify-center text-[#00f2fe] hover:bg-[#00f2fe] hover:text-black transition duration-200 active:scale-90 cursor-pointer"
                        >
                          {playingPreviewId === spk.id ? (
                            <Square className="w-3.5 h-3.5 fill-current" />
                          ) : (
                            <Play className="w-3.5 h-3.5 fill-current ml-0.5" />
                          )}
                        </button>
                        <div className="flex-1">
                          <span className="text-[10px] text-white font-semibold flex items-center gap-1 select-text">
                            <Music className="w-3 h-3 text-[#00f2fe]" /> reference_{spk.name}.wav
                          </span>
                          <span className="text-[9px] text-[#8e9bb5]">Ready for zero-shot synthesis</span>
                        </div>
                      </div>
                    </div>
                  )}
                </div>
              );
            })}

            {/* Add Speaker Slot Trigger */}
            <button
              onClick={addSpeaker}
              className="flex items-center justify-center gap-2 w-full py-3 px-4 bg-white/4 hover:bg-[#00f2fe]/10 border border-white/5 hover:border-[#00f2fe]/30 text-[#8e9bb5] hover:text-[#00f2fe] text-xs font-bold rounded-xl transition duration-200 cursor-pointer active:scale-95"
            >
              <Plus className="w-4 h-4" />
              Add Speaker Slot
            </button>

            {/* Presets */}
            <div className="mt-2 pt-4 border-t border-white/5 flex flex-col gap-2.5">
              <h3 className="text-xs font-semibold text-[#8e9bb5]">Dialogue Templates</h3>
              <div className="flex flex-col gap-2">
                <button
                  onClick={() => loadPreset('podcast')}
                  className="flex items-center gap-2.5 w-full py-2.5 px-3 bg-white/2 hover:bg-white/5 border border-white/5 hover:border-white/10 text-[#8e9bb5] hover:text-[#f0f3fa] text-xs font-medium rounded-xl transition duration-200 justify-start cursor-pointer"
                >
                  <Podcast className="w-4 h-4 text-[#a259ff]" />
                  Podcast Interview Preset
                </button>
                <button
                  onClick={() => loadPreset('assistant')}
                  className="flex items-center gap-2.5 w-full py-2.5 px-3 bg-white/2 hover:bg-white/5 border border-white/5 hover:border-white/10 text-[#8e9bb5] hover:text-[#f0f3fa] text-xs font-medium rounded-xl transition duration-200 justify-start cursor-pointer"
                >
                  <Headset className="w-4 h-4 text-[#00f2fe]" />
                  DineDirect Voice Agent
                </button>
                <button
                  onClick={() => loadPreset('news')}
                  className="flex items-center gap-2.5 w-full py-2.5 px-3 bg-white/2 hover:bg-white/5 border border-white/5 hover:border-white/10 text-[#8e9bb5] hover:text-[#f0f3fa] text-xs font-medium rounded-xl transition duration-200 justify-start cursor-pointer"
                >
                  <Newspaper className="w-4 h-4 text-[#ff5c8d]" />
                  News Broadcast Preset
                </button>
              </div>
            </div>

            {/* 🎙️ Voice Vault (Saved Neural Profiles) */}
            <div className="mt-4 pt-4 border-t border-white/5 flex flex-col gap-2.5">
              <div className="flex items-center justify-between">
                <h3 className="text-xs font-bold text-[#8e9bb5] uppercase tracking-wider">Voice Vault ({savedVoices.length})</h3>
                <span className="text-[10px] text-[#00f2fe] bg-[#00f2fe]/10 px-2 py-0.5 rounded-full font-semibold border border-[#00f2fe]/20">Storage</span>
              </div>
              
              <div className="flex flex-col gap-2 max-h-[220px] overflow-y-auto pr-1">
                {savedVoices.length === 0 ? (
                  <p className="text-[11px] text-[#8e9bb5] italic py-2 text-center">No voice profiles saved yet.</p>
                ) : (
                  savedVoices.map(v => (
                    <div key={v.id} className="flex items-center justify-between bg-white/2 hover:bg-white/4 border border-white/5 hover:border-white/10 p-2 rounded-xl transition duration-150 group/vault">
                      <div className="flex items-center gap-2 min-w-0">
                        <button
                          onClick={() => playPreview(v.id, v.audio_url)}
                          className="w-6 h-6 rounded-full bg-white/5 hover:bg-[#00f2fe]/20 hover:text-[#00f2fe] flex items-center justify-center text-[#8e9bb5] transition active:scale-90 cursor-pointer shrink-0"
                          title="Preview Voice"
                        >
                          {playingPreviewId === v.id ? (
                            <Square className="w-2.5 h-2.5 fill-current animate-pulse text-[#00f2fe]" />
                          ) : (
                            <Play className="w-2.5 h-2.5 fill-current ml-0.5" />
                          )}
                        </button>
                        <span className="text-xs font-semibold text-white truncate max-w-[120px]" title={v.name}>
                          {v.name}
                        </span>
                      </div>
                      
                      <div className="flex items-center gap-1 shrink-0">
                        <button
                          onClick={() => openRenameVoiceModal(v.id, v.name, v.audio_url)}
                          className="p-1 rounded hover:bg-white/5 text-[#8e9bb5] hover:text-[#00f2fe] transition active:scale-95 cursor-pointer"
                          title="Rename voice profile"
                        >
                          <Edit2 className="w-3.5 h-3.5" />
                        </button>
                        <button
                          onClick={() => openDeleteVoiceModal(v.id, v.name, v.audio_url)}
                          className="p-1 rounded hover:bg-[#ff5c8d]/5 text-[#8e9bb5] hover:text-[#ff5c8d] transition active:scale-95 cursor-pointer"
                          title="Delete voice profile"
                        >
                          <Trash2 className="w-3.5 h-3.5" />
                        </button>
                      </div>
                    </div>
                  ))
                )}
              </div>
            </div>
          </section>

          {/* Right Column: Execution Panels */}
          <section className="flex flex-col gap-6">
            
            {/* Visualizer Container */}
            <div className="bg-glass p-6 rounded-3xl flex flex-col justify-center items-center gap-4 min-h-[250px] bg-gradient-to-b from-[#101830]/30 to-transparent">
              <div className="flex flex-col md:flex-row items-center gap-8 w-full max-w-[500px] justify-center">
                {/* Visual pulsating holographic Orb */}
                <div className="relative w-[90px] h-[90px] flex items-center justify-center">
                  <div className={`w-[60px] h-[60px] rounded-full z-10 transition-all duration-500 ${
                    agentState.status === 'idle' && 'orb-state-idle'
                  } ${
                    agentState.status === 'thinking' && 'orb-state-thinking'
                  } ${
                    agentState.status === 'speaking' && 'orb-state-speaking'
                  } ${
                    agentState.status === 'listening' && 'orb-state-listening'
                  }`}></div>
                  
                  {/* Glowing backing shadows */}
                  <div className={`absolute -inset-[15px] rounded-full blur-[25px] opacity-50 z-0 transition-all duration-500 ${
                    agentState.status === 'idle' && 'bg-[#00f2fe]'
                  } ${
                    agentState.status === 'thinking' && 'bg-[#a259ff] scale-110 animate-pulse'
                  } ${
                    agentState.status === 'speaking' && 'bg-[#ff5c8d]'
                  } ${
                    agentState.status === 'listening' && 'bg-[#00e673]'
                  }`}></div>

                  {/* Expansion speech rings */}
                  {agentState.status === 'speaking' && (
                    <>
                      <div className="absolute inset-0 rounded-full border-2 border-[#ff5c8d] shadow-[0_0_10px_rgba(255,92,141,0.35)] animate-[waveExpand_1.2s_infinite_cubic-bezier(0.1,0.8,0.3,1)] opacity-100 z-10"></div>
                      <div className="absolute inset-0 rounded-full border-2 border-[#ff5c8d] shadow-[0_0_10px_rgba(255,92,141,0.35)] animate-[waveExpand_1.2s_infinite_cubic-bezier(0.1,0.8,0.3,1)] opacity-100 z-10 [animation-delay:0.6s]"></div>
                    </>
                  )}
                </div>

                <div className="flex flex-col text-center md:text-left gap-1">
                  <span className="font-orbitron font-extrabold text-lg tracking-wider text-shadow-md text-[#f0f3fa] uppercase">
                    {agentState.title}
                  </span>
                  <p className="text-xs text-[#8e9bb5]">{agentState.sub}</p>
                </div>
              </div>

              {/* Waveform Canvas */}
              <div className="w-full flex justify-center border-t border-white/5 pt-4 mt-2">
                <canvas ref={canvasRef} width="600" height="90" className="w-full max-w-[600px] h-[75px] rounded-xl"></canvas>
              </div>
            </div>

            {/* Script Studio Box */}
            <div className="bg-glass p-6 rounded-3xl flex flex-col gap-4">
              <div className="flex justify-between items-center border-b border-white/5 pb-4">
                <div className="flex items-center gap-2">
                  <Sparkles className="w-5 h-5 text-[#a259ff]" />
                  <h2 className="text-md font-semibold">Podcast Script Studio</h2>
                </div>

                {/* Real-time Streaming Check */}
                <label className="flex items-center gap-2.5 cursor-pointer">
                  <input
                    type="checkbox"
                    checked={streamMode}
                    onChange={(e) => setStreamMode(e.target.checked)}
                    className="hidden"
                  />
                  <div className={`w-[42px] h-[22px] rounded-full relative border transition duration-300 ${
                    streamMode ? 'bg-[#00f2fe]/20 border-[#00f2fe]' : 'bg-white/8 border-white/10'
                  }`}>
                    <div className={`w-4 h-4 rounded-full absolute top-[2px] left-[2px] transition-transform duration-300 ${
                      streamMode ? 'transform translate-x-[20px] bg-[#00f2fe] shadow-[0_0_6px_#00f2fe]' : 'bg-[#f0f3fa]'
                    }`}></div>
                  </div>
                  <span className={`text-xs font-semibold ${streamMode ? 'text-[#00f2fe]' : 'text-[#8e9bb5]'}`}>
                    Real-time Streaming
                  </span>
                </label>
              </div>

              {/* Textarea script fields */}
              <div className="bg-black/25 border border-white/8 rounded-xl overflow-hidden">
                <textarea
                  value={script}
                  onChange={(e) => setScript(e.target.value)}
                  placeholder="Format: Speaker ID: Speech dialog content..."
                  className="w-full h-[180px] bg-transparent resize-none p-4 text-[#f0f3fa] font-mono text-sm leading-relaxed outline-none border-none"
                />
              </div>

              {/* Action Buttons */}
              <div className="flex gap-4">
                <button
                  onClick={handleSynthesize}
                  disabled={isAudioPlayingState}
                  className="flex-1 flex items-center justify-center gap-2 py-3 px-6 bg-gradient-to-r from-[#00f2fe] to-[#a259ff] hover:shadow-[0_0_20px_rgba(0,242,254,0.4)] text-black font-bold rounded-xl transition duration-200 active:scale-98 cursor-pointer disabled:opacity-40"
                >
                  <PlayCircle className="w-5 h-5" />
                  Synthesize Dialogue
                </button>
                <button
                  onClick={handleStopPlayback}
                  disabled={!isAudioPlayingState}
                  className="flex-1 flex items-center justify-center gap-2 py-3 px-6 bg-white/5 border border-white/8 hover:bg-white/10 text-white font-medium rounded-xl transition duration-200 active:scale-98 cursor-pointer disabled:opacity-40"
                >
                  <Square className="w-4 h-4" />
                  Stop Playback
                </button>
              </div>
            </div>

            {/* Master Export Hub */}
            {compiledAudioUrl && (
              <div className="bg-glass p-6 rounded-3xl border border-[#00f2fe]/20 bg-gradient-to-r from-[#00f2fe]/4 to-[#a259ff]/4 shadow-[0_0_20px_rgba(0,242,254,0.08)] flex flex-col gap-4 transition duration-300">
                <div className="flex justify-between items-center border-b border-white/5 pb-3">
                  <div className="flex items-center gap-2">
                    <Sparkles className="w-5 h-5 text-neon-cyan animate-pulse" />
                    <div>
                      <h3 className="text-sm font-bold text-white uppercase tracking-wider">Podcast Master Output</h3>
                      <p className="text-[9px] text-[#8e9bb5] uppercase tracking-wide">Ready for download & broadcast</p>
                    </div>
                  </div>
                  <span className="text-[10px] px-2.5 py-0.5 rounded-full bg-[#00e673]/10 border border-[#00e673]/20 text-[#00e673] font-bold">
                    {compiledAudioMode === 'stream' ? 'Stream Mastered' : 'Engine Compiled'}
                  </span>
                </div>

                <div className="flex flex-col sm:flex-row items-center gap-4 justify-between bg-black/20 p-4 rounded-2xl border border-white/5 w-full">
                  <div className="flex items-center gap-3">
                    <div className="w-10 h-10 rounded-full bg-gradient-to-r from-[#00f2fe] to-[#a259ff] flex items-center justify-center text-black font-bold">
                      <Volume2 className="w-5 h-5" />
                    </div>
                    <div className="text-left">
                      <h4 className="text-xs font-semibold text-white">VibeVoice_Podcast_Session.wav</h4>
                      <p className="text-[10px] text-[#8e9bb5]">
                        {compiledAudioMode === 'stream' ? 'Real-time WebSocket Stream' : 'REST Compiled Dialogue Track'}
                      </p>
                    </div>
                  </div>

                  <a
                    href={compiledAudioUrl}
                    download="VibeVoice_Podcast_Session.wav"
                    className="w-full sm:w-auto flex items-center justify-center gap-2 py-2.5 px-5 bg-gradient-to-r from-[#00f2fe] to-[#a259ff] hover:shadow-[0_0_15px_rgba(0,242,254,0.3)] text-black font-bold rounded-xl text-xs transition duration-200 cursor-pointer active:scale-95"
                  >
                    <Upload className="w-4 h-4 rotate-180" />
                    Export WAV File
                  </a>
                </div>
              </div>
            )}

            {/* Custom timeline bar player */}
            {showToolbar && (
              <div className="bg-glass p-4 rounded-3xl border border-[#00f2fe]/20 shadow-[0_0_20px_rgba(0,242,254,0.05)]">
                <div className="flex flex-col md:flex-row items-center gap-4 w-full">
                  <button onClick={handleStopPlayback} className="w-9 h-9 rounded-full bg-white/5 border border-white/10 flex items-center justify-center text-white hover:bg-[#00f2fe] hover:text-black hover:shadow-[0_0_10px_rgba(0,242,254,0.35)] transition cursor-pointer">
                    <Square className="w-4 h-4" />
                  </button>

                  <div className="flex items-center gap-3 flex-1 w-full">
                    <span className="font-mono text-[10px] text-[#8e9bb5]">{formatTime(timeline.elapsed)}</span>
                    <div className="relative flex-1 h-1.5 bg-white/8 rounded-full overflow-hidden">
                      <div className="absolute left-0 top-0 bottom-0 bg-gradient-to-r from-[#00f2fe] to-[#a259ff] rounded-full" style={{ width: `${(timeline.elapsed / timeline.total) * 100}%` }}></div>
                    </div>
                    <span className="font-mono text-[10px] text-[#8e9bb5]">{formatTime(timeline.total)}</span>
                  </div>

                  <div className="flex items-center gap-3 w-[150px]">
                    {volume === 0 ? <VolumeX className="w-4 h-4 text-[#8e9bb5]" /> : volume < 50 ? <Volume1 className="w-4 h-4 text-[#8e9bb5]" /> : <Volume2 className="w-4 h-4 text-[#8e9bb5]" />}
                    <input
                      type="range"
                      min="0"
                      max="100"
                      value={volume}
                      onChange={(e) => setVolume(parseInt(e.target.value))}
                      className="w-full accent-[#00f2fe] h-1 bg-white/10 rounded-lg outline-none cursor-pointer"
                    />
                  </div>

                  <select
                    value={speed}
                    onChange={(e) => setSpeed(e.target.value)}
                    className="bg-white/5 border border-white/8 rounded-lg px-2 py-1 text-xs text-white outline-none cursor-pointer"
                  >
                    <option value="0.75" className="bg-[#07090e]">0.75x</option>
                    <option value="1.0" className="bg-[#07090e]">1.0x</option>
                    <option value="1.25" className="bg-[#07090e]">1.25x</option>
                    <option value="1.5" className="bg-[#07090e]">1.5x</option>
                  </select>
                </div>
              </div>
            )}

            {/* Podcast History & Archive section */}
            <div className="bg-glass p-6 rounded-3xl border border-white/4 bg-black/40 flex flex-col gap-4">
              <div className="flex justify-between items-center border-b border-white/5 pb-2 text-xs font-semibold text-[#8e9bb5]">
                <div className="flex items-center gap-2">
                  <Podcast className="w-4 h-4 text-[#a259ff] animate-pulse" />
                  <span className="text-white font-bold uppercase tracking-wider text-[10px]">Supabase Broadcast Archive</span>
                </div>
                <span className="text-[10px] bg-[#a259ff]/10 px-2 py-0.5 rounded-full text-neon-purple font-mono border border-[#a259ff]/20">
                  {podcastHistory.length} Saved
                </span>
              </div>

              <div className="max-h-[220px] overflow-y-auto pr-1 flex flex-col gap-2.5 custom-scrollbar">
                {podcastHistory.length === 0 ? (
                  <div className="py-8 text-center flex flex-col items-center justify-center gap-2 border border-dashed border-white/5 rounded-2xl bg-white/2">
                    <Music className="w-8 h-8 text-[#8e9bb5]/40" />
                    <div>
                      <p className="text-xs text-white font-medium">No podcasts archived yet</p>
                      <p className="text-[10px] text-[#8e9bb5] mt-0.5 max-w-[200px]">Generate speech scripts to automatically archive them permanently!</p>
                    </div>
                  </div>
                ) : (
                  podcastHistory.map((podcast) => (
                    <div 
                      key={podcast.id} 
                      className="p-3 bg-white/3 border border-white/5 rounded-xl hover:border-white/10 hover:bg-white/5 transition duration-200 flex items-center justify-between gap-3 group/item relative overflow-hidden"
                    >
                      {isAudioPlayingState && compiledAudioUrl === podcast.audio_url && (
                        <div className="absolute inset-0 bg-gradient-to-r from-[#a259ff]/10 to-transparent pointer-events-none" />
                      )}

                      <div className="flex items-center gap-3 min-w-0">
                        <button 
                          onClick={() => playHistoryPodcast(podcast)}
                          className={`w-8 h-8 rounded-full flex items-center justify-center transition active:scale-95 cursor-pointer shrink-0 ${
                            isAudioPlayingState && compiledAudioUrl === podcast.audio_url
                              ? 'bg-[#ff5c8d] text-white animate-pulse'
                              : 'bg-white/5 hover:bg-white/10 text-white'
                          }`}
                        >
                          {isAudioPlayingState && compiledAudioUrl === podcast.audio_url ? (
                            <Square className="w-3.5 h-3.5 fill-current" />
                          ) : (
                            <Play className="w-3.5 h-3.5 fill-current ml-0.5" />
                          )}
                        </button>

                        <div className="min-w-0 flex flex-col gap-0.5">
                          <span className="text-xs font-bold text-white truncate max-w-[240px] block group-hover/item:text-[#00f2fe] transition duration-150">
                            {podcast.title}
                          </span>
                          <span className="text-[10px] text-[#8e9bb5] truncate block max-w-[240px] leading-relaxed cursor-help" title={podcast.text_script}>
                            Script: "{podcast.text_script}"
                          </span>
                        </div>
                      </div>

                      <div className="flex items-center gap-2 shrink-0">
                        <a 
                          href={podcast.audio_url}
                          download
                          target="_blank"
                          rel="noopener noreferrer"
                          className="p-1.5 rounded-lg border border-white/6 hover:border-[#00f2fe]/40 text-[#8e9bb5] hover:text-white hover:bg-white/4 active:scale-95 transition"
                          title="Open audio in new tab / download"
                        >
                          <Upload className="w-3.5 h-3.5 rotate-180" />
                        </a>
                        <button
                          onClick={() => openRenamePodcastModal(podcast.id, podcast.title)}
                          className="p-1.5 rounded-lg border border-white/6 hover:border-[#00f2fe]/40 text-[#8e9bb5] hover:text-white hover:bg-white/4 active:scale-95 transition cursor-pointer"
                          title="Rename podcast title"
                        >
                          <Edit2 className="w-3.5 h-3.5" />
                        </button>
                        <button
                          onClick={() => openDeletePodcastModal(podcast.id, podcast.title, podcast.audio_url)}
                          className="p-1.5 rounded-lg border border-white/6 hover:border-[#ff5c8d]/40 text-[#8e9bb5] hover:text-[#ff5c8d] hover:bg-[#ff5c8d]/5 active:scale-95 transition cursor-pointer"
                          title="Delete podcast from Supabase archive"
                        >
                          <Trash2 className="w-3.5 h-3.5" />
                        </button>
                      </div>
                    </div>
                  ))
                )}
              </div>
            </div>

            {/* Diagnostic Terminal card */}
            <div className="bg-glass p-6 rounded-3xl border border-white/4 bg-black/40">
              <div className="flex justify-between items-center border-b border-white/5 pb-2 mb-3 text-xs font-semibold text-[#8e9bb5]">
                <div className="flex items-center gap-2">
                  <Terminal className="w-4 h-4 text-[#00f2fe]" />
                  <span>Agent HUD Console Logs</span>
                </div>
                <button
                  onClick={() => setLogs([{ type: 'system', text: 'Console buffer cleared.', time: new Date().toLocaleTimeString() }])}
                  className="px-2 py-0.5 rounded border border-white/10 hover:border-white/20 active:scale-95 text-[10px] text-white hover:bg-white/2 cursor-pointer transition duration-150"
                >
                  Clear Buffer
                </button>
              </div>

              <div id="consoleBody" className="h-[120px] overflow-y-auto font-mono text-[10.5px] leading-relaxed flex flex-col gap-1.5 pr-2 select-text">
                {logs.map((logItem, idx) => (
                  <div key={idx} className={`px-2 py-0.5 rounded ${
                    logItem.type === 'system' && 'text-[#8e9bb5] bg-white/2'
                  } ${
                    logItem.type === 'info' && 'text-[#00f2fe] bg-[#00f2fe]/2'
                  } ${
                    logItem.type === 'success' && 'text-[#00e673] bg-[#00e673]/2'
                  } ${
                    logItem.type === 'error' && 'text-[#ff5c8d] bg-[#ff5c8d]/2'
                  } ${
                    logItem.type === 'word' && 'text-white font-medium drop-shadow-[0_0_4px_rgba(255,255,255,0.25)]'
                  }`}>
                    [{logItem.time}] {logItem.text}
                  </div>
                ))}
              </div>
            </div>

          </section>
        </main>
      </div>

      {/* 🎙️ Premium Glassmorphic Custom Voice Profile Naming Modal */}
      {namingModal.isOpen && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-md animate-fade-in">
          <div className="w-[90%] max-w-[420px] bg-gradient-to-b from-white/10 to-white/3 border border-white/12 backdrop-blur-2xl p-6 rounded-3xl shadow-2xl flex flex-col gap-4 animate-scale-up">
            <div className="flex items-center gap-3">
              <div className="w-10 h-10 rounded-full bg-[#00f2fe]/10 flex items-center justify-center border border-[#00f2fe]/20">
                <Sparkles className="w-5 h-5 text-neon-cyan animate-pulse" />
              </div>
              <div>
                <h3 className="text-base font-bold text-white tracking-tight">Save Custom Voice Signature</h3>
                <p className="text-[10px] text-[#8e9bb5] uppercase tracking-wider">Neural Studio Archivist</p>
              </div>
            </div>
            
            <p className="text-xs text-[#8e9bb5] leading-relaxed">
              Give your new voice profile signature a descriptive name (e.g. <em>John's Deep Voice</em>, <em>Excited Host</em>) to save it permanently in your custom voice selection.
            </p>

            <div className="flex flex-col gap-1.5 mt-2">
              <label className="text-[10px] text-[#8e9bb5] uppercase tracking-wide font-semibold">Voice Signature Name</label>
              <input
                type="text"
                autoFocus
                placeholder="Enter voice signature name..."
                value={voiceNameInput}
                onChange={(e) => setVoiceNameInput(e.target.value)}
                className="bg-black/40 border border-white/10 focus:border-[#00f2fe] rounded-xl px-4 py-2.5 text-xs text-white outline-none focus:shadow-[0_0_12px_rgba(0,242,254,0.2)] transition duration-200"
                onKeyDown={(e) => {
                  if (e.key === 'Enter') {
                    const name = voiceNameInput.trim() || namingModal.defaultName;
                    uploadVoiceProfile(namingModal.fileBlob, namingModal.speakerId, name);
                    setNamingModal({ isOpen: false, fileBlob: null, speakerId: null, defaultName: '' });
                  }
                }}
              />
            </div>

            <div className="flex justify-end gap-3 mt-3">
              <button
                onClick={() => setNamingModal({ isOpen: false, fileBlob: null, speakerId: null, defaultName: '' })}
                className="px-4 py-2 rounded-xl border border-white/6 hover:bg-white/4 active:scale-95 text-xs font-semibold text-[#8e9bb5] hover:text-white cursor-pointer transition duration-150"
              >
                Cancel
              </button>
              <button
                onClick={() => {
                  const name = voiceNameInput.trim() || namingModal.defaultName;
                  uploadVoiceProfile(namingModal.fileBlob, namingModal.speakerId, name);
                  setNamingModal({ isOpen: false, fileBlob: null, speakerId: null, defaultName: '' });
                }}
                className="px-5 py-2 rounded-xl bg-gradient-to-r from-[#00f2fe] to-[#a259ff] text-xs font-bold text-black hover:shadow-[0_0_15px_rgba(0,242,254,0.3)] active:scale-95 cursor-pointer transition duration-200"
              >
                Save to Studio
              </button>
            </div>
          </div>
        </div>
      )}

      {/* 🔮 Premium custom action (Rename/Delete) modal */}
      {actionModal.isOpen && (
        <div className="fixed inset-0 z-[100] flex items-center justify-center bg-black/60 backdrop-blur-md animate-fade-in">
          <div className="w-[90%] max-w-[420px] bg-gradient-to-b from-white/10 to-white/3 border border-white/12 backdrop-blur-2xl p-6 rounded-3xl shadow-2xl flex flex-col gap-4 animate-scale-up">
            <div className="flex justify-between items-center border-b border-white/6 pb-3">
              <div className="flex items-center gap-2">
                <Sparkles className="w-5 h-5 text-neon-cyan" />
                <h3 className="text-sm font-bold text-white uppercase tracking-wider">
                  {actionModal.type.startsWith('rename') ? 'Rename Profile' : 'Confirm Action'}
                </h3>
              </div>
              <button 
                onClick={() => setActionModal({ isOpen: false, type: '', id: null, oldValue: '', inputValue: '', audioUrl: '', profileName: '' })}
                className="text-[#8e9bb5] hover:text-white transition cursor-pointer text-sm"
              >
                ✕
              </button>
            </div>

            {actionModal.type.startsWith('rename') ? (
              <div className="flex flex-col gap-3">
                <p className="text-xs text-[#8e9bb5] leading-relaxed">
                  Enter a new name for your {actionModal.type === 'rename_voice' ? 'voice profile signature' : 'podcast archive title'}:
                </p>
                <input
                  type="text"
                  autoFocus
                  value={actionModal.inputValue}
                  onChange={(e) => setActionModal(prev => ({ ...prev, inputValue: e.target.value }))}
                  className="bg-black/40 border border-white/10 focus:border-[#00f2fe] rounded-xl px-4 py-2.5 text-xs text-white outline-none focus:shadow-[0_0_12px_rgba(0,242,254,0.2)] transition duration-200"
                  onKeyDown={(e) => {
                    if (e.key === 'Enter') {
                      if (actionModal.type === 'rename_voice') {
                        executeRenameVoice(actionModal.id, actionModal.inputValue, actionModal.audioUrl);
                      } else {
                        executeRenamePodcast(actionModal.id, actionModal.inputValue);
                      }
                      setActionModal({ isOpen: false, type: '', id: null, oldValue: '', inputValue: '', audioUrl: '', profileName: '' });
                    }
                  }}
                />
                <div className="flex items-center gap-2.5 mt-2">
                  <button
                    onClick={() => setActionModal({ isOpen: false, type: '', id: null, oldValue: '', inputValue: '', audioUrl: '', profileName: '' })}
                    className="flex-1 py-2.5 text-xs font-bold bg-white/4 border border-white/5 hover:border-white/12 rounded-xl text-white transition active:scale-95 cursor-pointer"
                  >
                    Cancel
                  </button>
                  <button
                    onClick={() => {
                      if (actionModal.type === 'rename_voice') {
                        executeRenameVoice(actionModal.id, actionModal.inputValue, actionModal.audioUrl);
                      } else {
                        executeRenamePodcast(actionModal.id, actionModal.inputValue);
                      }
                      setActionModal({ isOpen: false, type: '', id: null, oldValue: '', inputValue: '', audioUrl: '', profileName: '' });
                    }}
                    className="flex-1 py-2.5 text-xs font-bold bg-gradient-to-r from-[#00f2fe] to-[#a259ff] hover:shadow-[0_0_12px_rgba(0,242,254,0.3)] text-black rounded-xl transition active:scale-95 cursor-pointer"
                  >
                    Save Changes
                  </button>
                </div>
              </div>
            ) : (
              <div className="flex flex-col gap-3">
                <p className="text-xs text-[#8e9bb5] leading-relaxed">
                  Are you sure you want to permanently delete the {actionModal.type === 'delete_voice' ? 'voice profile signature' : 'archived podcast'} <strong className="text-white">"{actionModal.profileName}"</strong>? This action cannot be undone.
                </p>
                <div className="flex items-center gap-2.5 mt-2">
                  <button
                    onClick={() => setActionModal({ isOpen: false, type: '', id: null, oldValue: '', inputValue: '', audioUrl: '', profileName: '' })}
                    className="flex-1 py-2.5 text-xs font-bold bg-white/4 border border-white/5 hover:border-white/12 rounded-xl text-white transition active:scale-95 cursor-pointer"
                  >
                    Cancel
                  </button>
                  <button
                    onClick={() => {
                      if (actionModal.type === 'delete_voice') {
                        executeDeleteVoice(actionModal.id, actionModal.audioUrl, actionModal.profileName);
                      } else {
                        executeDeletePodcast(actionModal.id, actionModal.audioUrl, actionModal.profileName);
                      }
                      setActionModal({ isOpen: false, type: '', id: null, oldValue: '', inputValue: '', audioUrl: '', profileName: '' });
                    }}
                    className="flex-1 py-2.5 text-xs font-bold bg-[#ff5c8d] hover:bg-[#ff5c8d]/90 hover:shadow-[0_0_12px_rgba(255,92,141,0.3)] text-white rounded-xl transition active:scale-95 cursor-pointer"
                  >
                    Delete Permanently
                  </button>
                </div>
              </div>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

// ==========================================================================
// WAV Exporter Helpers
// ==========================================================================
function exportWav(chunks, sampleRate) {
  let totalLength = 0;
  for (const chunk of chunks) {
    totalLength += chunk.length;
  }
  
  const result = new Float32Array(totalLength);
  let offset = 0;
  for (const chunk of chunks) {
    result.set(chunk, offset);
    offset += chunk.length;
  }
  
  const buffer = new ArrayBuffer(44 + totalLength * 2);
  const view = new DataView(buffer);
  
  // RIFF identifier
  writeString(view, 0, 'RIFF');
  // File length
  view.setUint32(4, 36 + totalLength * 2, true);
  // RIFF type
  writeString(view, 8, 'WAVE');
  // Format chunk identifier
  writeString(view, 12, 'fmt ');
  // Format chunk length
  view.setUint32(16, 16, true);
  // Sample format (raw PCM)
  view.setUint16(20, 1, true);
  // Channel count (mono)
  view.setUint16(22, 1, true);
  // Sample rate
  view.setUint32(24, sampleRate, true);
  // Byte rate (sample rate * block align)
  view.setUint32(28, sampleRate * 2, true);
  // Block align (channel count * bytes per sample)
  view.setUint16(32, 2, true);
  // Bits per sample
  view.setUint16(34, 16, true);
  // Data chunk identifier
  writeString(view, 36, 'data');
  // Data chunk length
  view.setUint32(40, totalLength * 2, true);
  
  // Write PCM audio samples
  let index = 44;
  for (let i = 0; i < totalLength; i++) {
    const s = Math.max(-1, Math.min(1, result[i]));
    view.setInt16(index, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
    index += 2;
  }
  
  return new Blob([view], { type: 'audio/wav' });
}

function writeString(view, offset, string) {
  for (let i = 0; i < string.length; i++) {
    view.setUint8(offset + i, string.charCodeAt(i));
  }
}

export default App;
