import { useState, useEffect, useRef, useCallback } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useAuth } from '@/contexts/AuthContext';
import { 
  ArrowLeft,
  Download,
  MessageCircle,
  Lightbulb,
  ClipboardList,
  BarChart,
  PlayCircle,
  StickyNote,
  Settings,
  Bot
} from 'lucide-react';
import { toastService } from '@/lib/toast';
import { Button } from '@/components/ui/button';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Badge } from '@/components/ui/badge';
import Navigation from '@/components/Navigation';
import ParticipantPanel from '@/components/focus-group-session/ParticipantPanel';
import DiscussionPanel from '@/components/focus-group-session/DiscussionPanel';
import ThemesPanel from '@/components/focus-group-session/ThemesPanel';
import AnalyticsPanel from '@/components/focus-group-session/AnalyticsPanel';
import AutonomousDashboard from '@/components/focus-group-session/AutonomousDashboard';
import CollapsibleDiscussionGuide from '@/components/focus-group-session/CollapsibleDiscussionGuide';
import NotesPanel from '@/components/focus-group-session/NotesPanel';
import QuickNoteModal from '@/components/focus-group-session/QuickNoteModal';
import { FocusGroup, Message, Theme, Note, QuoteData, ModeEvent } from '@/components/focus-group-session/types';
import { Persona } from '@/types/persona';
import api, { focusGroupsApi, personasApi, focusGroupAiApi } from '@/lib/api';
import { useCancellableGeneration } from '@/hooks/useCancellableGeneration';
import { getSocket } from '@/services/websocketServiceNew';
import ProgressModal from '@/components/ui/ProgressModal';
// GPT-5 FIX: Use new singleton WebSocket service
import { initSocket, joinFocusGroup, leaveFocusGroup } from '@/services/websocketServiceNew';
import { 
  convertWebSocketMessage, 
  convertWebSocketTheme, 
  WS_EVENTS,
  shouldUseWebSocket 
} from '@/services/websocketService';

