/**
 * HP AI Chatbot
 * 
 * Frontend interface for the HP Marketing Materials Chatbot.
 * This application provides a chat interface to query the HP marketing
 * knowledge base containing HP brand guidelines and supporting documents.
 * 
 * Key features:
 * - Clean chat interface for asking questions about HP marketing materials
 * - Sources and reasoning display for transparency
 * - Brief download functionality to export conversations
 * - Session-based memory for contextual conversations
 * 
 */

import { useState, useRef, useEffect } from 'react';
import { Send, Upload, Loader2, X, FileText, Info, PlusCircle, Trash2, Moon, Sun } from 'lucide-react';
import ThemeToggle from './components/ThemeToggle';
import { fetchWithTimeout } from './lib/utils';
import { Alert, AlertDescription } from "./components/ui/alert";
import * as Tooltip from '@radix-ui/react-tooltip';
import showdown from 'showdown';
import { getCurrentUser, signOut } from './auth';
import { loadUserConversations, loadConversationMessages, createNewConversation, deleteConversation } from './components/ConversationManager';

// Use environment variables for backend URL
// Define backend URL dynamically based on environment
const BACKEND_URL = import.meta.env.VITE_BACKEND_URL || 'https://ai-sandbox.oliver.solutions/hp_back_v2';
console.log('Using backend URL:', BACKEND_URL);

// Function to get authenticated fetch defaults
const getFetchDefaults = () => {
  // Get MSAL username for authentication
  const username = getCurrentUser();
  
  return {
    credentials: 'include',
    headers: {
      'Content-Type': 'application/json',
      'X-MS-USERNAME': username || '', // Add the authenticated username to requests
    }
  };
};