const FocusGroupSession = () => {
  const { id } = useParams<{ id: string }>();
  const navigate = useNavigate();
  const { token } = useAuth();
  
  const [messages, setMessages] = useState<Message[]>([]);
  const [modeEvents, setModeEvents] = useState<ModeEvent[]>([]);
  const [themes, setThemes] = useState<Theme[]>([]);
  const [focusGroup, setFocusGroup] = useState<FocusGroup | null>(null);
  const [participants, setParticipants] = useState<Persona[]>([]);
  const [activeTab, setActiveTab] = useState('chat');
  const [moderatorStatus, setModeratorStatus] = useState<any>(null);
  const [showAutonomousDashboard, setShowAutonomousDashboard] = useState(false);
  const [isAiModeActive, setIsAiModeActive] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  const [isDiscussionGuideOpen, setIsDiscussionGuideOpen] = useState(false);
  const [isEditingDiscussionGuide, setIsEditingDiscussionGuide] = useState(false);
  const isEditingDiscussionGuideRef = useRef(false);
  
  // Track discussion guide editing state to prevent focus loss
  const [isEditingGuideContent, setIsEditingGuideContent] = useState(false);
  const focusGroupRef = useRef(focusGroup);
  focusGroupRef.current = focusGroup;
  
  // Notes-related state
  const [notes, setNotes] = useState<Note[]>([]);
  
  // Model settings state
  const [showModelSettings, setShowModelSettings] = useState(false);
  const [selectedModel, setSelectedModel] = useState<string>('');
  const [selectedReasoningEffort, setSelectedReasoningEffort] = useState<string>('medium');
  const [selectedVerbosity, setSelectedVerbosity] = useState<string>('medium');
  const [isUpdatingModel, setIsUpdatingModel] = useState(false);
  const [isNoteModalOpen, setIsNoteModalOpen] = useState(false);
  const [sessionStartTime, setSessionStartTime] = useState<Date | null>(null);
  
  // Participant filtering state
  const [selectedParticipantIds, setSelectedParticipantIds] = useState<string[]>([]);
  
  // Cancellable generation for key themes
  const socket = getSocket();
  const [themeGenerationState, themeGenerationControls] = useCancellableGeneration('key themes generation', socket);
  const [isThemeProgressModalOpen, setIsThemeProgressModalOpen] = useState(false);

  // WebSocket status bar visibility
  const [isStatusBarVisible, setIsStatusBarVisible] = useState(true);
  
  // AI mode generation state - removed since we show loading continuously during AI mode
  
  // Set position dialog state
  const [setPositionDialog, setSetPositionDialog] = useState<{
    isOpen: boolean;
    sectionId?: string;
    itemId?: string;
    content?: string;
    sectionTitle?: string;
    itemTitle?: string;
    itemType?: string;
    metadata?: Record<string, any>;
    isLoading?: boolean;
  }>({ isOpen: false });
  
  // Track the last known AI status from API to avoid false positive changes
  const lastAiStatusRef = useRef<boolean>(false);
  
  // Track session status for ending detection
  const [sessionStatus, setSessionStatus] = useState<string>('');
  const lastSessionStatusRef = useRef<string>('');
  const sessionEndingProcessedRef = useRef<boolean>(false);

  // WebSocket connection state tracking for notifications
  const wsConnectionStateRef = useRef<{
    wasConnected: boolean;
    wasConnecting: boolean;
    initialConnection: boolean;
    hasShownFallbackNotification: boolean;
  }>({
    wasConnected: false,
    wasConnecting: false,
    initialConnection: true,
    hasShownFallbackNotification: false
  });

  // GPT-5 FIX: WebSocket singleton service
  const useWebSocketEnabled = shouldUseWebSocket();
  
  // Simple WebSocket connection state (GPT-5 simplified approach)
  const [wsConnected, setWsConnected] = useState(false);
  const [wsConnecting, setWsConnecting] = useState(false);
  const [wsError, setWsError] = useState<string | null>(null);
  
  // Get token for WebSocket auth
  const getAccessToken = useCallback(() => {
    return token || '';
  }, [token]);

  // Initialize singleton socket (GPT-5 fix: avoid useMemo issues)
  useEffect(() => {
    if (useWebSocketEnabled) {
      console.log('🔧 [GPT-5 Session] Initializing WebSocket');
      initSocket(getAccessToken);
    }
  }, [useWebSocketEnabled, getAccessToken]);

  // GPT-5 FIX: Join room on mount and reconnect
  useEffect(() => {
    if (!useWebSocketEnabled || !id) return;

    const tryJoin = () => {
      console.log('🔧 [GPT-5 Session] Joining focus group:', id);
      joinFocusGroup(id);
    };
    
    // Join room (the singleton service handles connection state)
    tryJoin();
  }, [id, useWebSocketEnabled]);

  // GPT-5 FIX: Simple connection state management
  useEffect(() => {
    if (!useWebSocketEnabled) return;
    
    // Set initial connecting state
    setWsConnecting(true);
    setWsConnected(false);
    setWsError(null);
    
    // Simple timeout to assume connection (the singleton service handles the actual connection)
    const connectionTimeout = setTimeout(() => {
      setWsConnected(true);
      setWsConnecting(false);
    }, 1000);
    
    return () => {
      clearTimeout(connectionTimeout);
    };
  }, [useWebSocketEnabled]);

  // GPT-5 FIX: Handle WebSocket events via window events (decoupled from React lifecycle)
  useEffect(() => {
    if (!useWebSocketEnabled) return;

    console.log('🔧 [GPT-5 Session] Setting up window event listeners');

    // Handle message updates
    const onMessageUpdate = (e: CustomEvent) => {
      const data = e.detail;
      console.log('🔧 [GPT-5 Session] message_update:', data);
      
      // Debug focus group filtering
      if (data.focus_group_id) {
        console.log('🔧 [GPT-5] Message focus_group_id:', data.focus_group_id);
        console.log('🔧 [GPT-5] Current focus group from URL:', id);
      }
      
      const newMessage = convertWebSocketMessage(data.message);
      if (!newMessage) {
        console.error('🔧 [GPT-5] convertWebSocketMessage returned null');
        return;
      }
      
      setMessages(prev => {
        // Check for duplicates
        const exists = prev.find(m => m.id === newMessage.id);
        if (exists) {
          console.log('🔧 [GPT-5] Message already exists, skipping');
          return prev;
        }
        
        console.log('🔧 [GPT-5] Adding new message, count:', prev.length + 1);
        return [...prev, newMessage];
      });
    };

    // Handle AI status updates - GPT-5 fix: functional state updates  
    const onAiStatusUpdate = (e: CustomEvent) => {
      const data = e.detail;
      console.log('🔧 [GPT-5 Session] ai_status_update:', data);
      
      // GPT-5 fix: Use functional updates to prevent stale closures during AI mode  
      setIsAiModeActive(prev => data.status.status === 'ai_mode');
      setSessionStatus(prev => data.status.status);
    };

    // Handle moderator status updates
    const onModeratorStatusUpdate = (e: CustomEvent) => {
      const data = e.detail;
      console.log('🔧 [GPT-5 Session] moderator_status_update:', data);
      setModeratorStatus(data.moderator_status);
    };

    // Handle theme updates
    const onThemeUpdate = (e: CustomEvent) => {
      const data = e.detail;
      console.log('🔧 [GPT-5 Session] theme_update:', data);
      const theme = convertWebSocketTheme(data.theme);
      
      setThemes(prev => {
        const updated = [...prev];
        const existingIndex = updated.findIndex(t => t.id === theme.id);
        if (existingIndex >= 0) {
          updated[existingIndex] = theme;
        } else {
          updated.push(theme);
        }
        return updated;
      });
    };

    // Handle focus group updates
    const onFocusGroupUpdate = (e: CustomEvent) => {
      const data = e.detail;
      console.log('🔧 [GPT-5 Session] focus_group_update:', data);
      setFocusGroup(prev => prev ? { ...prev, ...data } : null);
    };

    // Handle mode event updates
    const onModeEventUpdate = (e: CustomEvent) => {
      const data = e.detail;
      console.log('🔧 [GPT-5 Session] mode_event_update:', data);
      
      // Convert timestamp to Date object
      const modeEvent = {
        ...data,
        timestamp: new Date(data.timestamp),
        created_at: new Date(data.created_at)
      };
      
      // Check for duplicates before adding
      setModeEvents(prev => {
        const existingIndex = prev.findIndex(event => event.id === modeEvent.id);
        if (existingIndex >= 0) {
          console.log('🔧 [GPT-5 Session] Mode event already exists, skipping:', modeEvent.id);
          return prev; // Don't add duplicate
        }
        console.log('🔧 [GPT-5 Session] Adding new mode event:', modeEvent.id);
        return [...prev, modeEvent];
      });
    };

    // Handle room join confirmations
    const onJoinedFocusGroup = (e: CustomEvent) => {
      const data = e.detail;
      console.log('🔧 [GPT-5 Session] joined_focus_group:', data);
    };

    // Add window event listeners
    console.log('🔧 [GPT-5 Session] ADDING window event listeners');
    window.addEventListener('ws:message_update', onMessageUpdate as any);
    window.addEventListener('ws:ai_status_update', onAiStatusUpdate as any);
    window.addEventListener('ws:moderator_status_update', onModeratorStatusUpdate as any);
    window.addEventListener('ws:theme_update', onThemeUpdate as any);
    window.addEventListener('ws:focus_group_update', onFocusGroupUpdate as any);
    window.addEventListener('ws:mode_event_update', onModeEventUpdate as any);
    window.addEventListener('ws:joined_focus_group', onJoinedFocusGroup as any);
    console.log('🔧 [GPT-5 Session] ADDED all window event listeners');

    // Cleanup window event listeners
    return () => {
      console.log('🔧 [GPT-5 Session] Cleaning up window event listeners');
      window.removeEventListener('ws:message_update', onMessageUpdate as any);
      window.removeEventListener('ws:ai_status_update', onAiStatusUpdate as any);
      window.removeEventListener('ws:moderator_status_update', onModeratorStatusUpdate as any);
      window.removeEventListener('ws:theme_update', onThemeUpdate as any);
      window.removeEventListener('ws:focus_group_update', onFocusGroupUpdate as any);
      window.removeEventListener('ws:mode_event_update', onModeEventUpdate as any);
      window.removeEventListener('ws:joined_focus_group', onJoinedFocusGroup as any);
      
      // Leave room on unmount
      if (id) leaveFocusGroup(id);
    };
  }, [useWebSocketEnabled, id]); // Simple dependencies - no complex handler deps!

  // WebSocket connection state notifications
  useEffect(() => {
    if (!useWebSocketEnabled || !id) return;

    const state = wsConnectionStateRef.current;

    // Handle successful WebSocket connection
    if (wsConnected && !state.wasConnected) {
      if (!state.initialConnection) {
        // Reconnection after disconnection
        toastService.success('Real-time updates restored', {
          description: 'WebSocket connection re-established. You\'ll now receive instant updates.',
          duration: 4000
        });
      } else {
        // Initial successful connection
        toastService.success('Live updates enabled', {
          description: 'Connected to real-time updates. Changes will appear instantly.',
          duration: 3000
        });
      }
      state.wasConnected = true;
      state.initialConnection = false;
    }

    // Handle WebSocket disconnection
    if (!wsConnected && !wsConnecting && state.wasConnected && !state.initialConnection) {
      toastService.warning('Connection lost', {
        description: 'Real-time updates unavailable. Attempting to reconnect...',
        duration: 5000
      });
      state.wasConnected = false;
      // Show status bar when connection is lost so user can see the issue
      setIsStatusBarVisible(true);
    }

    // Handle WebSocket connection errors
    if (wsError && !wsConnecting && !wsConnected && !state.initialConnection) {
      toastService.error('Connection failed', {
        description: 'Unable to establish real-time connection. Using periodic updates instead.',
        duration: 6000
      });
      // Show status bar when there's an error so user can see the issue
      setIsStatusBarVisible(true);
    }

    state.wasConnecting = wsConnecting;

  }, [wsConnected, wsConnecting, wsError, useWebSocketEnabled, id]);


  // Notification for polling fallback when WebSocket is disabled
  useEffect(() => {
    if (!useWebSocketEnabled && id && focusGroup) {
      const state = wsConnectionStateRef.current;
      
      if (!state.hasShownFallbackNotification) {
        toastService.info('Using periodic updates', {
          description: 'Real-time updates are not available. Data will refresh automatically every few seconds.',
          duration: 4000
        });
        state.hasShownFallbackNotification = true;
      }
    }
  }, [useWebSocketEnabled, id, focusGroup]);
  
  // Fetch moderator status (fallback for when WebSocket is disabled)
  const fetchModeratorStatus = async () => {
    if (!id) return;
    
    try {
      const response = await focusGroupAiApi.getModeratorStatus(id);
      if (response?.data?.status) {
        const newStatus = response.data.status;
        
        // Debug logging for moderator status changes
        if (moderatorStatus) {
          const positionChanged = 
            moderatorStatus.current_section_id !== newStatus.current_section_id ||
            moderatorStatus.current_item_id !== newStatus.current_item_id ||
            moderatorStatus.progress !== newStatus.progress;
            
          if (positionChanged) {
            // Moderator position changed - update moderator position state
          }
        } else {
          // Initial load - no logging needed for routine status updates
        }
        
        // Don't update moderator status if editing discussion guide to prevent re-renders
        if (!isEditingDiscussionGuideRef.current) {
          setModeratorStatus(newStatus);
        } else {
          // Skip moderator status update while editing discussion guide
        }
      }
    } catch (error) {
      console.error("Error fetching moderator status:", error);
      // Don't show error toast for this as it's not critical
    }
  };

  // Check if AI mode is active and get session status
  const checkAiModeStatus = async () => {
    if (!id) return { aiActive: false, sessionStatus: '' };
    
    try {
      // Ensure we have a valid API method before calling
      if (typeof focusGroupsApi?.getById !== 'function') {
        console.error('focusGroupsApi.getById is not a function:', typeof focusGroupsApi?.getById);
        return { aiActive: isAiModeActive, sessionStatus: sessionStatus };
      }
      
      const response = await focusGroupsApi.getById(id);
      
      // Validate response object exists and has expected structure
      if (!response || typeof response !== 'object') {
        console.error('Invalid response object received:', response);
        return { aiActive: isAiModeActive, sessionStatus: sessionStatus };
      }
      
      // Status check logging reduced to prevent console spam
      
      // Validate response data structure
      if (!response.data || typeof response.data !== 'object') {
        console.warn('Focus group response missing data property:', response);
        return { aiActive: isAiModeActive, sessionStatus: sessionStatus };
      }
      
      // Validate status field and check for expected values
      const status = response.data.status;
      if (typeof status === 'undefined') {
        console.warn('Focus group response missing status field:', response.data);
        return { aiActive: isAiModeActive, sessionStatus: sessionStatus };
      }
      
      // Check for the expected ai_mode status
      const isActive = status === 'ai_mode';
      
      // Removed individual generation checking since we show loading continuously during AI mode
      
      // DEBUG: Log the status check details
      // AI Mode Status Check
      
      // Warn about unexpected status values that might indicate backend issues
      if (status === 'autonomous_active') {
        console.warn('Detected legacy "autonomous_active" status - backend may need updating to "ai_mode"');
      } else if (!['ai_mode', 'active', 'completed', 'paused', 'draft', 'in-progress'].includes(status)) {
        console.warn('Unexpected focus group status value:', status);
      }
      
      // Return the current status without updating state here
      // State will be updated by the calling code to avoid race conditions
      return { aiActive: isActive, sessionStatus: status };
    } catch (error) {
      console.error("Error checking AI mode status:", error);
      
      // Add more detailed error logging with context
      const errorDetails = {
        focusGroupId: id,
        currentAiModeStatus: isAiModeActive,
        errorType: 'unknown',
        timestamp: new Date().toISOString()
      };
      
      if (error.response) {
        errorDetails.errorType = 'api_error';
        errorDetails.status = error.response.status;
        errorDetails.data = error.response.data;
        console.error('API error response:', error.response.status, error.response.data);
        
        // Specific handling for common API errors
        if (error.response.status === 404) {
          console.warn('Focus group not found - may have been deleted');
        } else if (error.response.status === 500) {
          console.error('Server error during status check - backend issue');
        }
      } else if (error.request) {
        errorDetails.errorType = 'network_error';
        console.error('Network error - no response received, check connectivity');
      } else {
        errorDetails.errorType = 'request_setup';
        errorDetails.message = error.message;
        console.error('Request setup error:', error.message);
      }
      
      console.debug('Status check error details:', errorDetails);
      
      // Don't change the current state on error - return current state
      return { aiActive: isAiModeActive, sessionStatus: sessionStatus, isGenerating: false };
    }
  };

  // Handle session ending with concluding statement
  const handleSessionEnding = async (newStatus: string, previousStatus: string) => {
    if (!id || sessionEndingProcessedRef.current) return;
    
    // Define statuses that indicate a session has ended
    const endedStatuses = ['completed', 'paused'];
    const activeStatuses = ['ai_mode', 'autonomous_active', 'active', 'in-progress'];
    
    const wasActive = activeStatuses.includes(previousStatus);
    const isNowEnded = endedStatuses.includes(newStatus);
    
    // Trigger concluding statement if session transitioned from active to ended
    if (wasActive && isNowEnded) {
      sessionEndingProcessedRef.current = true;
      
      try {
        // Determine the reason based on the status change
        let reason = 'session_ended';
        if (newStatus === 'completed') {
          reason = 'auto_complete';
        } else if (newStatus === 'paused') {
          reason = 'manual_stop';
        }
        
        
        // Call the new endSession API
        const response = await focusGroupAiApi.endSession(id, reason);
        
        if (response?.data) {
          
          // Show success toast
          toastService.success("Session concluded", {
            description: "The focus group session has ended with a concluding statement from the moderator."
          });
          
          // Refresh messages to show the concluding statement
          setTimeout(() => {
            fetchMessages();
          }, 1000);
        }
      } catch (error) {
        console.error('❌ Error ending session with concluding statement:', error);
        toastService.error("Error ending session", {
          description: "Failed to add concluding statement, but the session has ended."
        });
      }
    }
  };
  
  // Fetch messages for the focus group
  const fetchMessages = async () => {
    if (!id) return;
    
    
    try {
      const response = await focusGroupsApi.getMessages(id);
      console.log('🔍 [FetchMessages] Raw API response:', response?.data);
      
      // Handle both old (array) and new (object with messages/mode_events) response formats
      let messagesData: any[] = [];
      let modeEventsData: any[] = [];
      
      if (response && response.data) {
        if (Array.isArray(response.data)) {
          // Old format - just messages
          messagesData = response.data;
          modeEventsData = [];
        } else if (response.data.messages || response.data.mode_events) {
          // New format - messages and mode events (both could be present or just one)
          messagesData = response.data.messages || [];
          modeEventsData = response.data.mode_events || [];
        } else {
          // Fallback - treat the whole response as messages array
          messagesData = Array.isArray(response.data) ? response.data : [];
          modeEventsData = [];
        }
      }
      
      // Convert dates and format messages
      const formattedMessages = messagesData.map((msg: any) => ({
        id: msg._id || msg.id || `msg-${Date.now()}`,
        senderId: msg.senderId,
        text: msg.text,
        timestamp: new Date(msg.timestamp || msg.created_at),
        type: msg.type || 'response',
        highlighted: msg.highlighted || false,
        visualAsset: msg.visualAsset // Include visual asset metadata for image display
      }));
      
      console.log('🔍 [FetchMessages] Formatted messages with visual assets:', 
        formattedMessages.filter(m => m.visualAsset).map(m => ({
          id: m.id,
          senderId: m.senderId,
          hasVisualAsset: !!m.visualAsset,
          visualAsset: m.visualAsset
        }))
      );
      
      // Convert dates and format mode events
      const formattedModeEvents = modeEventsData.map((event: any) => ({
        id: event._id || event.id || `event-${Date.now()}`,
        focus_group_id: event.focus_group_id,
        event_type: event.event_type,
        timestamp: new Date(event.timestamp || event.created_at),
        user_id: event.user_id,
        created_at: new Date(event.created_at)
      }));
      
      // Always update mode events
      setModeEvents(formattedModeEvents);
      
      // Always process messages, use functional setState to access current state
      if (formattedMessages.length > 0) {
        setMessages(prevMessages => {
          if (prevMessages.length === 0) {
            // No existing messages, use the fetched ones
            return formattedMessages;
          } else {
            // Merge messages, keeping any local ones that aren't in the API response
            // and preserving the highlighted state for existing messages
            
            // Create a map of existing messages by ID for quick lookup
            const existingMsgsMap = new Map();
            prevMessages.forEach(msg => existingMsgsMap.set(msg.id, msg));
            
            // Process all messages from the API
            const processedMessages = formattedMessages.map(apiMsg => {
              // If we already have this message locally, preserve its highlighted state
              if (existingMsgsMap.has(apiMsg.id)) {
                const existingMsg = existingMsgsMap.get(apiMsg.id);
                return {
                  ...apiMsg,
                  highlighted: existingMsg.highlighted // Keep local highlight state
                };
              }
              return apiMsg; // New message, use API data
            });
            
            // Add new messages from API that don't exist locally
            const newMsgIds = new Set(processedMessages.map(msg => msg.id));
            const localOnlyMessages = prevMessages.filter(msg => !newMsgIds.has(msg.id));
            
            const mergedMessages = [...processedMessages, ...localOnlyMessages];
            
            // Sort by timestamp
            return mergedMessages.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
          }
        });
      } else if (formattedMessages.length === 0) {
        // API returned empty - only clear messages if we don't have any yet
        setMessages(prevMessages => {
          if (prevMessages.length === 0) {
            return [];
          } else {
            return prevMessages; // Keep existing messages
          }
        });
      }
      
      // Generate basic themes from highlighted messages (run this regardless of new messages)
      // Find highlighted messages and create themes from them 
      const highlightedMessages = formattedMessages.filter(msg => msg.highlighted);
      
      // Create themes from highlighted messages
      const extractedThemes = highlightedMessages.length > 0 
        ? highlightedMessages.map(msg => ({
            id: `theme-${msg.id}`,
            text: msg.text.substring(0, 40) + (msg.text.length > 40 ? '...' : ''),
            count: 1,
            messages: [msg.id],
            source: 'highlight' as const
          }))
        : [];
      
      // Also fetch any AI-generated themes
      try {
        const aiThemesResponse = await focusGroupAiApi.getKeyThemes(id);
        if (aiThemesResponse?.data?.themes && Array.isArray(aiThemesResponse.data.themes)) {
          const generatedThemes = aiThemesResponse.data.themes;
          setThemes([...extractedThemes, ...generatedThemes]);
        } else {
          setThemes(extractedThemes);
        }
      } catch (error) {
        console.error("Error fetching AI-generated themes:", error);
        setThemes(extractedThemes);
      }
    } catch (error) {
      console.error("Error fetching messages:", error);
      // Keep existing messages if API fails
      if (messages.length === 0) {
        toastService.error("Failed to fetch messages", {
          description: "Please try again later or restart the session."
        });
      }
    }
  };

  // Function to reload the focus group data
  const reloadFocusGroup = async () => {
    
    if (!id) return false;
    
    try {
      const allPersonasResponse = await personasApi.getAll();
      const allPersonas = allPersonasResponse.data || [];
      
      const response = await focusGroupsApi.getById(id);
      
      if (response && response.data) {
        const data = response.data;
        console.log("Focus group data from API:", data);
        
        // Process focus group data
        const focusGroupData = {
          id: data._id || data.id,
          name: data.name,
          status: data.status || 'in-progress',
          participants: data.participants || [],
          date: data.date || new Date().toISOString(),
          duration: data.duration || 60,
          topic: data.topic || 'general',
          discussionGuide: data.discussionGuide || '',
          llm_model: data.llm_model || 'gemini-3-pro-preview'
        };
        
        setFocusGroup(focusGroupData);
        setSelectedModel(focusGroupData.llm_model || 'gemini-3-pro-preview');
        setSelectedReasoningEffort(focusGroupData.reasoning_effort || 'medium');
        setSelectedVerbosity(focusGroupData.verbosity || 'medium');
        
        // Handle participants
        if (data.participants_data && Array.isArray(data.participants_data)) {
          // Use participants data if available
          setParticipants(data.participants_data.map((p: any) => ({
            ...p,
            id: p._id || p.id
          })));
        } else if (focusGroupData.participants && Array.isArray(focusGroupData.participants)) {
          console.log("Matching participants from DB:", {
            focusGroupParticipants: focusGroupData.participants,
            allPersonas: allPersonas.map(p => ({ id: p._id || p.id, name: p.name }))
          });
          
          // Otherwise use real personas from the database
          const groupParticipants = allPersonas.filter(persona => {
            const personaId = persona._id || persona.id;
            return focusGroupData.participants.includes(personaId);
          });
          
          console.log("Matched participants:", groupParticipants.map(p => p.name));
          setParticipants(groupParticipants);
        }
        
        // Load messages and moderator status
        await fetchMessages();
        await fetchModeratorStatus();
        
        // Immediately check and update AI mode status
        const statusResult = await checkAiModeStatus();
        setIsAiModeActive(statusResult.aiActive);
        setSessionStatus(statusResult.sessionStatus);
        
        // Initialize the refs with the initial API result
        lastAiStatusRef.current = statusResult.aiActive;
        lastSessionStatusRef.current = statusResult.sessionStatus;
        
        return true;
      }
      return false;
    } catch (error) {
      console.error("Error fetching focus group:", error);
      return false;
    }
  };

  // Function to update the LLM model for this focus group
  const updateFocusGroupModel = async (newModel: string, reasoningEffort?: string, verbosity?: string) => {
    console.log('🔧 updateFocusGroupModel called with:', { id, focusGroup: !!focusGroup, newModel, reasoningEffort, verbosity });
    
    if (!id || !focusGroup) {
      console.log('❌ updateFocusGroupModel: Missing id or focusGroup', { id, focusGroup: !!focusGroup });
      return;
    }
    
    setIsUpdatingModel(true);
    try {
      const updateData: any = { llm_model: newModel };
      
      // Only include GPT-5 parameters if the model is GPT-5
      if (newModel === 'gpt-5') {
        updateData.reasoning_effort = reasoningEffort || selectedReasoningEffort;
        updateData.verbosity = verbosity || selectedVerbosity;
      }
      
      console.log('🔧 Making API call to update focus group model:', { id, updateData });
      const response = await focusGroupsApi.update(id, updateData);
      
      console.log('🔧 API response:', response);
      
      if (response && response.data) {
        setFocusGroup(prev => prev ? { 
          ...prev, 
          llm_model: newModel,
          reasoning_effort: newModel === 'gpt-5' ? (reasoningEffort || selectedReasoningEffort) : prev?.reasoning_effort,
          verbosity: newModel === 'gpt-5' ? (verbosity || selectedVerbosity) : prev?.verbosity
        } : null);
        toastService.success('AI Model Updated', {
          description: `Focus group will now use ${
            newModel === 'gemini-3-pro-preview' ? 'Gemini 3 Pro' : 
            newModel === 'gpt-4.1' ? 'GPT-4.1' : 
            newModel === 'gpt-5' ? 'GPT-5' : newModel
          } for AI responses`
        });
        setShowModelSettings(false);
        console.log('✅ Model update successful');
      } else {
        console.log('❌ API response missing data:', response);
      }
    } catch (error) {
      console.error('❌ Error updating focus group model:', error);
      toastService.error('Failed to update AI model', {
        description: 'There was an error updating the AI model. Please try again.'
      });
    } finally {
      setIsUpdatingModel(false);
    }
  };

  useEffect(() => {
    console.log("Looking for focus group with ID:", id);
    
    // Fetch all personas from the database first
    const fetchAllPersonas = async () => {
      try {
        const response = await personasApi.getAll();
        return response.data || [];
      } catch (error) {
        console.error("Error fetching personas:", error);
        return [];
      }
    };
    
    // First try to fetch from API
    const fetchFocusGroup = async (allPersonas: any[]) => {
      try {
        const response = await focusGroupsApi.getById(id as string);
        
        if (response && response.data) {
          const data = response.data;
          console.log("Focus group data from API:", data);
          
          // Process focus group data
          const focusGroupData = {
            id: data._id || data.id,
            name: data.name,
            status: data.status || 'in-progress',
            participants: data.participants || [],
            date: data.date || new Date().toISOString(),
            duration: data.duration || 60,
            topic: data.topic || 'general',
            discussionGuide: data.discussionGuide || '',
            llm_model: data.llm_model || 'gemini-3-pro-preview'
          };
          
          setFocusGroup(focusGroupData);
          setSelectedModel(focusGroupData.llm_model || 'gemini-3-pro-preview');
        setSelectedReasoningEffort(focusGroupData.reasoning_effort || 'medium');
        setSelectedVerbosity(focusGroupData.verbosity || 'medium');
          
          // Handle participants
          if (data.participants_data && Array.isArray(data.participants_data)) {
            // Use participants data if available
            setParticipants(data.participants_data.map((p: any) => ({
              ...p,
              id: p._id || p.id
            })));
          } else if (focusGroupData.participants && Array.isArray(focusGroupData.participants)) {
            console.log("Matching participants from DB:", {
              focusGroupParticipants: focusGroupData.participants,
              allPersonas: allPersonas.map(p => ({ id: p._id || p.id, name: p.name }))
            });
            
            // Otherwise use real personas from the database
            const groupParticipants = allPersonas.filter(persona => {
              const personaId = persona._id || persona.id;
              return focusGroupData.participants.includes(personaId);
            });
            
            console.log("Matched participants:", groupParticipants.map(p => p.name));
            setParticipants(groupParticipants);
          }
          
          // Always load messages from the database
          fetchMessages();
          fetchModeratorStatus();
          
          setIsLoading(false); // Stop loading once focus group is loaded
          return true;
        }
        return false;
      } catch (error) {
        console.error("Error fetching focus group:", error);
        return false;
      }
    };
    
    // Set up dynamic polling based on AI mode status
    let messageRefreshInterval: number | undefined;
    let aiStatusCheckInterval: number | undefined;
    
    // Try API first with real personas
    fetchAllPersonas().then(allPersonas => {
      fetchFocusGroup(allPersonas).then(success => {
        if (success) {
          // Set up polling if WebSocket is disabled OR if WebSocket connection failed
          const wsConnectionFailed = wsError && (wsError.includes('unavailable') || wsError.includes('websocket error'));
          const shouldUsePolling = !useWebSocketEnabled || (useWebSocketEnabled && wsConnectionFailed);
          
          if (shouldUsePolling) {
            console.log(useWebSocketEnabled ? '📡 WebSocket connection failed, falling back to polling' : '📡 WebSocket disabled, using polling for updates');
            const startDynamicPolling = () => {
            const pollMessages = () => {
              fetchMessages();
              fetchModeratorStatus();
              
              // Don't check AI status here - let the dedicated 15s interval handle it
              // This prevents state oscillation from competing interval calls
              
              // Clear existing interval
              if (messageRefreshInterval) {
                window.clearInterval(messageRefreshInterval);
              }
              
              // Set new interval based on current AI mode status
              const interval = isAiModeActive ? 3000 : 10000; // 3s when AI active, 10s when inactive
              
              // DEBUG: Log polling setup
              console.log('📡 Setting up message polling:', {
                aiModeActive: isAiModeActive,
                pollInterval: interval,
                timestamp: new Date().toISOString()
              });
              
              messageRefreshInterval = window.setInterval(() => {
                // Skip polling when editing discussion guide to prevent focus loss
                if (!isEditingDiscussionGuideRef.current) {
                  console.log('📡 Polling for messages...', new Date().toISOString());
                  fetchMessages();
                  fetchModeratorStatus();
                } else {
                  console.log('📡 Skipping poll - editing discussion guide');
                }
              }, interval);
            };
            
            // Start polling
            pollMessages();
            
            // Also check AI status every 15 seconds to adjust polling if needed
            aiStatusCheckInterval = window.setInterval(async () => {
              const previousApiStatus = lastAiStatusRef.current;
              const previousSessionStatus = lastSessionStatusRef.current;
              const statusResult = await checkAiModeStatus();
              
              // Update the refs with the new API results
              lastAiStatusRef.current = statusResult.aiActive;
              lastSessionStatusRef.current = statusResult.sessionStatus;
              
              // Update state after getting the new status
              setIsAiModeActive(statusResult.aiActive);
              setSessionStatus(statusResult.sessionStatus);
              
              // Check for session ending (status transition)
              if (previousSessionStatus && previousSessionStatus !== statusResult.sessionStatus) {
                await handleSessionEnding(statusResult.sessionStatus, previousSessionStatus);
              }
              
              // Only restart interval if AI mode actually changed
              if (previousApiStatus !== statusResult.aiActive && messageRefreshInterval) {
                window.clearInterval(messageRefreshInterval);
                const newInterval = statusResult.aiActive ? 3000 : 10000;
                
                messageRefreshInterval = window.setInterval(() => {
                  // Skip polling when editing discussion guide to prevent focus loss
                  if (!isEditingDiscussionGuideRef.current) {
                    fetchMessages();
                    fetchModeratorStatus();
                  }
                }, newInterval);
              }
            }, 15000); // Check every 15 seconds
          };
          
          startDynamicPolling();
            } else {
              console.log('📡 WebSocket enabled, skipping polling setup');
            }
        } else {
          console.error("Focus group not found with ID:", id);
          setIsLoading(false); // Stop loading since we've determined it's not found
          toastService.error("Focus group not found", {
            description: `Could not find focus group with ID: ${id}`
          });
          // Don't navigate immediately, let user see the error message
        }
      });
    });
    
    // Clean up intervals on component unmount
    return () => {
      if (messageRefreshInterval) {
        window.clearInterval(messageRefreshInterval);
      }
      if (aiStatusCheckInterval) {
        window.clearInterval(aiStatusCheckInterval);
      }
    };
  }, [id, navigate, useWebSocketEnabled, wsError]);
  
  // Helper function to get the first discussion item from the discussion guide
  const getFirstDiscussionItem = (discussionGuide: any) => {
    // Check if we have a valid structured discussion guide
    if (!discussionGuide || !discussionGuide.sections || !Array.isArray(discussionGuide.sections)) {
      return {
        content: "Welcome to our focus group session! Let's begin our discussion.",
        sectionId: 'welcome',
        itemId: 'welcome-message'
      };
    }

    // Get the first section
    const firstSection = discussionGuide.sections[0];
    if (!firstSection) {
      return {
        content: "Welcome to our focus group session! Let's begin our discussion.",
        sectionId: 'welcome',
        itemId: 'welcome-message'
      };
    }

    // Helper to get first item from a container (section or subsection)
    const getFirstItemFromContainer = (container: any) => {
      // Check for questions first
      if (container.questions && Array.isArray(container.questions) && container.questions.length > 0) {
        return {
          content: container.questions[0].content,
          itemId: container.questions[0].id,
          type: 'question'
        };
      }
      
      // Then check for activities
      if (container.activities && Array.isArray(container.activities) && container.activities.length > 0) {
        return {
          content: container.activities[0].content,
          itemId: container.activities[0].id,
          type: 'activity'
        };
      }
      
      return null;
    };

    // Try to get first item from the first section
    let firstItem = getFirstItemFromContainer(firstSection);
    
    // If the first section doesn't have direct questions/activities, check subsections
    if (!firstItem && firstSection.subsections && Array.isArray(firstSection.subsections)) {
      for (const subsection of firstSection.subsections) {
        firstItem = getFirstItemFromContainer(subsection);
        if (firstItem) break;
      }
    }

    // Return the first item if found, otherwise a fallback
    if (firstItem) {
      return {
        content: firstItem.content,
        sectionId: firstSection.id,
        itemId: firstItem.itemId
      };
    }

    // Fallback if no questions or activities found
    return {
      content: `Welcome to our focus group session on "${firstSection.title || 'our topic'}". Let's begin our discussion.`,
      sectionId: firstSection.id,
      itemId: 'section-intro'
    };
  };
  
  const startSession = async () => {
    if (id) {
      try {
        toastService.info("Starting focus group session...", {
          description: "The session is now ready for AI moderation."
        });
        
        // Only initialize moderator position if it doesn't already exist
        // This preserves progress if someone stops and restarts the session
        try {
          const currentStatus = await focusGroupAiApi.getModeratorStatus(id);
          const hasExistingPosition = currentStatus?.data?.status?.moderator_position;
          
          if (!hasExistingPosition) {
            await focusGroupAiApi.setModeratorPosition(id, 
              focusGroup?.discussionGuide?.sections?.[0]?.id || 'welcome'
            );
            console.log('🚀 Moderator position initialized to start of discussion guide (first time)');
          } else {
            console.log('📍 Preserving existing moderator position:', hasExistingPosition);
          }
        } catch (error) {
          console.warn('Failed to check/initialize moderator position:', error);
        }

        // Set the focus group status to active
        await focusGroupsApi.update(id, { 
          status: 'active'
        });

        // Create initial moderator message from the discussion guide
        try {
          const firstDiscussionItem = getFirstDiscussionItem(focusGroup?.discussionGuide);
          
          // Send the message to the API - it will be added back via websocket/polling with server timestamp
          const msgResponse = await focusGroupsApi.sendMessage(id, {
            senderId: 'moderator',
            text: firstDiscussionItem.content,
            type: 'question'
          });

          console.log('🚀 Initial moderator message created:', {
            content: firstDiscussionItem.content,
            sectionId: firstDiscussionItem.sectionId,
            itemId: firstDiscussionItem.itemId
          });

        } catch (messageError) {
          console.warn('Failed to create initial moderator message:', messageError);
          // Don't fail the entire session start if message creation fails
          // The session can still proceed without the initial message
        }
        
        toastService.success("Focus group session started", {
          description: "The discussion has begun. Use the control panel below to moderate."
        });
      } catch (error) {
        console.error("Error starting session:", error);
        toastService.error("Error starting session", {
          description: "There was a problem connecting to the server."
        });
      }
    }
  };
  
  // This function is kept for backward compatibility with other features
  // but we now use the direct AI response generation in DiscussionPanel
  const addModeratorMessage = async () => {
    try {
      if (!id) return;
      
      // Send to API - message will be added back via websocket/polling with server timestamp
      const msgResponse = await focusGroupsApi.sendMessage(id, {
        senderId: 'moderator',
        text: 'Can you share specific examples that you think handle this particularly well?',
        type: 'question'
      });
      
      toastService.info("Added moderator message", {
        description: "You can now click 'Advance Discussion' to get AI-generated responses."
      });
      
    } catch (error) {
      console.error("Error adding moderator message:", error);
      toastService.error("Failed to add moderator message", {
        description: "There was a problem connecting to the server."
      });
    }
  };
  
  // Handler for adding new messages to the conversation
  const handleNewMessage = (message: Message) => {
    setMessages(prevMessages => {
      // Check for duplicates
      const exists = prevMessages.find(m => m.id === message.id);
      if (exists) {
        console.log('🔧 [handleNewMessage] Message already exists, skipping:', message.id);
        return prevMessages;
      }
      
      console.log('🔧 [handleNewMessage] Adding new message:', message.id);
      return [...prevMessages, message];
    });
  };
  
  const toggleHighlight = async (messageId: string) => {
    // First update the UI optimistically
    const updatedMessages = [...messages];
    const messageIndex = updatedMessages.findIndex(msg => msg.id === messageId);
    
    if (messageIndex !== -1) {
      const message = updatedMessages[messageIndex];
      const newHighlightState = !message.highlighted;
      
      // Update locally first for immediate feedback
      updatedMessages[messageIndex] = { 
        ...message, 
        highlighted: newHighlightState 
      };
      setMessages(updatedMessages);
      
      // Then save to database if we have a valid focus group ID
      if (id) {
        try {
          // Don't attempt to update local test messages in the database
          if (!messageId.startsWith('local-') && !messageId.startsWith('msg-')) {
            await focusGroupsApi.updateMessageHighlight(id, messageId, newHighlightState);
          } else {
            console.log('Skipping database update for local message:', messageId);
          }
        } catch (error) {
          console.error('Error updating message highlight state:', error);
          toastService.error('Failed to save highlight state', {
            description: 'The highlight may not persist if the page is refreshed.'
          });
        }
      }
    }
  };
  
  
  const getPersona = (id: string) => {
    // Handle both local-created IDs and MongoDB IDs
    return participants.find(p => p.id === id || p._id === id);
  };
  
  const downloadTranscript = () => {
    const transcript = messages.map(msg => {
      let sender: string;
      if (msg.senderId === 'moderator') {
        sender = 'AI Moderator';
      } else if (msg.senderId === 'facilitator') {
        sender = 'Human Facilitator';
      } else {
        sender = getPersona(msg.senderId)?.name || 'Unknown';
      }
      const time = msg.timestamp.toLocaleTimeString();
      return `[${time}] ${sender}: ${msg.text}`;
    }).join('\n\n');
    
    const element = document.createElement('a');
    const file = new Blob([transcript], {type: 'text/plain'});
    element.href = URL.createObjectURL(file);
    element.download = `focus-group-${id}-transcript.txt`;
    document.body.appendChild(element);
    element.click();
    document.body.removeChild(element);
    
    toastService.success("Transcript downloaded", {
      description: "The focus group transcript has been saved to your device."
    });
  };


  const handleQuoteClick = (quote: string | QuoteData, messageId?: string) => {
    // Helper function to extract quote text without speaker attribution
    const extractQuoteText = (quote: string): string => {
      // Check if quote has attribution format [Name]: text
      const attributionMatch = quote.match(/^\[([^\]]+)\]:\s*(.*)$/);
      if (attributionMatch) {
        return attributionMatch[2].trim();
      }
      return quote.trim();
    };

    // Helper function to normalize text for comparison
    const normalizeText = (text: string): string => {
      return text.toLowerCase()
        .replace(/[^\w\s]/g, ' ')  // Replace punctuation with spaces
        .replace(/\s+/g, ' ')      // Normalize whitespace
        .trim();
    };

    // Helper function to calculate similarity between two strings
    const calculateSimilarity = (str1: string, str2: string): number => {
      const normalized1 = normalizeText(str1);
      const normalized2 = normalizeText(str2);
      
      if (normalized1 === normalized2) return 1.0;
      
      // Check if one contains the other
      if (normalized1.includes(normalized2) || normalized2.includes(normalized1)) {
        return Math.min(normalized1.length, normalized2.length) / Math.max(normalized1.length, normalized2.length);
      }
      
      // Simple word overlap calculation
      const words1 = normalized1.split(' ');
      const words2 = normalized2.split(' ');
      const commonWords = words1.filter(word => words2.includes(word) && word.length > 2);
      
      if (words1.length === 0 || words2.length === 0) return 0;
      return commonWords.length / Math.max(words1.length, words2.length);
    };

    // Handle both string and QuoteData formats
    const isQuoteData = typeof quote === 'object' && quote !== null;
    const quoteText = isQuoteData ? quote.text : extractQuoteText(quote as string);
    const originalQuote = isQuoteData ? quote.original : (quote as string);
    
    // Try multiple matching strategies in order of preference
    let matchingMessage = null;
    let matchReason = '';

    // Strategy 0: Direct message ID lookup (highest priority for new format)
    if (messageId) {
      matchingMessage = messages.find(msg => msg.id === messageId);
      if (matchingMessage) {
        matchReason = 'direct_message_id_match';
      } else {
        console.warn(`Message ID ${messageId} not found in current messages array`);
      }
    }

    // Strategy 1: Exact match with original quote (only if no message ID match)
    if (!matchingMessage) {
      matchingMessage = messages.find(msg => msg.text.includes(originalQuote));
      if (matchingMessage) {
        matchReason = 'exact_full_match';
      }
    }

    // Strategy 2: Exact match with quote text (without attribution)
    if (!matchingMessage) {
      matchingMessage = messages.find(msg => msg.text.includes(quoteText));
      if (matchingMessage) {
        matchReason = 'exact_text_match';
      }
    }

    // Strategy 3: Reverse exact match (quote contains message text)
    if (!matchingMessage) {
      matchingMessage = messages.find(msg => quoteText.includes(msg.text.trim()));
      if (matchingMessage) {
        matchReason = 'reverse_exact_match';
      }
    }

    // Strategy 4: Case-insensitive partial match
    if (!matchingMessage) {
      const quoteLower = quoteText.toLowerCase();
      matchingMessage = messages.find(msg => 
        msg.text.toLowerCase().includes(quoteLower) || 
        quoteLower.includes(msg.text.toLowerCase())
      );
      if (matchingMessage) {
        matchReason = 'case_insensitive_match';
      }
    }

    // Strategy 5: Fuzzy matching with similarity threshold
    if (!matchingMessage) {
      const candidates = messages.map(msg => ({
        message: msg,
        similarity: calculateSimilarity(quoteText, msg.text)
      }))
      .filter(candidate => candidate.similarity > 0.7)  // 70% similarity threshold
      .sort((a, b) => b.similarity - a.similarity);

      if (candidates.length > 0) {
        matchingMessage = candidates[0].message;
        matchReason = `fuzzy_match_${Math.round(candidates[0].similarity * 100)}%`;
      }
    }

    // Strategy 6: Partial word matching (as last resort)
    if (!matchingMessage) {
      const quoteLower = normalizeText(quoteText);
      const words = quoteLower.split(' ').filter(word => word.length > 3);
      
      if (words.length > 0) {
        matchingMessage = messages.find(msg => {
          const msgNormalized = normalizeText(msg.text);
          return words.every(word => msgNormalized.includes(word));
        });
        if (matchingMessage) {
          matchReason = 'partial_word_match';
        }
      }
    }
    
    if (matchingMessage) {
      // Log successful match for debugging
      console.log(`Quote match found using strategy: ${matchReason}`, {
        quoteType: isQuoteData ? 'QuoteData' : 'string',
        providedMessageId: messageId,
        extractedText: quoteText, 
        matchedMessage: matchingMessage.text.substring(0, 100),
        matchedMessageId: matchingMessage.id,
        originalQuote: originalQuote.substring(0, 100)
      });

      // Switch to discussion tab
      setActiveTab('chat');
      
      // Scroll to and highlight the message
      setTimeout(() => {
        const messageElement = document.getElementById(`message-${matchingMessage.id}`);
        if (messageElement) {
          // Don't scroll if editing discussion guide
          if (!isEditingDiscussionGuide) {
            messageElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
          }
          
          // Add a temporary highlight effect
          messageElement.style.backgroundColor = '#fbbf24';
          messageElement.style.transition = 'background-color 0.3s ease';
          
          setTimeout(() => {
            messageElement.style.backgroundColor = '';
          }, 2000);
        }
      }, 100);
    } else {
      // Log failed match for debugging
      console.warn('Quote match failed', {
        quoteType: isQuoteData ? 'QuoteData' : 'string',
        providedMessageId: messageId,
        originalQuote: originalQuote.substring(0, 100),
        extractedText: quoteText.substring(0, 100),
        totalMessages: messages.length,
        messageSample: messages.slice(0, 3).map(m => ({ id: m.id, text: m.text.substring(0, 50) }))
      });

      toastService.warning('Message not found', {
        description: 'Could not locate the original message for this quote. The quote may have been paraphrased by the AI.'
      });
    }
  };
  
  // Handler for when new themes are generated
  const handleThemesGenerated = (newThemes: Theme[]) => {
    setThemes(currentThemes => {
      // Get existing theme IDs to avoid duplicates
      const existingThemeIds = new Set(currentThemes.map(t => t.id));
      
      // Filter out themes that already exist
      const uniqueNewThemes = newThemes.filter(t => !existingThemeIds.has(t.id));
      
      return [...currentThemes, ...uniqueNewThemes];
    });
  };
  
  // Handler for deleting a theme
  const handleThemeDelete = async (themeId: string) => {
    if (!id) return;
    
    // Find the theme to delete
    const theme = themes.find(t => t.id === themeId);
    if (!theme) return;
    
    try {
      // For generated themes, delete from database
      if ('source' in theme && theme.source === 'generated') {
        await focusGroupAiApi.deleteKeyTheme(id, themeId);
      }
      
      // Update local state by removing the theme
      setThemes(themes.filter(t => t.id !== themeId));
      
    } catch (error) {
      console.error('Error deleting theme:', error);
      toastService.error('Failed to delete theme', {
        description: 'There was an error removing the theme. Please try again.'
      });
    }
  };
  
  // Handler for section selection in discussion guide
  const handleSectionSelect = useCallback(async (sectionId: string, itemId?: string) => {
    if (!id) return;
    
    try {
      await focusGroupAiApi.setModeratorPosition(id, sectionId, itemId);
      
      // Note: Moderator status will be updated automatically via WebSocket event
      
      toastService.success('Moderator position updated', {
        description: 'The moderator has been moved to the selected section.'
      });
    } catch (error) {
      console.error('Error setting moderator position:', error);
      toastService.error('Failed to update moderator position', {
        description: 'There was an error updating the moderator position.'
      });
    }
  }, [id]);
  
  // Handler for saving discussion guide changes
  const handleDiscussionGuideSave = useCallback(async (updatedGuide: any) => {
    console.log('💾 handleDiscussionGuideSave called:', {
      hasId: !!id,
      isEditingGuideContent,
      timestamp: new Date().toISOString()
    });
    
    if (!id) return;
    
    try {
      await focusGroupsApi.update(id, { 
        discussionGuide: updatedGuide 
      });
      
      // Only update local state if we're not currently editing to prevent focus loss
      if (!isEditingGuideContent) {
        console.log('🔄 Updating focus group state (not editing)');
        setFocusGroup(prev => prev ? {
          ...prev,
          discussionGuide: updatedGuide
        } : null);
      } else {
        // During editing, update the ref so we have the latest version
        if (focusGroupRef.current) {
          focusGroupRef.current = {
            ...focusGroupRef.current,
            discussionGuide: updatedGuide
          };
        }
        console.log('⚠️ Skipping focus group state update during editing to preserve focus');
      }
      
    } catch (error) {
      console.error('Error saving discussion guide:', error);
      throw error; // Re-throw to let the component handle the error display
    }
  }, [id, isEditingGuideContent]);
  
  // Handle editing state changes from DiscussionGuideViewer
  const handleGuideEditingStateChange = useCallback((editing: boolean) => {
    console.log('🔄 handleGuideEditingStateChange called:', {
      editing,
      timestamp: new Date().toISOString(),
      currentIsEditingGuideContent: isEditingGuideContent
    });
    
    // Update both editing states
    setIsEditingDiscussionGuide(editing);  // For scroll prevention
    setIsEditingGuideContent(editing);     // For focus preservation
    
    // When editing ends, update the focus group state with the latest version
    if (!editing && focusGroupRef.current) {
      console.log('📝 Updating focus group state after editing ended');
      setFocusGroup(focusGroupRef.current);
    }
  }, [isEditingGuideContent]);
  
  // Handler for toggling discussion guide
  const handleToggleDiscussionGuide = useCallback(() => {
    setIsDiscussionGuideOpen(prev => !prev);
  }, []);
  
  // Handler for setting moderator position
  const handleSetPosition = useCallback((sectionId: string, itemId: string, content: string, sectionTitle: string, itemTitle?: string, itemType?: string, metadata?: Record<string, any>) => {
    setSetPositionDialog({
      isOpen: true,
      sectionId,
      itemId,
      content,
      sectionTitle,
      itemTitle,
      itemType,
      metadata
    });
  }, []);

  // Helper function to extract asset filename from creative review content
  const extractAssetFilename = (content: string): string | null => {
    console.log('🔍 EXTRACT ASSET FILENAME DEBUG - Input content:', content);
    
    // Look for patterns like "titled 'filename.jpg'" or similar
    const patterns = [
      /'([^']*\.[a-zA-Z]{3,4})'/g,  // 'filename.ext'
      /"([^"]*\.[a-zA-Z]{3,4})"/g,  // "filename.ext"
      /titled\s+['"]([^'"]*\.[a-zA-Z]{3,4})['"](?:\.|,|\s|$)/gi,  // titled 'filename.ext'
      /asset[:\s]+['"]?([^'"\s]*\.[a-zA-Z]{3,4})['"]?(?:\.|,|\s|$)/gi,  // asset: filename.ext
      /image[:\s]+['"]?([^'"\s]*\.[a-zA-Z]{3,4})['"]?(?:\.|,|\s|$)/gi,  // image: filename.ext
      /file[:\s]+['"]?([^'"\s]*\.[a-zA-Z]{3,4})['"]?(?:\.|,|\s|$)/gi,   // file: filename.ext
      /\b([a-zA-Z0-9_-]+\.[a-zA-Z]{3,4})\b/g  // standalone filename.ext
    ];
    
    for (let i = 0; i < patterns.length; i++) {
      const pattern = patterns[i];
      console.log(`🔍 Testing pattern ${i + 1}:`, pattern.source);
      
      const matches = Array.from(content.matchAll(pattern));
      console.log(`🔍 Pattern ${i + 1} matches:`, matches.length, matches);
      
      if (matches.length > 0) {
        // Get the first capture group from the first match
        const filename = matches[0][1];
        console.log(`🔍 Pattern ${i + 1} extracted filename:`, filename);
        
        if (filename && filename.includes('.')) {
          console.log('✅ EXTRACT ASSET FILENAME - Found:', filename);
          return filename;
        }
      }
    }
    
    console.warn('❌ EXTRACT ASSET FILENAME - No filename found in content');
    return null;
  };
  
  // Notes-related functions
  const getElapsedTime = (): number => {
    if (!sessionStartTime) return 0;
    return Date.now() - sessionStartTime.getTime();
  };

  const formatElapsedTime = (milliseconds: number): string => {
    const totalSeconds = Math.floor(milliseconds / 1000);
    const minutes = Math.floor(totalSeconds / 60);
    const seconds = totalSeconds % 60;
    return `${minutes}:${seconds.toString().padStart(2, '0')}`;
  };

  const getCurrentSectionInfo = () => {
    if (!moderatorStatus) return undefined;
    
    return {
      sectionId: moderatorStatus.current_section_id,
      sectionTitle: moderatorStatus.current_section,
      itemId: moderatorStatus.current_item_id,
      itemTitle: moderatorStatus.current_item
    };
  };

  const getMostRecentMessageId = (): string | undefined => {
    if (messages.length === 0) return undefined;
    return messages[messages.length - 1].id;
  };

  const getMessageTimestamp = (): Date => {
    const messageId = getMostRecentMessageId();
    
    // If we have messages, use the most recent message timestamp
    if (messageId && messages.length > 0) {
      const associatedMessage = messages.find(msg => msg.id === messageId);
      if (associatedMessage) {
        return associatedMessage.timestamp;
      }
    }
    
    // Fallback: use focus group date, session start time, or current time as last resort
    if (focusGroup?.date) {
      return new Date(focusGroup.date);
    }
    
    if (sessionStartTime) {
      return sessionStartTime;
    }
    
    return new Date();
  };

  // Theme generation functions
  const generateKeyThemes = async () => {
    if (!id) return;

    // Reset states and open progress modal
    themeGenerationControls.startGeneration();
    setIsThemeProgressModalOpen(true);

    toastService.info("Analyzing discussion for key themes...", {
      description: "This may take a moment as we process the entire conversation."
    });

    try {
      const response = await focusGroupAiApi.generateKeyThemes(id);

      if (response.data && response.data.themes) {
        // Update themes state immediately
        setThemes(prevThemes => [...prevThemes, ...response.data.themes]);

        // Allow progress to animate for at least 3 seconds before completing
        setTimeout(() => {
          themeGenerationControls.completeGeneration();
          toastService.success(`Generated ${response.data.themes.length} key themes`, {
            description: "New themes have been added to the analysis."
          });
        }, 3000);
      } else {
        // Allow progress to animate for at least 3 seconds before completing
        setTimeout(() => {
          themeGenerationControls.completeGeneration();
          toastService.warning("No new themes were generated", {
            description: "Try again when the discussion has more content."
          });
        }, 3000);
      }
    } catch (error) {
      console.error('Error generating key themes:', error);
      themeGenerationControls.failGeneration('Failed to generate key themes');
      toastService.error("Failed to generate key themes", {
        description: "There was an error analyzing the discussion. Please try again."
      });
    }
    // Note: Don't reset generation here - let the progress modal handle it
  };

  const handleThemeProgressComplete = () => {
    setIsThemeProgressModalOpen(false);
    themeGenerationControls.resetGeneration();
  };

  const handleOpenNoteModal = () => {
    // Initialize session start time if not already set
    if (!sessionStartTime) {
      setSessionStartTime(new Date());
    }
    setIsNoteModalOpen(true);
  };

  const handleNoteSaved = (note: Note) => {
    setNotes(prevNotes => [...prevNotes, note].sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()));
    
    // Also add to NotesPanel if it exists
    if ((window as any).notesPanelAddNote) {
      (window as any).notesPanelAddNote(note);
    }
  };

  const handleNoteClick = (associatedMessageId: string) => {
    // Find the message that matches this ID
    const matchingMessage = messages.find(msg => msg.id === associatedMessageId);
    
    if (matchingMessage) {
      // Switch to discussion tab
      setActiveTab('chat');
      
      // Scroll to and highlight the message
      setTimeout(() => {
        const messageElement = document.getElementById(`message-${matchingMessage.id}`);
        if (messageElement) {
          // Don't scroll if editing discussion guide
          if (!isEditingDiscussionGuide) {
            messageElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
          }
          
          // Add a temporary highlight effect
          messageElement.style.backgroundColor = '#fbbf24';
          messageElement.style.transition = 'background-color 0.3s ease';
          
          setTimeout(() => {
            messageElement.style.backgroundColor = '';
          }, 2000);
        }
      }, 100);
    } else {
      toastService.info('Message not found', {
        description: 'Could not locate the original message for this note.'
      });
    }
  };

  // Initialize session start time when messages first appear
  useEffect(() => {
    if (messages.length > 0 && !sessionStartTime) {
      setSessionStartTime(new Date());
    }
  }, [messages.length, sessionStartTime]);
  
  
  // Sync editing state with ref and fetch latest moderator status when editing stops
  useEffect(() => {
    isEditingDiscussionGuideRef.current = isEditingDiscussionGuide;
    if (!isEditingDiscussionGuide) {
      // Fetch the latest moderator status when editing stops
      fetchModeratorStatus();
    }
  }, [isEditingDiscussionGuide]);
  
  // Toggle participant filter selection
  const toggleParticipantFilter = (participantId: string) => {
    setSelectedParticipantIds(prevSelected => {
      if (prevSelected.includes(participantId)) {
        // Remove participant from selection
        return prevSelected.filter(id => id !== participantId);
      } else {
        // Add participant to selection
        return [...prevSelected, participantId];
      }
    });
  };
  
  // Show loading state while fetching
  if (isLoading) {
    return (
      <div className="min-h-screen bg-slate-50 pt-20 pb-16 px-4">
        <Navigation />
        <div className="max-w-7xl mx-auto text-center py-12">
          <div className="flex justify-center items-center">
            <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
          </div>
          <p className="mt-4 text-slate-600">Loading focus group...</p>
        </div>
      </div>
    );
  }

  // Show error state if not found after loading
  if (!focusGroup) {
    return (
      <div className="min-h-screen bg-slate-50 pt-20 pb-16 px-4">
        <Navigation />
        <div className="max-w-7xl mx-auto text-center py-12">
          <h1 className="text-2xl font-bold">Focus group not found</h1>
          <p className="mt-2 text-slate-600">We couldn't find the focus group you're looking for.</p>
          <Button 
            onClick={() => navigate('/focus-groups')} 
            className="mt-4"
          >
            <ArrowLeft className="mr-2 h-4 w-4" /> Back to Focus Groups
          </Button>
        </div>
      </div>
    );
  }
  
  return (
    <div className="min-h-screen bg-slate-50">
      <Navigation />
      
      {/* WebSocket Connection Status Bar */}
      {useWebSocketEnabled && isStatusBarVisible && (
        <div className={`w-full transition-all duration-300 ${
          wsConnected 
            ? 'bg-green-500' 
            : wsConnecting 
              ? 'bg-yellow-500' 
              : 'bg-red-500'
        }`}>
          <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
            <div className="flex items-center justify-between py-2 text-white text-sm font-medium">
              <div className="flex items-center space-x-2">
                <div className={`w-2 h-2 rounded-full ${
                  wsConnected 
                    ? 'bg-white animate-pulse' 
                    : wsConnecting 
                      ? 'bg-white animate-spin' 
                      : 'bg-white'
                }`} />
                <span>
                  {wsConnected 
                    ? 'Real-time updates active - Changes appear instantly'
                    : wsConnecting 
                      ? 'Connecting to real-time updates...'
                      : 'Real-time updates unavailable - Using periodic refresh'}
                </span>
                {wsError && (
                  <span className="text-xs opacity-75 ml-2" title={wsError}>
                    (Connection error)
                  </span>
                )}
              </div>
              
              <button 
                onClick={() => setIsStatusBarVisible(false)}
                className="ml-4 text-white hover:text-gray-200 transition-colors"
                title="Hide status bar"
                aria-label="Hide connection status"
              >
                <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
                </svg>
              </button>
            </div>
          </div>
        </div>
      )}
      
      {/* Status Bar Toggle Button (when hidden) */}
      {useWebSocketEnabled && !isStatusBarVisible && (
        <div className="fixed top-20 right-4 z-40">
          <button
            onClick={() => setIsStatusBarVisible(true)}
            className={`px-3 py-1 rounded-full text-white text-xs font-medium shadow-lg transition-all duration-200 hover:shadow-xl ${
              wsConnected 
                ? 'bg-green-500 hover:bg-green-600' 
                : wsConnecting 
                  ? 'bg-yellow-500 hover:bg-yellow-600' 
                  : 'bg-red-500 hover:bg-red-600'
            }`}
            title={
              wsConnected 
                ? 'WebSocket connected - Show status bar'
                : wsConnecting 
                  ? 'WebSocket connecting - Show status bar'
                  : 'WebSocket disconnected - Show status bar'
            }
          >
            <div className="flex items-center space-x-1">
              <div className={`w-2 h-2 rounded-full bg-white ${wsConnected ? 'animate-pulse' : ''}`} />
              <span>{wsConnected ? 'Live' : wsConnecting ? 'Connecting' : 'Offline'}</span>
            </div>
          </button>
        </div>
      )}
      
      <main className="pt-20 pb-16 px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto">
        <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center mb-4">
          <div className="flex items-center">
            <Button 
              variant="ghost" 
              onClick={() => navigate('/focus-groups')}
              className="mr-2"
            >
              <ArrowLeft className="h-4 w-4" />
            </Button>
            <div>
              <h1 className="font-sf text-2xl font-bold text-slate-900">{focusGroup.name}</h1>
              <p className="text-slate-600">{new Date(focusGroup.date).toLocaleString()}</p>
              <div className="flex items-center mt-1">
                <Bot className="h-3 w-3 text-slate-500 mr-1" />
                <Badge variant="secondary" className="text-xs">
                  {focusGroup.llm_model === 'gpt-4.1' ? 'GPT-4.1' : 
                   focusGroup.llm_model === 'gpt-5' ? 'GPT-5' : 'Gemini 3 Pro'}
                </Badge>
              </div>
            </div>
          </div>
          
          <div className="flex items-center space-x-4 mt-4 sm:mt-0">
            <Button 
              variant="outline" 
              onClick={() => setShowAutonomousDashboard(!showAutonomousDashboard)}
              className={showAutonomousDashboard ? 'bg-blue-50 text-blue-600' : ''}
            >
              <BarChart className="mr-2 h-4 w-4" />
              AI Dashboard
            </Button>
            
            <Button 
              variant="outline" 
              onClick={() => setShowModelSettings(true)}
            >
              <Settings className="mr-2 h-4 w-4" />
              AI Model
            </Button>
            
            <Button variant="outline" onClick={downloadTranscript}>
              <Download className="mr-2 h-4 w-4" />
              Download Transcript
            </Button>
          </div>
        </div>
        
        {/* Progress Modal for Key Themes Generation */}
        <ProgressModal
          isOpen={isThemeProgressModalOpen}
          onClose={() => setIsThemeProgressModalOpen(false)}
          isActive={themeGenerationState.isGenerating}
          isComplete={themeGenerationState.isComplete}
          hasError={themeGenerationState.hasError}
          isCancelling={themeGenerationState.isCancelling}
          taskId={themeGenerationState.taskId}
          title="Extracting Key Themes"
          description="Analyzing the conversation to identify key themes and insights. This typically takes 30-60 seconds."
          onCancel={themeGenerationControls.cancelGeneration}
          onComplete={handleThemeProgressComplete}
        />
        
        {/* Collapsible Discussion Guide Panel */}
        <CollapsibleDiscussionGuide
          discussionGuide={focusGroup.discussionGuide}
          moderatorStatus={moderatorStatus}
          onSectionSelect={handleSectionSelect}
          onSetPosition={handleSetPosition}
          onSave={handleDiscussionGuideSave}
          focusGroupId={id || ''}
          isOpen={isDiscussionGuideOpen}
          onToggle={handleToggleDiscussionGuide}
          onEditingChange={handleGuideEditingStateChange}
        />
        
        <div className="flex flex-col lg:flex-row gap-6 h-[calc(100vh-12rem)]">
          <ParticipantPanel 
            participants={participants}
            selectedParticipantIds={selectedParticipantIds}
            onToggleParticipantFilter={toggleParticipantFilter}
          />
          
          <div className="flex-1 flex flex-col">
            <Tabs defaultValue="chat" value={activeTab} onValueChange={setActiveTab} className="w-full h-full flex flex-col">
              <TabsList className="grid grid-cols-4 mb-4">
                <TabsTrigger value="chat" className="flex items-center">
                  <MessageCircle className="h-4 w-4 mr-2" />
                  Discussion
                </TabsTrigger>
                <TabsTrigger value="themes" className="flex items-center">
                  <Lightbulb className="h-4 w-4 mr-2" />
                  Key Themes
                </TabsTrigger>
                <TabsTrigger value="notes" className="flex items-center">
                  <StickyNote className="h-4 w-4 mr-2" />
                  Notes
                </TabsTrigger>
                <TabsTrigger value="analytics" className="flex items-center">
                  <BarChart className="h-4 w-4 mr-2" />
                  Analytics
                </TabsTrigger>
              </TabsList>
              
              <TabsContent value="chat" className="m-0 flex-1 flex flex-col h-0">
                {messages.length === 0 ? (
                  <div className="flex flex-col items-center justify-center py-12 space-y-4">
                    <p className="text-lg text-slate-600">No messages yet. Start the session to begin the discussion.</p>
                    <Button 
                      onClick={startSession}
                      size="lg"
                      className="flex items-center gap-2"
                    >
                      <PlayCircle className="h-5 w-5" />
                      Start Session
                    </Button>
                  </div>
                ) : (
                  <DiscussionPanel 
                    messages={messages}
                    modeEvents={modeEvents}
                    personas={participants}
                    isSpeaking={false}
                    focusGroupId={id || ''}
                    isAiModeActive={isAiModeActive}
                    selectedParticipantIds={selectedParticipantIds}
                    onToggleHighlight={toggleHighlight}
                    onAdvanceDiscussion={() => null}
                    onNewMessage={handleNewMessage}
                    onStatusChange={reloadFocusGroup}
                    isEditingDiscussionGuide={isEditingDiscussionGuide}
                  />
                )}
              </TabsContent>
              
              <TabsContent value="themes" className="m-0">
                <ThemesPanel 
                  themes={themes} 
                  messages={messages} 
                  personas={participants}
                  focusGroupId={id || ''}
                  onThemesGenerated={handleThemesGenerated}
                  onThemeDelete={handleThemeDelete}
                  onQuoteClick={handleQuoteClick}
                  onGenerateKeyThemes={generateKeyThemes}
                />
              </TabsContent>
              
              <TabsContent value="notes" className="m-0" style={{ height: 'calc(100% - 3.5rem)' }}>
                <div className="h-full">
                  <NotesPanel 
                    focusGroupId={id || ''}
                    focusGroupName={focusGroup?.name}
                    onNoteClick={handleNoteClick}
                  />
                </div>
              </TabsContent>
              
              <TabsContent value="analytics" className="m-0">
                <AnalyticsPanel 
                  messages={messages}
                  themes={themes}
                  personas={participants}
                />
              </TabsContent>
            </Tabs>
          </div>
        </div>
      </main>
      
      {/* Floating Note Button */}
      {messages.length > 0 && (
        <div className="fixed bottom-6 right-6 z-40">
          <Button 
            onClick={handleOpenNoteModal}
            className="rounded-full h-12 w-12 p-0 shadow-lg"
            title="Take a quick note"
          >
            <StickyNote className="h-5 w-5" />
          </Button>
        </div>
      )}
      
      {/* Quick Note Modal */}
      <QuickNoteModal
        isOpen={isNoteModalOpen}
        onClose={() => setIsNoteModalOpen(false)}
        focusGroupId={id || ''}
        associatedMessageId={getMostRecentMessageId()}
        sectionInfo={getCurrentSectionInfo()}
        messageTimestamp={getMessageTimestamp()}
        onNoteSaved={handleNoteSaved}
      />
      
      {/* Set Position Confirmation Dialog */}
      <Dialog open={setPositionDialog.isOpen} onOpenChange={(open) => setSetPositionDialog(prev => ({ ...prev, isOpen: open }))}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Set Moderator Position</DialogTitle>
            <DialogDescription>
              Are you sure you want to set the moderator position to "{setPositionDialog.itemTitle}" in section "{setPositionDialog.sectionTitle}"? 
              This will make the moderator ask this question in the chat.
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button 
              variant="outline" 
              disabled={setPositionDialog.isLoading}
              onClick={() => setSetPositionDialog({ isOpen: false })}
            >
              Cancel
            </Button>
            <Button 
              disabled={setPositionDialog.isLoading}
              onClick={async () => {
                if (!id || !setPositionDialog.sectionId || !setPositionDialog.itemId || !setPositionDialog.content) return;
                
                // Set loading state
                setSetPositionDialog(prev => ({ ...prev, isLoading: true }));
                
                try {
                  // Set moderator position
                  await focusGroupAiApi.setModeratorPosition(id, setPositionDialog.sectionId, setPositionDialog.itemId);
                  
                  // Detect if this item has an image attached (regardless of item type)
                  let attachedAssets: string[] = [];
                  let activatesVisualContext = false;
                  let enhancedMessageText = setPositionDialog.content; // Start with original text
                  
                  // Check for visual asset in metadata instead of parsing content
                  const visualAsset = setPositionDialog.metadata?.visual_asset;
                  const hasImageAttached = !!visualAsset?.filename;
                  const assetFilename = visualAsset?.filename;
                  
                  console.log('🔍 MANUAL POSITION DEBUG:', {
                    itemType: setPositionDialog.itemType,
                    hasImageAttached,
                    visualAsset,
                    assetFilename,
                    content: setPositionDialog.content,
                    sectionTitle: setPositionDialog.sectionTitle,
                    itemTitle: setPositionDialog.itemTitle,
                    contentLength: setPositionDialog.content?.length
                  });
                  
                  if (hasImageAttached && setPositionDialog.content && assetFilename) {
                    console.log('🔍 VISUAL ASSET DEBUG:', {
                      originalContent: setPositionDialog.content,
                      visualAsset,
                      displayReference: visualAsset?.display_reference,
                      filename: assetFilename,
                      contentLength: setPositionDialog.content.length
                    });
                    
                    if (assetFilename) {
                      attachedAssets = [assetFilename];
                      activatesVisualContext = true;
                      console.log('🎨 MANUAL POSITION: Creative review detected, will activate visual context for:', assetFilename);
                      
                      // Generate AI description and enhance the question
                      try {
                        console.log('🎨 MANUAL MODE: Requesting AI description for', assetFilename);
                        
                        const descriptionResponse = await focusGroupsApi.describeAsset(id, assetFilename);
                        
                        if (descriptionResponse.data.description) {
                          // Enhance the question text with the AI description using display reference
                          const displayRef = visualAsset?.display_reference || 'the asset';
                          enhancedMessageText = setPositionDialog.content.replace(
                            displayRef,
                            `${displayRef} - ${descriptionResponse.data.description}`
                          );
                          
                          console.log('✅ MANUAL MODE: Enhanced question with AI description');
                          console.log('🔍 Original:', setPositionDialog.content);
                          console.log('🔍 Enhanced:', enhancedMessageText);
                        }
                        
                      } catch (descError) {
                        console.error('⚠️  MANUAL MODE: Failed to generate AI description:', descError);
                        console.error('⚠️  Error response data:', descError.response?.data);
                        console.error('⚠️  Error status:', descError.response?.status);
                        console.error('⚠️  Error headers:', descError.response?.headers);
                        console.error('⚠️  Full axios error:', {
                          message: descError.message,
                          code: descError.code,
                          status: descError.response?.status,
                          statusText: descError.response?.statusText,
                          url: descError.config?.url,
                          method: descError.config?.method
                        });
                        
                        // Show user notification about fallback
                        toastService.warning('AI description failed', {
                          description: 'Using original question text. Image will still be available to participants.'
                        });
                      }
                    } else {
                      console.warn('⚠️  MANUAL POSITION: Creative review detected but no asset filename extracted from content');
                    }
                  }
                  
                  // Send the moderator message to API - it will be added back via websocket/polling with server timestamp
                  console.log('📤 Sending moderator message to API:', {
                    text: enhancedMessageText,
                    attachedAssets,
                    activatesVisualContext
                  });
                  
                  try {
                    const msgResponse = await focusGroupsApi.sendMessage(id, {
                      senderId: 'moderator',
                      text: enhancedMessageText,
                      type: 'question',
                      attached_assets: attachedAssets,
                      activates_visual_context: activatesVisualContext,
                      visualAsset: hasImageAttached && visualAsset ? {
                        filename: assetFilename,
                        displayReference: visualAsset.display_reference
                      } : undefined
                    });
                    
                    console.log('✅ Message API call successful:', msgResponse?.data);
                  } catch (msgError) {
                    console.error('❌ Failed to save message to API:', msgError);
                    toastService.warning('Message not saved', {
                      description: 'Failed to save the moderator message to the server.'
                    });
                  }
                  
                  // Close dialog first for immediate feedback
                  setSetPositionDialog({ isOpen: false });
                  
                  // Don't fetch moderator status immediately to avoid race condition
                  // The status will update via WebSocket or next polling cycle
                  console.log('✅ Set position complete, moderator message added to UI');
                  
                  toastService.success('Moderator position set', {
                    description: `Position set to "${setPositionDialog.itemTitle}" in "${setPositionDialog.sectionTitle}"`
                  });
                  
                } catch (error) {
                  console.error('Error setting moderator position:', error);
                  setSetPositionDialog(prev => ({ ...prev, isLoading: false }));
                  toastService.error('Failed to set moderator position', {
                    description: 'There was an error setting the moderator position.'
                  });
                }
              }}
              className="flex items-center gap-2"
            >
              {setPositionDialog.isLoading && (
                <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
              )}
              {setPositionDialog.isLoading ? 'Generating detailed image description...' : 'Confirm'}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
      
      {/* Model Settings Dialog */}
      <Dialog open={showModelSettings} onOpenChange={setShowModelSettings}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>AI Model Settings</DialogTitle>
            <DialogDescription>
              Choose which AI model to use for generating responses, discussion guides, and thematic analysis in this focus group.
            </DialogDescription>
          </DialogHeader>
          
          <div className="space-y-4">
            <div className="flex items-center space-x-2">
              <Bot className="h-4 w-4 text-slate-500" />
              <span className="text-sm font-medium">Current Model:</span>
              <Badge variant="secondary">
                {focusGroup?.llm_model === 'gpt-4.1' ? 'GPT-4.1' : 
                 focusGroup?.llm_model === 'gpt-5' ? 'GPT-5' : 'Gemini 3 Pro'}
              </Badge>
            </div>
            
            <div>
              <label className="text-sm font-medium">Select AI Model:</label>
              <Select value={selectedModel} onValueChange={(value) => {
                console.log('🔧 Model selection changed:', { from: selectedModel, to: value });
                setSelectedModel(value);
              }}>
                <SelectTrigger className="mt-1">
                  <SelectValue placeholder="Select AI model" />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="gemini-3-pro-preview">Gemini 3 Pro</SelectItem>
                  <SelectItem value="gpt-4.1">GPT-4.1</SelectItem>
                  <SelectItem value="gpt-5">GPT-5</SelectItem>
                </SelectContent>
              </Select>
            </div>

            {/* GPT-5 specific parameters - only show when GPT-5 is selected */}
            {selectedModel === "gpt-5" && (
              <>
                {/* Reasoning Effort Parameter */}
                <div>
                  <label className="text-sm font-medium">Reasoning Effort:</label>
                  <Select value={selectedReasoningEffort} onValueChange={setSelectedReasoningEffort}>
                    <SelectTrigger className="mt-1">
                      <SelectValue placeholder="Select reasoning effort" />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="minimal">Minimal - Fast responses</SelectItem>
                      <SelectItem value="low">Low - Quick thinking</SelectItem>
                      <SelectItem value="medium">Medium - Balanced (default)</SelectItem>
                      <SelectItem value="high">High - Deep reasoning</SelectItem>
                    </SelectContent>
                  </Select>
                  <p className="text-xs text-slate-600 mt-1">
                    Controls how much time GPT-5 spends thinking before responding
                  </p>
                  <p className="text-xs text-amber-600 font-medium mt-1">
Controls how thoroughly GPT-5 thinks and how detailed responses are
                  </p>
                </div>

                {/* Verbosity Parameter */}
                <div>
                  <label className="text-sm font-medium">Response Verbosity:</label>
                  <Select value={selectedVerbosity} onValueChange={setSelectedVerbosity}>
                    <SelectTrigger className="mt-1">
                      <SelectValue placeholder="Select verbosity level" />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="low">Low - Concise responses</SelectItem>
                      <SelectItem value="medium">Medium - Balanced length (default)</SelectItem>
                      <SelectItem value="high">High - Detailed responses</SelectItem>
                    </SelectContent>
                  </Select>
                  <p className="text-xs text-slate-600 mt-1">
                    Controls how detailed and lengthy GPT-5's responses will be
                  </p>
                  <p className="text-xs text-amber-600 font-medium mt-1">
Controls how thoroughly GPT-5 thinks and how detailed responses are
                  </p>
                </div>
              </>
            )}
            
            <div className="text-xs text-slate-600">
              <p><strong>Gemini 3 Pro:</strong> Google's advanced model, great for creative and analytical tasks.</p>
              <p><strong>GPT-4.1:</strong> OpenAI's latest model, excellent for conversational and reasoning tasks.</p>
              <p><strong>GPT-5:</strong> OpenAI's newest model with advanced reasoning and customizable response styles.</p>
            </div>
          </div>
          
          <DialogFooter>
            <Button 
              variant="outline" 
              onClick={() => setShowModelSettings(false)}
              disabled={isUpdatingModel}
            >
              Cancel
            </Button>
            <Button 
              onClick={() => {
                console.log('🔧 Update button clicked:', { 
                  selectedModel, 
                  selectedReasoningEffort,
                  selectedVerbosity,
                  currentModel: focusGroup?.llm_model,
                  isDisabled: isUpdatingModel || (selectedModel === focusGroup?.llm_model && 
                    (selectedModel !== 'gpt-5' || 
                      (selectedReasoningEffort === focusGroup?.reasoning_effort && 
                       selectedVerbosity === focusGroup?.verbosity)))
                });
                updateFocusGroupModel(selectedModel, selectedReasoningEffort, selectedVerbosity);
              }}
              disabled={isUpdatingModel || (selectedModel === focusGroup?.llm_model && 
                (selectedModel !== 'gpt-5' || 
                  (selectedReasoningEffort === (focusGroup?.reasoning_effort || 'medium') && 
                   selectedVerbosity === (focusGroup?.verbosity || 'medium'))))}
            >
              {isUpdatingModel && (
                <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
              )}
              {isUpdatingModel ? 'Updating...' : 'Update Model'}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
      
      {/* Autonomous Dashboard */}
      <AutonomousDashboard
        focusGroupId={id!}
        personas={participants}
        isVisible={showAutonomousDashboard}
        onToggle={() => setShowAutonomousDashboard(!showAutonomousDashboard)}
      />
      
    </div>
  );
};

export default FocusGroupSession;