export default function ChatInterface() {
  // Build timestamp to force new hash generation on rebuild - logged only once
  const BUILD_TIMESTAMP = "2025-04-27T" + "FIXED_TIMESTAMP";
  // Only log in development mode and only once during initialization
  if (process.env.NODE_ENV !== 'production') {
    // Using useRef to ensure this only runs once
    const hasLoggedTimestamp = useRef(false);
    useEffect(() => {
      if (!hasLoggedTimestamp.current) {
        console.log('App build timestamp:', BUILD_TIMESTAMP);
        hasLoggedTimestamp.current = true;
      }
    }, []);
  }
  
  const [messages, setMessages] = useState([]);
  const [inputMessage, setInputMessage] = useState('');
  const [isProcessing, setIsProcessing] = useState(false);
  const [isInitialized, setIsInitialized] = useState(false);
  const [error, setError] = useState(null);
  const [isCheckingStatus, setIsCheckingStatus] = useState(true);
  
  // Conversation state
  const [conversations, setConversations] = useState([]);
  const [loadingConversations, setLoadingConversations] = useState(false);
  const [activeConversation, setActiveConversation] = useState(null);
  
  // Sidebar resizing state
  const [sidebarWidth, setSidebarWidth] = useState(320); // Default width in pixels
  const [isResizing, setIsResizing] = useState(false);
  const [autoWidth, setAutoWidth] = useState(true); // Auto-width flag
  const minSidebarWidth = 240;
  const maxSidebarWidth = 480;
  const sidebarRef = useRef(null);
  
  // Initialize Showdown converter for markdown
  const markdownConverter = new showdown.Converter({
    tables: true,
    simplifiedAutoLink: true,
    strikethrough: true,
    tasklists: true,
    emoji: true
  });
  
  const messagesEndRef = useRef(null);

  // Use a ref to track if we've already created a new conversation on this page load
  const hasCreatedConversation = useRef(false);

  const [sessionId, setSessionId] = useState(() => {
    // Check for existing session ID in localStorage
    const existingSessionId = localStorage.getItem('chatSessionId');
    if (existingSessionId) {
      return existingSessionId;
    }
    // Generate new session ID if none exists
    const newSessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    localStorage.setItem('chatSessionId', newSessionId);
    return newSessionId;
  });

  // Load user conversations from the API
  const loadUserConversations = async () => {
    setLoadingConversations(true);
    try {
      const fetchOptions = getFetchDefaults();
      const response = await fetchWithTimeout(`${BACKEND_URL}/conversations`, {
        ...fetchOptions,
        method: 'GET'
      });
      
      if (response.ok) {
        const data = await response.json();
        setConversations(data.conversations || []);
        
        // REMOVED auto-loading of the most recent conversation
        // We want the user to always start with a fresh conversation when refreshing
      } else {
        console.error('Failed to load conversations');
      }
    } catch (error) {
      console.error('Error loading conversations:', error);
    } finally {
      setLoadingConversations(false);
    }
  };
  
  // Load a specific conversation
  const loadConversation = async (conversation) => {
    try {
      setIsProcessing(true);
      setActiveConversation(conversation);
      
      // Set the session ID
      setSessionId(conversation.session_id);
      localStorage.setItem('chatSessionId', conversation.session_id);
      
      // Fetch the messages for this conversation
      const fetchOptions = getFetchDefaults();
      const response = await fetchWithTimeout(`${BACKEND_URL}/conversations/${conversation.id}/messages`, {
        ...fetchOptions,
        method: 'GET'
      });
      
      if (response.ok) {
        const data = await response.json();
        
        // Format the messages for the UI
        const formattedMessages = data.messages.map(msg => ({
          role: msg.role,
          content: msg.content,
          sources: msg.sources || [],
          reasoning: msg.reasoning || [],
          images: msg.images || []
        }));
        
        setMessages(formattedMessages);
        setIsInitialized(true);
        setError(null);
      } else {
        setError('Failed to load conversation messages');
        console.error('Failed to load conversation messages');
      }
    } catch (error) {
      setError('Error loading conversation');
      console.error('Error loading conversation:', error);
    } finally {
      setIsProcessing(false);
    }
  };
  
  // Create a new conversation
  const createNewConversation = async () => {
    try {
      setIsProcessing(true);
      const fetchOptions = getFetchDefaults();
      const response = await fetchWithTimeout(`${BACKEND_URL}/conversations/new`, {
        ...fetchOptions,
        method: 'POST'
      });
      
      if (response.ok) {
        const data = await response.json();
        
        // Set the new session ID
        setSessionId(data.session_id);
        localStorage.setItem('chatSessionId', data.session_id);
        
        // Create a new conversation object
        const newConversation = {
          id: data.conversation_id,
          title: "New conversation",
          created_at: new Date().toISOString(),
          last_updated: new Date().toISOString(),
          session_id: data.session_id
        };
        
        // Update the conversations list
        setConversations(prev => [newConversation, ...prev]);
        
        // Set as active conversation
        setActiveConversation(newConversation);
        
        // Reset messages
        setMessages([{ 
          role: 'assistant', 
          content: 'Welcome to the HP Marketing Materials Chatbot! How can I help you today?' 
        }]);
        
        setIsInitialized(true);
        setError(null);
      } else {
        setError('Failed to create new conversation');
        console.error('Failed to create new conversation');
      }
    } catch (error) {
      setError('Error creating new conversation');
      console.error('Error creating new conversation:', error);
    } finally {
      setIsProcessing(false);
    }
  };

  // Function to handle loading a conversation
  const handleLoadConversation = async (conversation) => {
    setActiveConversation(conversation);
    await loadConversationMessages(
      conversation, 
      getCurrentUser(), 
      setMessages, 
      setSessionId, 
      setError
    );
  };
  
  // Function to handle creating a new conversation
  const handleCreateNewConversation = async () => {
    await createNewConversation(
      getCurrentUser(),
      setConversations,
      setActiveConversation,
      setSessionId,
      setMessages,
      setError
    );
  };
  
  // Function to update conversations list (including titles) after a message is sent
  const updateConversationsList = async () => {
    if (activeConversation) {
      try {
        console.log('Updating conversations list...');
        // Get updated conversations from the server
        const fetchOptions = getFetchDefaults();
        const response = await fetchWithTimeout(`${BACKEND_URL}/conversations`, {
          ...fetchOptions,
          method: 'GET'
        });
        
        if (response.ok) {
          const data = await response.json();
          const updatedConversations = data.conversations || [];
          
          // Update the conversations list
          setConversations(updatedConversations);
          
          // Find and update the active conversation with any title changes
          const updatedActiveConversation = updatedConversations.find(
            convo => convo.id === activeConversation.id
          );
          
          if (updatedActiveConversation) {
            // Always update the active conversation to get the latest data
            // This ensures titles get updated after messages are sent
            setActiveConversation(updatedActiveConversation);
            console.log('Updated active conversation:', 
              'ID:', updatedActiveConversation.id, 
              'Title:', updatedActiveConversation.title
            );
          } else {
            console.warn('Active conversation not found in updated list');
          }
        } else {
          console.error('Failed to update conversations list');
        }
      } catch (err) {
        console.error('Error updating conversations list:', err);
        // Continue with existing data on error
      }
    } else {
      console.warn('No active conversation to update');
    }
  };
  
  // Separate useEffect that only runs once on component mount
  useEffect(() => {
    // Flag to prevent multiple conversation creations
    hasCreatedConversation.current = false;
    
    // Check the status of the chat system when the component mounts
    const checkStatus = async () => {
      setIsCheckingStatus(true);
      try {
        // Check if the chat system is initialized
        const fetchOptions = getFetchDefaults();
        const response = await fetchWithTimeout(`${BACKEND_URL}/status?sessionId=${sessionId}`, {
          ...fetchOptions,
          method: 'GET'
        });
        
        if (response.ok) {
          const data = await response.json();
          // Check for either the new property 'global_status' or the old 'initialized' property
          // Enhanced logging for the status response
          console.log('Status check raw response:', JSON.stringify(data));
          
          // Explicitly check each property with detailed logging
          const hasGlobalStatus = 'global_status' in data;
          const globalStatusValue = hasGlobalStatus ? data.global_status : 'missing';
          const globalStatusMatch = globalStatusValue === 'initialized';
          
          const hasInitialized = 'initialized' in data;
          const initializedValue = hasInitialized ? data.initialized : false;
          
          console.log('Status check property analysis:', {
            hasGlobalStatus,
            globalStatusValue,
            globalStatusMatch,
            hasInitialized,
            initializedValue
          });
          
          // Try also checking 'is_initialized' as another possible property name
          const hasIsInitialized = 'is_initialized' in data;
          const isInitializedValue = hasIsInitialized ? data.is_initialized : false;
          
          // Check session-specific initialization if available
          const hasSessionInitialized = 'session_initialized' in data;
          const sessionInitialized = hasSessionInitialized ? data.session_initialized : true; // Default to true if not present
          const sessionStatus = data.session_status || 'unknown';
          
          // OVERRIDE: ALWAYS force initialization to true 
          // This completely bypasses all property checks and status endpoint validation
          // Complementing the backend change which now always returns initialized=true
          const systemInitialized = true;
          
          // Log final decision with full context
          console.log('Final initialization decision:', {
            systemInitialized,
            globalStatusMatch,
            initializedValue,
            isInitializedValue,
            hasSessionInitialized,
            sessionInitialized,
            sessionStatus,
            fullData: data
          });
          
          setIsInitialized(systemInitialized);
          
          if (systemInitialized) {
            // First, load conversations list for the sidebar without auto-selecting any
            await loadUserConversations();
            
            // Only create a new conversation if we haven't already
            if (!hasCreatedConversation.current) {
              logToConsole('info', 'App mounted, creating a new conversation', { sessionId });
              
              // Set the flag to prevent creating multiple conversations
              hasCreatedConversation.current = true;
              
              setIsProcessing(true);
              try {
                const fetchOptions = getFetchDefaults();
                const response = await fetch(`${BACKEND_URL}/conversations/new`, {
                  ...fetchOptions,
                  method: 'POST'
                });
                
                if (response.ok) {
                  const data = await response.json();
                  
                  // Set the new session ID
                  setSessionId(data.session_id);
                  localStorage.setItem('chatSessionId', data.session_id);
                  
                  // Create a new conversation object
                  const newConversation = {
                    id: data.conversation_id,
                    title: "New conversation",
                    created_at: new Date().toISOString(),
                    last_updated: new Date().toISOString(),
                    session_id: data.session_id
                  };
                  
                  // Update the conversations list
                  setConversations(prev => [newConversation, ...prev]);
                  
                  // Set as active conversation
                  setActiveConversation(newConversation);
                  
                  // Reset messages
                  setMessages([{ 
                    role: 'assistant', 
                    content: 'Welcome to the HP Marketing Materials Chatbot! How can I help you today?' 
                  }]);
                } else {
                  console.error('Failed to create new conversation');
                }
              } catch (error) {
                console.error('Error creating new conversation on page load:', error);
              } finally {
                setIsProcessing(false);
              }
            }
            
            setError(null);
            logToConsole('info', 'Chat system is ready', { sessionId });
          } else {
            // System is not initialized
            setError('The chat system is not yet initialized. Please try again later.');
            logToConsole('error', 'Chat system not initialized', { sessionId });
          }
        } else {
          console.error('Failed to check system status');
          setError('Failed to connect to the chat system. Please try again later.');
        }
      } catch (error) {
        console.error('Error checking system status:', error);
        setError('Failed to connect to the chat system. Please try again later.');
      } finally {
        setIsCheckingStatus(false);
      }
    };
    
    checkStatus();
    
    // Empty dependency array to ensure this only runs once when the component mounts
  }, []);

  const logToConsole = (type, message, data = null) => {
    const timestamp = new Date().toISOString();
    const logMessage = {
      timestamp,
      type,
      message,
      data
    };
    console.log(JSON.stringify(logMessage, null, 2));
  };

  const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
  };

  useEffect(() => {
    scrollToBottom();
  }, [messages]);
  
  // Update the page title when active conversation changes or is updated
  useEffect(() => {
    if (activeConversation?.title) {
      document.title = `${activeConversation.title} | HP Marketing Bot`;
    } else {
      document.title = 'HP Marketing Materials Chatbot';
    }
  }, [activeConversation?.title]);
  
  // Sidebar resize handlers
  const startResizing = (e) => {
    setIsResizing(true);
    e.preventDefault();
  };
  
  const stopResizing = () => {
    setIsResizing(false);
    document.body.style.cursor = 'default';
  };
  
  const resize = (e) => {
    if (isResizing) {
      document.body.style.cursor = 'ew-resize';
      const newWidth = e.clientX;
      if (newWidth >= minSidebarWidth && newWidth <= maxSidebarWidth) {
        setSidebarWidth(newWidth);
      }
    }
  };
  
  // Auto-resize sidebar based on conversation titles
  useEffect(() => {
    // Function to calculate the sidebar width based on conversation titles
    const calculateSidebarWidth = () => {
      if (!autoWidth || !conversations.length) return;
      
      // Create a temporary div to measure text width
      const measureDiv = document.createElement('div');
      measureDiv.style.position = 'absolute';
      measureDiv.style.visibility = 'hidden';
      measureDiv.style.whiteSpace = 'nowrap';
      measureDiv.style.fontFamily = 'inherit';
      measureDiv.style.fontSize = '0.875rem'; // text-sm
      measureDiv.style.fontWeight = '500'; // font-medium
      
      // Add to DOM for measurement
      document.body.appendChild(measureDiv);
      
      // Find longest title
      let maxWidth = 0;
      conversations.forEach(convo => {
        measureDiv.textContent = convo.title || "New conversation";
        const width = measureDiv.offsetWidth;
        maxWidth = Math.max(maxWidth, width);
      });
      
      // Remove measurement div
      document.body.removeChild(measureDiv);
      
      // Calculate sidebar width (add padding for buttons, icons, etc.)
      // We add extra padding for the delete button and some margin
      const calculatedWidth = Math.max(minSidebarWidth, Math.min(maxWidth + 100, maxSidebarWidth));
      
      // Update width if it's significantly different
      if (Math.abs(calculatedWidth - sidebarWidth) > 10) {
        setSidebarWidth(calculatedWidth);
      }
    };
    
    // Call the calculation function
    calculateSidebarWidth();
    
    // Add an event listener for window resize to recalculate if needed
    if (autoWidth) {
      window.addEventListener('resize', calculateSidebarWidth);
      return () => window.removeEventListener('resize', calculateSidebarWidth);
    }
  }, [conversations, autoWidth, minSidebarWidth, maxSidebarWidth, sidebarWidth]);

  // Add event listeners for manual resize
  useEffect(() => {
    const handleResize = (e) => {
      if (isResizing) {
        document.body.style.cursor = 'ew-resize';
        const newWidth = e.clientX;
        
        if (newWidth >= minSidebarWidth && newWidth <= maxSidebarWidth) {
          setSidebarWidth(newWidth);
          // When user manually resizes, disable auto width
          setAutoWidth(false);
        }
      }
    };
    
    const handleStopResizing = () => {
      setIsResizing(false);
      document.body.style.cursor = 'default';
    };
    
    window.addEventListener('mousemove', handleResize);
    window.addEventListener('mouseup', handleStopResizing);
    
    return () => {
      window.removeEventListener('mousemove', handleResize);
      window.removeEventListener('mouseup', handleStopResizing);
    };
  }, [isResizing, minSidebarWidth, maxSidebarWidth]);

  const handleFilesChange = (e, type) => {
    const files = Array.from(e.target.files);
    logToConsole('info', `Handling ${type} files change`, {
      fileCount: files.length,
      fileDetails: files.map(f => ({
        name: f.name,
        type: f.type,
        size: f.size
      }))
    });

    if (type === 'brief') {
      setBriefFiles(prev => [...prev, ...files]);
    } else {
      setSupportingFiles(prev => [...prev, ...files]);
    }
  };

  const removeFile = (fileName, type) => {
    logToConsole('info', `Removing file`, {
      fileName,
      type
    });

    if (type === 'brief') {
      setBriefFiles(prev => prev.filter(file => file.name !== fileName));
    } else {
      setSupportingFiles(prev => prev.filter(file => file.name !== fileName));
    }
  };
  
  const resetChat = async () => {
    try {
      setIsProcessing(true);
      logToConsole('info', 'Resetting chat session', { sessionId });
      const fetchOptions = getFetchDefaults();
      const response = await fetchWithTimeout(`${BACKEND_URL}/reset`, {
        ...fetchOptions,
        method: 'POST',
        body: JSON.stringify({ sessionId })
      });
      
      if (response.ok) {
        // Reset the UI state
        setMessages([{ 
          role: 'assistant', 
          content: 'Chat session has been reset. How can I help you today?' 
        }]);
        setError(null);
        setInputMessage('');
        
        logToConsole('info', 'Chat session reset successfully');
      } else {
        const errorData = await response.json();
        setError(errorData.error || 'Failed to reset chat');
      }
    } catch (error) {
      console.error('Error resetting chat:', error);
      setError('Failed to reset chat. Please try again.');
    } finally {
      setIsProcessing(false);
    }
  };


  const ImageViewer = ({ image, isOpen, onClose, allImages }) => {
    if (!isOpen) return null;
    
    // Find the index of the current image in the allImages array
    const currentImageIndex = allImages.findIndex(img => {
      const imgFilename = typeof img === 'string' ? img : img.filename;
      const selectedFilename = typeof image === 'string' ? image : image.filename;
      return imgFilename === selectedFilename;
    });
    
    const [activeIndex, setActiveIndex] = useState(currentImageIndex >= 0 ? currentImageIndex : 0);
    
    // Handle both string and object formats for backward compatibility
    const currentImage = allImages[activeIndex];
    const filename = typeof currentImage === 'string' ? currentImage : currentImage.filename;
    const metadata = typeof currentImage === 'string' ? null : currentImage;
    
    const goToPrevious = (e) => {
      e.stopPropagation();
      setActiveIndex((prevIndex) => (prevIndex > 0 ? prevIndex - 1 : allImages.length - 1));
    };
    
    const goToNext = (e) => {
      e.stopPropagation();
      setActiveIndex((prevIndex) => (prevIndex < allImages.length - 1 ? prevIndex + 1 : 0));
    };
    
    return (
      <div 
        className="fixed inset-0 bg-black/80 flex items-center justify-center z-50"
        onClick={onClose}
      >
        <div className="relative max-w-[90%] max-h-[90%] flex items-center">
          {allImages.length > 1 && (
            <button 
              onClick={goToPrevious}
              className="absolute left-[-50px] bg-white/20 hover:bg-white/40 rounded-full p-2 z-10"
              aria-label="Previous image"
            >
              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="text-white">
                <polyline points="15 18 9 12 15 6"></polyline>
              </svg>
            </button>
          )}
          
          <div className="relative">
            <img 
              src={`${BACKEND_URL}/images/${filename}`} 
              alt={metadata ? `${metadata.document} (page ${metadata.page})` : "Document screenshot"} 
              className="max-w-full max-h-[90vh] object-contain"
            />
            {metadata && (
              <div className="absolute bottom-0 left-0 right-0 bg-black/60 text-white p-2 text-sm">
                <div className="font-bold">{metadata.document}</div>
                <div>Page {metadata.page} {allImages.length > 1 ? `(${activeIndex + 1}/${allImages.length})` : ''}</div>
              </div>
            )}
          </div>
          
          {allImages.length > 1 && (
            <button 
              onClick={goToNext}
              className="absolute right-[-50px] bg-white/20 hover:bg-white/40 rounded-full p-2 z-10"
              aria-label="Next image"
            >
              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="text-white">
                <polyline points="9 18 15 12 9 6"></polyline>
              </svg>
            </button>
          )}
          
          <button 
            onClick={onClose}
            className="absolute top-2 right-2 bg-white/20 hover:bg-white/40 rounded-full p-1"
          >
            <X size={24} />
          </button>
        </div>
      </div>
    );
  };

  const MessageBubble = ({ message }) => {
    const [selectedImage, setSelectedImage] = useState(null);
    
    const formatSources = (sources) => {
      if (!sources || !Array.isArray(sources)) return [];
      
      return sources.map((source) => {
        if (source && typeof source === 'object') {
          if (source.content) {
            return {
              text: typeof source.content === 'string' 
                ? source.content 
                : JSON.stringify(source.content),
              tool: source.tool_name || ''
            };
          }
          return {
            text: JSON.stringify(source),
            tool: ''
          };
        }
        return {
          text: String(source),
          tool: ''
        };
      }).filter(source => source.text);
    };
  
    const formatReasoning = (reasoning) => {
      if (!reasoning || !Array.isArray(reasoning)) return [];
      
      return reasoning.map((step, index) => {
        const stepType = step.type || 'thought';
        let content = '';
        
        if (step.action) {
          content = `${step.action}${step.action_input ? `: ${step.action_input}` : ''}`;
        } else if (step.observation) {
          content = step.observation;
        } else if (step.response) {
          content = step.response;
        } else if (step.thought) {
          content = step.thought;
        }
  
        return {
          id: index,
          type: stepType,
          content: content,
          thought: step.thought
        };
      }).filter(step => step.content);
    };
  
    const sources = formatSources(message.sources);
    const reasoningSteps = formatReasoning(message.reasoning);
    const images = message.images || [];
    
    // Handle image click - open full-size viewer
    const openImage = (image) => {
      setSelectedImage(image);
    };
    
    // Close image viewer
    const closeImage = () => {
      setSelectedImage(null);
    };
    
    // Handle escape key to close image
    useEffect(() => {
      const handleEscKey = (e) => {
        if (e.key === 'Escape' && selectedImage) {
          closeImage();
        }
      };
      
      window.addEventListener('keydown', handleEscKey);
      return () => window.removeEventListener('keydown', handleEscKey);
    }, [selectedImage]);
  
    return (
      <div className={`flex ${message.role === 'user' ? 'justify-end' : 'justify-start'} mb-4`}>
        <div className={`max-w-[80%] rounded-lg p-3 ${
          message.role === 'user' ? 'bg-blue-500 text-white' : 'bg-gray-100 dark:bg-gray-700 dark:text-white'
        }`}>
          <div 
            className="mb-2 markdown-content" 
            dangerouslySetInnerHTML={{ 
              __html: message.role === 'assistant' 
                ? markdownConverter.makeHtml(message.content) 
                : message.content 
            }}
          />
          
          {/* Display image thumbnails if available */}
          {images.length > 0 && (
            <div className="mt-3 mb-2">
              <div className="text-xs font-medium mb-1 text-gray-600 dark:text-gray-300">Relevant Document Screenshots:</div>
              <div className="flex flex-wrap gap-2">
                {images.map((image, idx) => {
                  // Handle both string and object formats for backward compatibility
                  const filename = typeof image === 'string' ? image : image.filename;
                  const metadata = typeof image === 'string' ? null : image;
                  
                  return (
                    <div 
                      key={idx} 
                      className="relative cursor-pointer border border-gray-300 rounded overflow-hidden"
                      onClick={() => openImage(image)}
                    >
                      <img 
                        src={`${BACKEND_URL}/images/${filename}`} 
                        alt={metadata ? `${metadata.document} (page ${metadata.page})` : `Document screenshot ${idx+1}`}
                        className="w-20 h-20 object-cover" 
                      />
                      {metadata && (
                        <div className="absolute bottom-0 left-0 right-0 bg-black/70 text-white text-xs p-1 truncate">
                          pg. {metadata.page}
                        </div>
                      )}
                    </div>
                  );
                })}
              </div>
            </div>
          )}
          
          <div className="flex gap-2 mt-2">
            {sources.length > 0 && (
              <Tooltip.Provider delayDuration={200}>
                <Tooltip.Root>
                  <Tooltip.Trigger asChild>
                    <button 
                      className={`flex items-center gap-1 text-xs rounded px-2 py-1 ${
                        message.role === 'user' 
                          ? 'bg-white/10 hover:bg-white/20' 
                          : 'bg-gray-200 hover:bg-gray-300 dark:bg-gray-600 dark:hover:bg-gray-500 dark:text-white'
                      }`}
                    >
                      <Info size={12} />
                      <span>Sources ({sources.length})</span>
                    </button>
                  </Tooltip.Trigger>
                  <Tooltip.Portal>
                    <Tooltip.Content 
                      className="bg-white dark:bg-gray-800 p-4 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 max-w-md z-50"
                      sideOffset={5}
                    >
                      <div className="max-h-[300px] overflow-y-auto">
                        <h4 className="font-semibold mb-2 text-gray-900 dark:text-white">Sources Used:</h4>
                        <ul className="space-y-3">
                          {sources.map((source, idx) => (
                            <li key={idx} className="text-sm">
                              {source.tool && (
                                <div className="text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">
                                  Tool: {source.tool}
                                </div>
                              )}
                              <div className="text-gray-700 dark:text-gray-300">{source.text}</div>
                            </li>
                          ))}
                        </ul>
                      </div>
                      <Tooltip.Arrow className="fill-white dark:fill-gray-800" />
                    </Tooltip.Content>
                  </Tooltip.Portal>
                </Tooltip.Root>
              </Tooltip.Provider>
            )}
  
            {reasoningSteps.length > 0 && (
              <Tooltip.Provider delayDuration={200}>
                <Tooltip.Root>
                  <Tooltip.Trigger asChild>
                    <button 
                      className={`flex items-center gap-1 text-xs rounded px-2 py-1 ${
                        message.role === 'user' 
                          ? 'bg-white/10 hover:bg-white/20' 
                          : 'bg-gray-200 hover:bg-gray-300 dark:bg-gray-600 dark:hover:bg-gray-500 dark:text-white'
                      }`}
                    >
                      <Info size={12} />
                      <span>Reasoning ({reasoningSteps.length})</span>
                    </button>
                  </Tooltip.Trigger>
                  <Tooltip.Portal>
                    <Tooltip.Content 
                      className="bg-white dark:bg-gray-800 p-4 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 max-w-md z-50"
                      sideOffset={5}
                    >
                      <div className="max-h-[300px] overflow-y-auto">
                        <h4 className="font-semibold mb-2 text-gray-900 dark:text-white">Reasoning Steps:</h4>
                        <ul className="space-y-3">
                          {reasoningSteps.map((step) => (
                            <li key={step.id} className="text-sm">
                              <div className="font-medium text-gray-900 dark:text-white capitalize">
                                {step.type}:
                              </div>
                              <div className="text-gray-700 dark:text-gray-300 ml-2">{step.content}</div>
                              {step.thought && step.thought !== step.content && (
                                <div className="text-gray-500 dark:text-gray-400 ml-2 mt-1 text-xs">
                                  Thought: {step.thought}
                                </div>
                              )}
                            </li>
                          ))}
                        </ul>
                      </div>
                      <Tooltip.Arrow className="fill-white dark:fill-gray-800" />
                    </Tooltip.Content>
                  </Tooltip.Portal>
                </Tooltip.Root>
              </Tooltip.Provider>
            )}
          </div>
        </div>
        
        {/* Image viewer modal */}
        <ImageViewer 
          image={selectedImage} 
          isOpen={Boolean(selectedImage)} 
          onClose={closeImage}
          allImages={images || []}
        />
      </div>
    );
  };

  const handleSubmit = async () => {
    if (!inputMessage.trim() || isProcessing) return;
  
    const currentMessage = inputMessage;
    setMessages(prev => [...prev, { role: 'user', content: currentMessage }]);
    setInputMessage('');
    setIsProcessing(true);
    
    // ENHANCED DEBUGGING: Log the current state of sessionId and related variables
    console.log('SUBMIT DEBUG DATA:', {
      sessionId,
      sessionIdType: typeof sessionId,
      sessionIdLength: sessionId ? sessionId.length : 0,
      hasActiveConversation: !!activeConversation,
      activeConversationId: activeConversation ? activeConversation.id : null,
      activeConversationSessionId: activeConversation ? activeConversation.session_id : null,
      localStorageSessionId: localStorage.getItem('chatSessionId')
    });
    
    // Check if this is a blank chat with no active conversation - create one if needed
    if (!activeConversation) {
      logToConsole('info', 'No active conversation found when submitting message, creating a new one', { sessionId });
      try {
        await handleCreateNewConversation();
      } catch (err) {
        console.error('Error creating new conversation before sending message:', err);
        // Continue with the chat request anyway, as the backend might handle this
      }
    }
    
    // ENHANCEMENT: Try to ensure we have a valid sessionId
    const effectiveSessionId = sessionId || 
                               (activeConversation ? activeConversation.session_id : null) || 
                               localStorage.getItem('chatSessionId');
    
    if (!effectiveSessionId) {
      console.error('No valid sessionId found from any source');
      setError('Session ID is missing. Please refresh the page.');
      setIsProcessing(false);
      return;
    }
  
    try {
      // Log the sessionId to help debug
      console.log('Sending chat request with sessionId:', effectiveSessionId);
      
      const fetchOptions = getFetchDefaults();
      const response = await fetchWithTimeout(`${BACKEND_URL}/chat`, {
        ...fetchOptions,
        method: 'POST',
        body: JSON.stringify({ 
          message: currentMessage,
          sessionId: effectiveSessionId 
        })
      });
  
      if (!response.ok) {
        const errorData = await response.json();
        // If the server says chat is not initialized, reset UI to show upload screen
        if (errorData.error === 'Chat system not initialized') {
          setIsInitialized(false);
          throw new Error('Chat system not initialized. Please upload files first.');
        }
        throw new Error(errorData.error || 'Failed to get response');
      }
  
      const responseData = await response.json();
  
      let assistantMessage;
      if (responseData.status === 'success' && responseData.data) {
        assistantMessage = {
          role: 'assistant',
          content: responseData.data.response || '',
          sources: responseData.data.sources || [],
          reasoning: responseData.data.reasoning || [],
          images: responseData.data.images || []
        };
      } else if (responseData.result) {
        assistantMessage = {
          role: 'assistant',
          content: responseData.result.response || '',
          sources: responseData.result.sources || [],
          reasoning: responseData.result.reasoning || [],
          images: responseData.result.images || []
        };
      } else {
        assistantMessage = {
          role: 'assistant',
          content: responseData.response || '',
          sources: responseData.sources || [],
          reasoning: responseData.reasoning || [],
          images: responseData.images || []
        };
      }
  
      console.log('Processed assistant message:', assistantMessage);
      setMessages(prev => [...prev, assistantMessage]);
      setError(null);
      
      // Update the conversations list to get the AI-generated title
      // Add a longer delay to allow backend to generate title using OpenAI
      setTimeout(() => {
        // Need a longer delay for OpenAI to generate the title
        updateConversationsList();
        
        // Check again after a bit longer in case the first attempt was too soon
        setTimeout(() => {
          updateConversationsList();
        }, 3000); // Check again after 3 more seconds
      }, 2000); // Initial 2 second delay
  
    } catch (e) {
      console.error('Error in chat:', e);
      setError('Failed to process response. Please try again.');
    } finally {
      setIsProcessing(false);
    }
  };

// Helper function to slice file into chunks and upload them
const uploadFileInChunks = async (file, fileType, sessionId, controller) => {
  const chunkSize = 1024 * 1024; // 1MB chunks
  const totalChunks = Math.ceil(file.size / chunkSize);
  
  // Step 1: Initialize the chunked upload
  const fetchOptions = getFetchDefaults();
  const initResponse = await fetch(`${BACKEND_URL}/init-chunked-upload`, {
    method: 'POST',
    headers: { 
      ...fetchOptions.headers,
      'Content-Type': 'application/json' 
    },
    signal: controller.signal,
    body: JSON.stringify({
      fileName: file.name,
      fileType: fileType, // 'brief' or 'supporting'
      fileSize: file.size,
      mimeType: file.type,
      totalChunks,
      sessionId
    })
  });
  
  if (!initResponse.ok) {
    const error = await initResponse.json();
    throw new Error(error.message || 'Failed to initialize chunked upload');
  }
  
  const { uploadId } = await initResponse.json();
  
  // Step 2: Upload each chunk
  for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
    const start = chunkIndex * chunkSize;
    const end = Math.min(start + chunkSize, file.size);
    const chunk = file.slice(start, end);
    
    const chunkFormData = new FormData();
    chunkFormData.append('chunk', chunk);
    chunkFormData.append('uploadId', uploadId);
    chunkFormData.append('chunkIndex', chunkIndex);
    
    const fetchOptions = getFetchDefaults();
    const chunkResponse = await fetch(`${BACKEND_URL}/upload-chunk`, {
      method: 'POST',
      body: chunkFormData,
      signal: controller.signal,
      headers: {
        ...fetchOptions.headers,
        'X-Requested-With': 'XMLHttpRequest'
      }
    });
    
    if (!chunkResponse.ok) {
      throw new Error(`Failed to upload chunk ${chunkIndex}`);
    }
  }
  
  // Step 3: Finalize the upload
  const finalizeOptions = getFetchDefaults();
  const finalizeResponse = await fetch(`${BACKEND_URL}/finalize-upload`, {
    method: 'POST',
    headers: { 
      ...finalizeOptions.headers,
      'Content-Type': 'application/json' 
    },
    signal: controller.signal,
    body: JSON.stringify({ uploadId })
  });
  
  if (!finalizeResponse.ok) {
    throw new Error('Failed to finalize upload');
  }
  
  return { fileName: file.name, uploadId };
};

// Main function to initialize chat
const initializeChat = async () => {
  if (briefFiles.length === 0) {
    setError('Please upload at least one brief file.');
    return;
  }

  logToConsole('info', 'Starting chat initialization', {
    briefFilesCount: briefFiles.length,
    supportingFilesCount: supportingFiles.length
  });

  setIsProcessing(true);
  
  // Create an AbortController for proper timeout handling
  const controller = new AbortController();
  const timeoutId = setTimeout(() => {
    controller.abort();
    logToConsole('error', 'Request timed out after 10 minutes');
  }, 600000); // 10 minute timeout

  try {
    // Check for large files that might need chunked upload
    const largeFiles = [...briefFiles, ...supportingFiles].filter(file => file.size > 1024 * 1024);
    if (largeFiles.length > 0) {
      logToConsole('info', 'Large files detected, using chunked upload approach', {
        largeFiles: largeFiles.map(f => ({ name: f.name, size: f.size }))
      });
    }

    // Upload all brief files
    const briefUploads = [];
    for (const file of briefFiles) {
      if (file.size > 1024 * 1024) { // If file is larger than 1MB, use chunked upload
        const result = await uploadFileInChunks(file, 'brief', sessionId, controller);
        briefUploads.push(result);
      } else {
        // For small files, use regular upload
        const smallFormData = new FormData();
        smallFormData.append('file', file);
        smallFormData.append('fileType', 'brief');
        smallFormData.append('sessionId', sessionId);
        
        const fetchOptions = getFetchDefaults();
        const response = await fetch(`${BACKEND_URL}/upload-small-file`, {
          method: 'POST',
          body: smallFormData,
          signal: controller.signal,
          headers: {
            ...fetchOptions.headers,
            'X-Requested-With': 'XMLHttpRequest'
          }
        });
        
        if (!response.ok) {
          throw new Error(`Failed to upload small file: ${file.name}`);
        }
        
        const result = await response.json();
        briefUploads.push(result);
      }
    }
    
    // Upload all supporting files (similar approach)
    const supportingUploads = [];
    for (const file of supportingFiles) {
      if (file.size > 1024 * 1024) {
        const result = await uploadFileInChunks(file, 'supporting', sessionId, controller);
        supportingUploads.push(result);
      } else {
        // Small file upload code similar to brief files
        const smallFormData = new FormData();
        smallFormData.append('file', file);
        smallFormData.append('fileType', 'supporting');
        smallFormData.append('sessionId', sessionId);
        
        const fetchOptions = getFetchDefaults();
        const response = await fetch(`${BACKEND_URL}/upload-small-file`, {
          method: 'POST',
          body: smallFormData,
          signal: controller.signal,
          headers: {
            ...fetchOptions.headers,
            'X-Requested-With': 'XMLHttpRequest'
          }
        });
        
        if (!response.ok) {
          throw new Error(`Failed to upload small file: ${file.name}`);
        }
        
        const result = await response.json();
        supportingUploads.push(result);
      }
    }
    
    // Now that all files are uploaded, initialize the chat
    const finalizeData = {
      sessionId,
      briefFiles: briefUploads,
      supportingFiles: supportingUploads
    };
    
    const finalizeOptions = getFetchDefaults();
    const finalizeResponse = await fetch(`${BACKEND_URL}/initialize-from-uploads`, {
      method: 'POST',
      headers: { 
        ...finalizeOptions.headers,
        'Content-Type': 'application/json',
        'X-Requested-With': 'XMLHttpRequest'
      },
      body: JSON.stringify(finalizeData),
      signal: controller.signal
    });
    
    // Clear the timeout
    clearTimeout(timeoutId);
    
    if (!finalizeResponse.ok) {
      const errorData = await finalizeResponse.json();
      throw new Error(errorData.error || `Server responded with ${finalizeResponse.status}`);
    }
    
    const data = await finalizeResponse.json();
    
    logToConsole('info', 'Chat initialization successful');
    setIsInitialized(true);
    setMessages([{ 
      role: 'assistant', 
      content: 'Chat initialized! How can I help you?' 
    }]);
    setError(null);
    
  } catch (err) {
    // Clear the timeout if there's an error
    clearTimeout(timeoutId);
    
    // Enhanced error logging
    const errorDetails = {
      message: err.message,
      name: err.name,
      stack: err.stack,
      isAbortError: err.name === 'AbortError'
    };
    
    logToConsole('error', 'Initialization error', errorDetails);
    console.error('Initialization error:', err);
    
    // Set appropriate error message for user
    if (err.name === 'AbortError') {
      setError('Request timed out. The file(s) may be too large.');
    } else {
      setError(err.message || 'Failed to initialize chat');
    }
    
    setIsInitialized(false);
  } finally {
    setIsProcessing(false);
  }
};

  return (
    <Tooltip.Provider style={{ border: 'none' }}>
      <div className="flex min-h-screen w-full bg-black no-borders">
        {/* Conversation Sidebar - Fixed to left side */}
        <div 
          ref={sidebarRef}
          className="bg-gray-200 dark:bg-gray-800 shadow-lg flex flex-col h-full fixed left-0 top-0 bottom-0 z-10" 
          style={{ width: sidebarWidth }}>
          <div className="p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between bg-white dark:bg-gray-900">
            <h2 className="font-bold text-lg dark:text-white">Conversations</h2>
            <button 
              onClick={handleCreateNewConversation}
              className="p-2 bg-blue-500 text-white rounded-full hover:bg-blue-600"
              title="New Conversation"
            >
              <PlusCircle size={16} />
            </button>
          </div>
          
          <div className="flex-1 overflow-y-auto p-2">
            {loadingConversations ? (
              <div className="flex justify-center py-4">
                <Loader2 className="animate-spin dark:text-white" size={24} />
              </div>
            ) : conversations.length > 0 ? (
              conversations.map(convo => (
                <div 
                  key={convo.id}
                  className={`px-3 py-2 mb-2 rounded hover:bg-gray-100 dark:hover:bg-gray-700 ${
                    activeConversation && activeConversation.id === convo.id 
                      ? 'bg-gray-200 hover:bg-gray-200 dark:bg-gray-700 dark:hover:bg-gray-700' 
                      : ''
                  }`}
                >
                  <div className="flex items-center justify-between">
                    <div 
                      className="flex-1 cursor-pointer pr-2"
                      onClick={() => handleLoadConversation(convo)}
                    >
                      <div className="font-medium truncate text-sm dark:text-white">{convo.title || "New conversation"}</div>
                      <div className="text-xs text-gray-500 dark:text-gray-400">
                        {new Date(convo.last_updated).toLocaleDateString()}
                      </div>
                    </div>
                    <button
                      onClick={(e) => {
                        e.stopPropagation();
                        // Ask for confirmation before deleting
                        if (window.confirm(`Are you sure you want to delete "${convo.title || "this conversation"}"?`)) {
                          deleteConversation(
                            convo.id,
                            getCurrentUser(),
                            setConversations,
                            setError
                          );
                        }
                      }}
                      className="flex-shrink-0 p-1.5 text-gray-500 hover:text-red-500 hover:bg-gray-200 dark:hover:bg-gray-700 rounded-full dark:text-gray-400 dark:hover:text-red-400"
                      title="Delete conversation"
                    >
                      <Trash2 size={16} />
                    </button>
                  </div>
                </div>
              ))
            ) : (
              <div className="text-center py-4 text-gray-500 dark:text-gray-400">
                No conversations yet
              </div>
            )}
          </div>
          
          <div className="p-3 border-t border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900">
            <div className="flex flex-col gap-2">
              <div className="flex items-center justify-between">
                <span className="text-sm text-gray-600 dark:text-gray-300">{getCurrentUser()}</span>
                <button 
                  onClick={signOut}
                  className="px-2 py-1 bg-gray-200 text-gray-800 dark:bg-gray-700 dark:text-gray-200 rounded hover:bg-gray-300 dark:hover:bg-gray-600 text-xs"
                >
                  Sign Out
                </button>
              </div>
              
              {!autoWidth && (
                <button 
                  onClick={() => {
                    setAutoWidth(true);
                  }}
                  className="text-xs text-center w-full px-2 py-1 mt-2 bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-200 rounded hover:bg-gray-200 dark:hover:bg-gray-600"
                  title="Reset sidebar to auto-adjust width"
                >
                  Auto-adjust width
                </button>
              )}
            </div>
          </div>
        </div>
        
        {/* Resize handle */}
        <div 
          className="w-1 hover:w-2 bg-gray-400 hover:bg-blue-500 cursor-ew-resize fixed top-0 bottom-0 z-20 transition-all duration-150"
          style={{ left: `${sidebarWidth}px` }}
          onMouseDown={startResizing}
        ></div>
        
        {/* Header with HP branding - completely rebuilt without any borders */}
        <div 
          className="fixed top-0 w-full bg-black py-6 z-30 flex flex-col items-center justify-center no-borders" 
          style={{ 
            marginLeft: `${sidebarWidth}px`, 
            width: `calc(100% - ${sidebarWidth}px)`,
            boxShadow: 'none'
          }}
        >
          {/* Theme toggle in top right corner */}
          <div style={{ position: 'absolute', top: '1rem', right: '1rem' }}>
            <ThemeToggle />
          </div>
          {/* HP Logo */}
          <div className="h-14 mb-2 no-borders flex items-center justify-center text-white font-bold text-4xl">
            HP
          </div>
          <h1 className="text-white font-bold text-2xl tracking-widest mt-1 uppercase no-borders">Marketing Bot</h1>
        </div>
        
        {/* Main Chat Area - Centered with left margin to account for sidebar */}
        <div className="flex-1 pt-36 pb-8 px-4 no-borders" style={{ marginLeft: `${sidebarWidth}px` }}>
          <div className="max-w-4xl w-full mx-auto bg-white dark:bg-gray-800 rounded-lg shadow-xl flex flex-col no-borders">
            <div className="flex-1 flex flex-col p-6">
          {isCheckingStatus ? (
            <div className="flex flex-col items-center justify-center h-full">
              <Loader2 className="animate-spin h-12 w-12 text-blue-500 mb-4" />
              <p className="text-lg dark:text-white">Connecting to HP Marketing Materials Chatbot...</p>
            </div>
          ) : !isInitialized ? (
            <div className="flex flex-col items-center justify-center h-full">
              <h1 className="text-2xl font-bold mb-4 dark:text-white">HP Marketing Materials Chatbot</h1>
              <p className="text-lg text-center mb-4 dark:text-gray-300">
                The system is currently initializing. Please try again later.
              </p>
              <button
                onClick={() => window.location.reload()}
                className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
              >
                Refresh
              </button>
            </div>
          ) : (
            <>
              <div className="border-b pb-4 mb-4">
                <div className="flex justify-between items-center mb-2">
                  <h1 className="text-2xl font-bold dark:text-white">
                    {activeConversation?.title || "HP Marketing Materials Chatbot"}
                  </h1>
                  <div className="flex gap-2">
                    <button
                      onClick={resetChat}
                      className="px-3 py-1 bg-gray-200 text-gray-800 dark:bg-gray-700 dark:text-gray-200 rounded hover:bg-gray-300 dark:hover:bg-gray-600 text-sm"
                    >
                      Reset Chat
                    </button>
                  </div>
                </div>
                <p className="text-gray-600 dark:text-gray-300">
                  Ask questions about HP's marketing materials, branding guidelines, campaign strategies, and creative processes.
                </p>
              </div>
              
              <div className="flex-1 overflow-y-auto mb-4 -mx-6 px-6">
                <div className="space-y-4 py-2">
                  {messages.map((message, index) => (
                    <MessageBubble key={index} message={message} />
                  ))}
                  <div ref={messagesEndRef} className="h-4" />
                </div>
              </div>

              <div className="flex space-x-2">
                <input
                  type="text"
                  value={inputMessage}
                  onChange={(e) => setInputMessage(e.target.value)}
                  onKeyPress={(e) => {
                    if (e.key === 'Enter') {
                      e.preventDefault(); // Prevent any default behavior
                      if (!isProcessing && inputMessage.trim()) {
                        handleSubmit();
                      }
                    }
                  }}
                  placeholder="Type your message..."
                  className="flex-1 p-2 border dark:border-gray-600 dark:bg-gray-700 dark:text-white rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
                  disabled={isProcessing}
                />
                <button
                  onClick={handleSubmit}
                  disabled={isProcessing || !inputMessage.trim()}
                  className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 disabled:bg-gray-300 disabled:cursor-not-allowed"
                >
                  {isProcessing ? (
                    <Loader2 className="animate-spin" size={16} />
                  ) : (
                    <Send size={16} />
                  )}
                </button>
              </div>
            </>
          )}

          {error && !isCheckingStatus && (
            <Alert variant="destructive" className="mt-4">
              <AlertDescription>{error}</AlertDescription>
            </Alert>
          )}
            </div>
          </div>
        </div>
      </div>
    </Tooltip.Provider>
  );
}