class RonnieGPTWidget {
    constructor(companyId) {
        console.log("Widget initialized with company ID:", companyId);
        this.companyId = companyId;
        // this.apiBaseUrl = 'http://127.0.0.1:5001/';
        this.apiBaseUrl = 'https://agent.ronniemarket.com/';
        this.sessionId = localStorage.getItem('chat_session_id_' + companyId) || this.generateSessionId();
        // console.log("Initialized with session ID:", this.sessionId);
        this.injectStyles();
        this.createWidget();
        this.loadWelcomeMessage();
        this.loadChatHistory();
        this.isRecording = false;
        this.mediaRecorder = null;
        this.pendingActionData = null;
        this.audioChunks = [];
        this.setupSpeechRecognition();
        this.meetingInfo = {
            email: null,
            date: null,
            time: null,
            state: 'idle'
        };
        this.isVoiceModeActive = false;
        this.isSpeaking = false;
        this.currentUtterance = null;
        this.widgetColor = '#F42941';
        this.voiceSpeed = 1.0;
        this.aiVoice = 'en-GB-female';
        this.loadSettings();
        this.voiceState = 'idle';
        this.setupVoiceConversation();
        this.audioContext = null;
        this.mediaStream = null;
        this.micProcessor = null;
        this.isDetectingInterruption = false;
        this.idleReminderSeconds = 4; // default
    }

    generateSessionId() {
        const sessionId = 'session_' + Math.random().toString(36).substr(2, 9);
        localStorage.setItem('chat_session_id_' + this.companyId, sessionId);
        return sessionId;
    }

    async loadWelcomeMessage() {
        try {
            const response = await fetch(`${this.apiBaseUrl}/api/${this.companyId}/welcome-message`);
            const data = await response.json();

            if (data.success && data.welcome_message) {
                this.addMessage('assistant', data.welcome_message);
            }
        } catch (error) {
            console.error("Error loading welcome message:", error);
        }
    }

    async loadChatHistory() {
        try {
            const response = await fetch(`${this.apiBaseUrl}/api/${this.companyId}/chat-history?session_id=${this.sessionId}`);
            const data = await response.json();

            if (data.success && data.history) {
                const chatMessages = document.getElementById('chat-messages');
                chatMessages.innerHTML = '';

                // Only show welcome message for new chats (when history is empty)
                if (data.history.length === 0) {
                    await this.loadWelcomeMessage();
                } else {
                    // Add each message from history
                    data.history.forEach(msg => {
                        this.addMessage(msg.role, msg.content);
                    });
                }
            }
        } catch (error) {
            console.error("Error loading chat history:", error);
        }
    }

    injectStyles() {
        // Load Open Sans font from Google Fonts
        const fontLink = document.createElement('link');
        fontLink.href = 'https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500;600&display=swap';
        fontLink.rel = 'stylesheet';
        document.head.appendChild(fontLink);

        // Inject Chat Widget Styles
        const styles = `
            * {
                font-family: 'Segoe UI', Segoe UI;
            }
            /* Chat Toggle Button */
            .chat-toggle-btn {
                position: fixed;
                bottom: 30px;
                right: 30px;
                width: 60px;
                height: 60px;
                border-radius: 50%;
                background: ${this.widgetColor};
                color: white;
                border: none;
                cursor: pointer;
                display: flex;
                align-items: center;
                justify-content: center;
                box-shadow: 0 2px 10px rgba(0,0,0,0.2);
                z-index:9999999999999999999999;
                transition: all 0.3s ease;
            }
    
            .chat-toggle-btn:hover {
                transform: scale(1.1);
                background: ${this.adjustColor(this.widgetColor, -20)};
            }
    
            .chat-toggle-btn svg {
                width: 30px;
                height: 30px;
            }
    
            /* Chat Window */
            #chat-window {
                position: fixed;
                bottom: 100px;
                right: 30px;
                width: 370px;
                height: 500px;
                background: white;
                border-radius: 12px;
                box-shadow: 0 2px 15px rgba(0,0,0,0.1);
                display: flex;
                flex-direction: column;
                overflow: hidden;
                z-index: 10000;
                position: relative;
            }
    
            .chat-header {
                background: ${this.widgetColor};
                color: white;
                padding: 15px;
                font-size: 24px;
                font-weight: 600;
                border-radius: 12px 12px 0 0;
            }
    
            #chat-messages {
                flex-grow: 1;
                padding: 20px;
                overflow-y: auto;
                background: #fff;
                display: flex;
                flex-direction: column;
                gap: 12px;
            }
    
            .message {
                max-width: 85%;
                padding: 12px 16px;
                border-radius: 12px;
                font-size: 14px;
                line-height: 1.4;
            }
    
            .message.user {
                background: #E6F0FF;
                color: #333;
                align-self: flex-end;
                margin-left: 15%;
            }
    
            .message.assistant {
                background: #F5F5F5;
                color: #333;
                align-self: flex-start;
                margin-right: 15%;
                font-family: 'Segoe UI'!important;
            }
    
            .chat-input-container {
                padding: 11px;
                background: white;
                border-top: 1px solid #eee;
                display: flex;
                gap: 8px;
                align-items: center;
            }
    
            #chat-input {
                flex-grow: 1;
                padding: 9px;
                border: 1px solid #ddd;
                border-radius: 8px;
                outline: none;
                font-size: 14px;
            }
    
            #chat-input:focus {
                border-color: #ff4444;
            }
    
            .voice-button {
                position: relative;
                width: 40px;
                height: 40px;
                border-radius: 8px;
                background: none;
                border: 2px solid #ddd;
                cursor: pointer;
                transition: all 0.3s ease;
            }

            .voice-button.active {
                border-color: #ff4444;
                background: rgba(255, 68, 68, 0.1);
            }

            .voice-button.listening {
                animation: pulse 1.5s infinite;
            }
    
            .voice-button svg {
                width: 20px;
                height: 20px;
                transition: fill 0.3s ease;
            }

            .voice-button.active svg {
                fill: #ff4444;
            }

            @keyframes pulse {
                0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(255, 68, 68, 0.4); }
                70% { transform: scale(1.1); box-shadow: 0 0 0 10px rgba(255, 68, 68, 0); }
                100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(255, 68, 68, 0); }
            }
    
            #send-message {
                background: ${this.widgetColor};
                color: white;
                border: none;
                padding: 7px 8px;
                border-radius: 8px;
                cursor: pointer;
                font-weight: 500;
                transition: background 0.2s ease;
            }
    
            #send-message:hover {
                background: ${this.adjustColor(this.widgetColor, -20)};
            }
    
            @keyframes pulse {
                0% { transform: scale(1); }
                50% { transform: scale(1.1); }
                100% { transform: scale(1); }
            }
    
            #chat-window.hidden {
                display: none;
            }
    
            #ronnie-chat-widget {
                position: fixed;
                bottom: 0;
                right: 0;
                z-index: 9999999999999999999999 !important;
            }
    
            .footer-widget {
                text-align: center;
                padding: 10px;
                font-size: 12px;
                color: #fff;
                background: ${this.widgetColor};
            }
    
            .footer-widget a {
                color: #fff;
                text-decoration: none;
                font-weight: 700;
            }

            /* Voice Conversation Mode */
            .voice-conversation-mode {
                position: absolute;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                background: rgba(255, 255, 255, 0.98);
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;
                z-index: 1000;
                border-radius: 12px;
            }

            .voice-indicator {
                width: 80px;
                height: 80px;
                border-radius: 50%;
                background: ${this.widgetColor};
                display: flex;
                align-items: center;
                justify-content: center;
                margin-bottom: 20px;
                position: relative;
                box-shadow: 0 4px 12px rgba(244, 41, 65, 0.2);
            }

            .voice-indicator svg {
                width: 32px;
                height: 32px;
                fill: white;
                z-index: 1;
            }

            .voice-waves {
                position: absolute;
                width: 100%;
                height: 100%;
                border-radius: 50%;
                background: ${this.widgetColor};
                opacity: 0.2;
                animation: wave 1.5s infinite;
            }

            .voice-waves:nth-child(2) {
                animation-delay: 0.5s;
            }

            .voice-waves:nth-child(3) {
                animation-delay: 1s;
            }

            @keyframes wave {
                0% {
                    transform: scale(1);
                    opacity: 0.4;
                }
                100% {
                    transform: scale(2);
                    opacity: 0;
                }
            }

            .voice-status-text {
                font-size: 16px;
                color: #333;
                margin-top: 16px;
                text-align: center;
                font-weight: 500;
            }

            .voice-hint {
                font-size: 13px;
                color: #666;
                margin-top: 8px;
                text-align: center;
            }

            .exit-voice-mode {
                position: absolute;
                top: 16px;
                right: 16px;
                background: none;
                border: none;
                cursor: pointer;
                padding: 8px;
                opacity: 0.6;
                transition: opacity 0.2s ease;
            }

            .exit-voice-mode:hover {
                opacity: 1;
            }

            .exit-voice-mode svg {
                width: 20px;
                height: 20px;
                stock: #666;
            }
                /* Add these new styles for typing indicator */
            .typing-indicator {
                background: #F5F5F5 !important;
                padding: 12px 16px !important;
                width: fit-content !important;
            }

            .typing-animation {
                display: flex;
                align-items: center;
                gap: 4px;
            }

            .typing-animation span {
                width: 4px;
                height: 4px;
                background-color: black;
                border-radius: 50%;
                display: inline-block;
                animation: typing 1.4s infinite ease-in-out;
            }

            .typing-animation span:nth-child(1) {
                animation-delay: 0s;
            }

            .typing-animation span:nth-child(2) {
                animation-delay: 0.2s;
            }

            .typing-animation span:nth-child(3) {
                animation-delay: 0.4s;
            }

            @keyframes typing {
                0%, 60%, 100% {
                    transform: translateY(0);
                }
                30% {
                    transform: translateY(-4px);
                }
            }

            /* Update the mic button style */
            #start-voice {
                border: none;
                padding: 8px;
                cursor: pointer;
                display: flex;
                align-items: center;
                justify-content: center;
                opacity: 0.6;
                transition: opacity 0.2s ease;
                background: #eae1e187;
                border-radius: 8px;
            }

            #start-voice:hover {
                opacity: 1;
            }

            #start-voice svg {
                width: 24px;
                height: 24px;
            }

            .hidden {
                display: none !important;
            }
            @media screen and (max-width: 1400px) {
               #chat-window {
                width: 370px;
                height: 470px;
                }

            }
            @media screen and (max-width: 1024px) {
               #chat-window {
                width: 370px;
                height: 470px;
                }
            @media screen and (max-width: 1400px) {
               #chat-window {
                width: 370px;
                height: 450px;
                }

            }
            @media screen and (max-width: 391px) {
                #chat-window {
                    width: 335px !important;
                    height: 480px;
                }

            }
            @media screen and (max-width: 376px) {
                #chat-window {
                    width: 322px !important;
                    height: 480px;
                }
            }
            @media screen and (max-width:415px) {
                #chat-window {
                width: 360px;
                    height: 480px;
                }

            }
            @media screen and (max-width: 360px) {
                #chat-window {
                    width: 300px !important;
                    height: 450px;
                }
            }
             @media screen and (max-width: 344px) {
                #chat-window {
                    width: 290px !important;
                    height: 450px;
                }
            }
            .voice-indicator.listening {
                animation: pulse 1.5s infinite;
            }
            
            .voice-indicator.speaking {
                background: #4CAF50;
            }
            
            .transcript {
                max-height: 60px;
                overflow-y: auto;
                margin-top: 10px;
                padding: 5px;
                background: rgba(255, 255, 255, 0.9);
                border-radius: 4px;
            }

            
        `;

        const styleSheet = document.createElement("style");
        styleSheet.textContent = styles;
        document.head.appendChild(styleSheet);
    }

    createWidget() {
        const widgetHTML = `
            <div id="ronnie-chat-widget">
                <button class="chat-toggle-btn" id="chat-toggle" aria-label="chat">
                    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
                    </svg>
                </button>

                <div id="chat-window" class="hidden">
                    <div class="chat-header">
                        <div style="display: flex; justify-content: space-between; align-items: center;">
                            <h3 style="margin: 0; font-weight: 600;font-size: 22px;font-family: 'Segoe UI'!important;">Customer Support</h3>
                            <button id="close-chat" style="background: none; border: none; color: white; cursor: pointer;">
                            <svg  xmlns="http://www.w3.org/2000/svg"  width="24"  height="24"  viewBox="0 0 24 24"  fill="none"  stroke="currentColor"  stroke-width="2"  stroke-linecap="round"  stroke-linejoin="round"  class="icon icon-tabler icons-tabler-outline icon-tabler-x"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M18 6l-12 12" /><path d="M6 6l12 12" /></svg>                            </button>
                        </div>
                    </div>

                    <div id="chat-messages"></div>

                    <div class="chat-input-container">
                        <input type="text" id="chat-input" placeholder="Type your message..." style="font-family: 'Segoe UI'!important;">
                        <button id="send-message">
                        <svg  xmlns="http://www.w3.org/2000/svg"  width="23"  height="23"  viewBox="0 0 24 24"  fill="none"  stroke="currentColor"  stroke-width="2"  stroke-linecap="round"  stroke-linejoin="round"  class="icon icon-tabler icons-tabler-outline icon-tabler-send"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10 14l11 -11" /><path d="M21 3l-6.5 18a.55 .55 0 0 1 -1 0l-3.5 -7l-7 -3.5a.55 .55 0 0 1 0 -1l18 -6.5" /></svg>
                        </button>
                        <button id="start-voice" class="voice-button">
                            <svg  xmlns="http://www.w3.org/2000/svg"  width="24"  height="24"  viewBox="0 0 24 24"  fill="none"  stroke="currentColor"  stroke-width="2"  stroke-linecap="round"  stroke-linejoin="round"  class="icon icon-tabler icons-tabler-outline icon-tabler-phone"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 4h4l2 5l-2.5 1.5a11 11 0 0 0 5 5l1.5 -2.5l5 2v4a2 2 0 0 1 -2 2a16 16 0 0 1 -15 -15a2 2 0 0 1 2 -2" /></svg>
                        </button>
                    </div>

                    <!-- Voice conversation overlay - now inside chat-window -->
                    <div id="voice-conversation-mode" class="voice-conversation-mode hidden">
                        <button id="exit-voice-mode" class="exit-voice-mode">
                            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
                                <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
                            </svg>
                        </button>
                        <div class="voice-indicator">
                            <div class="voice-waves"></div>
                            <div class="voice-waves"></div>
                            <div class="voice-waves"></div>
                            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
                                <path d="M12 14c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3z"/>
                                <path d="M17 11c0 2.76-2.24 5-5 5s-5-2.24-5-5H5c0 3.53 2.61 6.43 6 6.92V21h2v-3.08c3.39-.49 6-3.39 6-6.92h-2z"/>
                            </svg>
                        </div>
                        <div id="voice-status-text" class="voice-status-text">Listening...</div>
                        <div class="voice-hint">Click anywhere to stop</div>
                        </div>

                    <div class="footer-widget" style="margin:0;font-family: 'Segoe UI'!important;">
                            Developed By<a href="https://ronnieridge.com/" target="__blank"> Ronnie Ridge </a>.
                        </div>
                </div>
            </div>
        `;

        const div = document.createElement('div');
        div.innerHTML = widgetHTML;
        document.body.appendChild(div);

        this.setupEventListeners();
    }

    setupEventListeners() {
        const toggle = document.getElementById('chat-toggle');
        const close = document.getElementById('close-chat');
        const window = document.getElementById('chat-window');
        const input = document.getElementById('chat-input');
        const send = document.getElementById('send-message');
        const startVoiceButton = document.getElementById('start-voice');

        toggle.addEventListener('click', () => {
            window.classList.toggle('hidden');
            // Stop speaking if widget is closed
            if (window.classList.contains('hidden')) {
                this.stopAISpeech();
                if (this.isVoiceModeActive) {
                    this.toggleVoiceMode();
                }
            }
        });

        close.addEventListener('click', () => {
            window.classList.add('hidden');
            // Stop speaking when widget is closed
            this.stopAISpeech();
            if (this.isVoiceModeActive) {
                this.toggleVoiceMode();
            }
        });

        // Update the sendMessage function to properly handle text input
        const sendMessage = async () => {
            const message = input.value.trim();
            if (!message) return;

            // Add user message to chat immediately
            this.addMessage('user', message);

            // Clear input field
            input.value = '';

            // Check for meeting confirmation
            if (this.pendingActionData && message.toLowerCase() === 'confirm') {
                console.log('Sending meeting data:', this.pendingActionData);
                console.log('Current meeting info:', this.meetingInfo);

                // Show typing indicator before API call
                const typingIndicator = this.showTypingIndicator();
                const startTime = Date.now();

                const response = await fetch(`${this.apiBaseUrl}/api/${this.companyId}/chat`, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        message: JSON.stringify({
                            action: 'schedule_meeting',
                            ...this.pendingActionData
                        }),
                        session_id: this.sessionId
                    })
                });

                const data = await response.json();

                // Calculate time spent fetching and wait if less than 2 seconds
                const elapsedTime = Date.now() - startTime;
                if (elapsedTime < 2000) {
                    await new Promise(resolve => setTimeout(resolve, 2000 - elapsedTime));
                }

                // Remove typing indicator
                typingIndicator.remove();

                if (data.success) {
                    this.addMessage('assistant', data.response);
                } else {
                    this.addMessage('assistant', data.error || 'Failed to schedule meeting.');
                }

                this.pendingActionData = null;
                return;
            }

            try {
                // Show typing indicator before API call
                const typingIndicator = this.showTypingIndicator();
                const startTime = Date.now();

                const apiUrl = this.apiBaseUrl + '/api/' + this.companyId + '/chat';
                const response = await fetch(apiUrl, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({
                        message: message,
                        session_id: this.sessionId
                    })
                });

                const data = await response.json();

                // Calculate time spent fetching and wait if less than 2 seconds
                const elapsedTime = Date.now() - startTime;
                if (elapsedTime < 2000) {
                    await new Promise(resolve => setTimeout(resolve, 2000 - elapsedTime));
                }

                // Remove typing indicator
                typingIndicator.remove();

                if (data.success) {
                    if (data.session_id) {
                        this.sessionId = data.session_id;
                        localStorage.setItem('chat_session_id_' + this.companyId, this.sessionId);
                    }

                    const actionMatch = data.response.match(/\[ACTION\](.*?)\[\/ACTION\]/s);
                    if (actionMatch) {
                        try {
                            const actionData = JSON.parse(actionMatch[1]);
                            if (actionData.action === 'schedule_meeting') {
                                this.pendingActionData = actionData;
                                this.addMessage('assistant', `Do you want to confirm the meeting on ${actionData.date} at ${actionData.time} for ${actionData.email}? Please type "confirm" to proceed.`);
                                return;
                            }
                        } catch (e) {
                            console.error('Action parsing error:', e);
                        }
                    }

                    this.addMessage('assistant', data.response);
                } else {
                    this.addMessage('assistant', 'Sorry, I encountered an error. Please try again.');
                }
            } catch (error) {
                console.error("API Error:", error);
                // Ensure typing indicator is removed even on error
                if (typingIndicator) {
                    typingIndicator.remove();
                }
                this.addMessage('assistant', 'Sorry, something went wrong.');
            }
        };

        // Add click event for send button
        if (send) {
            send.addEventListener('click', sendMessage);
        }

        // Add enter key event for input field
        if (input) {
            input.addEventListener('keypress', (e) => {
                if (e.key === 'Enter') {
                    sendMessage();
                }
            });
        }

        // Handle interruptions
        document.addEventListener('keydown', () => {
            if (this.synthesis.speaking) {
                this.synthesis.cancel();
            }
        });

        document.addEventListener('click', () => {
            if (this.synthesis.speaking) {
                this.synthesis.cancel();
            }
        });

        // Add keyboard shortcut for voice toggle (Space key)
        document.addEventListener('keydown', (e) => {
            if (e.code === 'Space' && document.activeElement.tagName !== 'INPUT' && document.activeElement.tagName !== 'TEXTAREA') {
                e.preventDefault();
                this.toggleVoiceMode();
            }
        });

        // Voice mode event listeners
        const exitVoiceMode = document.getElementById('exit-voice-mode');
        const voiceConversationMode = document.getElementById('voice-conversation-mode');

        if (exitVoiceMode) {
            exitVoiceMode.addEventListener('click', (e) => {
                e.stopPropagation();
                this.toggleVoiceMode();
            });
        }

        if (voiceConversationMode) {
            voiceConversationMode.addEventListener('click', () => {
                if (this.isSpeaking) {
                    this.stopAISpeech();
                    this.updateVoiceUI('Listening...');
                }
            });
        }

        if (startVoiceButton) {
            startVoiceButton.addEventListener('click', () => {
                this.toggleVoiceMode();
            });
        }
    }

    addMessage(role, content) {
        const chatMessages = document.getElementById('chat-messages');
        const messageDiv = document.createElement('div');
        messageDiv.className = `message ${role}`;
        
        // Use makeLinksClickable to convert links
        messageDiv.innerHTML = this.makeLinksClickable(content);
        
        chatMessages.appendChild(messageDiv);

        // Scroll to bottom after adding message
        chatMessages.scrollTop = chatMessages.scrollHeight;
    }

    showTypingIndicator() {
        const chatMessages = document.getElementById('chat-messages');
        const typingDiv = document.createElement('div');
        typingDiv.className = 'message assistant typing-indicator';
        typingDiv.innerHTML = `
            <div class="typing-animation">
                <span></span>
                <span></span>
                <span></span>
            </div>
        `;
        chatMessages.appendChild(typingDiv);
        chatMessages.scrollTop = chatMessages.scrollHeight;
        return typingDiv;
    }

    setupSpeechRecognition() {
        if ('webkitSpeechRecognition' in window) {
            this.recognition = new webkitSpeechRecognition();
            this.recognition.continuous = true;
            this.recognition.interimResults = true;
            this.recognition.lang = 'en-US';

            // Enhanced speech tracking properties
            this.lastSpeechTime = Date.now();
            this.isUserSpeaking = false;
            this.speechTimeout = null;
            this.isContinuousSpeech = false;

            // State tracking
            this.isListening = false;
            this.isSpeaking = false;
            this.lastTranscript = '';
            this.idleTimer = null;
            this.isProcessingSpeech = false;
            this.voiceState = 'idle';

            // Initialize speech synthesis
            this.synthesis = window.speechSynthesis;
            this.currentUtterance = null;
            this.voices = [];

            // Load voices
            const loadVoices = () => {
                this.voices = this.synthesis.getVoices();
                if (this.voices.length === 0) setTimeout(loadVoices, 100);
            };
            this.synthesis.onvoiceschanged = loadVoices;
            loadVoices();

            // Single consolidated onstart handler
            this.recognition.onstart = () => {
                console.log('Voice recognition started');
                this.isListening = true;
                this.voiceState = 'listening';
                this.updateVoiceUI('Listening...', '', true);
                this.updateVoiceButtonState(true);
                this.clearIdleTimer(); // Clear any existing idle timer
            };

            // Rest of the handlers remain the same...
            this.recognition.onend = () => {
                console.log('Voice recognition ended');
                this.isListening = false;

                // Only restart if we're still in voice mode and not speaking
                if (this.isVoiceModeActive && !this.isSpeaking) {
                    try {
                        setTimeout(() => {
                            if (this.isVoiceModeActive && !this.isSpeaking) {
                                this.recognition.start();
                            }
                        }, 100);
                    } catch (e) {
                        console.log('Recognition restart error:', e);
                    }
                }
                this.updateVoiceButtonState(false);
            };

            this.recognition.onresult = async (event) => {
                if (!this.isVoiceModeActive) return;
                let transcript = '';
                for (let i = event.resultIndex; i < event.results.length; ++i) {
                    transcript += event.results[i][0].transcript;
                }
                transcript = transcript.trim();
                if (transcript) {
                    this.resetIdleTimer();
                    this.handleUserVoiceInput(transcript);
                }
            };

            // Detect user interruption WHILE AI is speaking
            this.recognition.onsoundstart = () => {
                if (this.voiceState === 'speaking') {
                    this.stopAISpeech(true); // true = interrupted
                }
            };

            this.recognition.isListening = false; // Add this property
        }
    }

    async stopAISpeech() {
        if (this.synthesis && this.synthesis.speaking) {
            try {
                // Store the current state before canceling
                const wasSpeaking = this.isSpeaking;

                // Cancel speech
                this.synthesis.cancel();

                // Reset states
                this.isSpeaking = false;
                this.currentUtterance = null;

                // Update UI and restart recognition only if we were actually speaking
                if (wasSpeaking) {
                    this.updateVoiceUI('Listening...', '', true);

                    // Small delay before restarting recognition
                    await new Promise(resolve => setTimeout(resolve, 100));

                    if (this.isVoiceModeActive && !this.isListening) {
                        try {
                            await this.recognition.start();
                        } catch (e) {
                            console.log('Recognition restart error:', e);
                        }
                    }
                }

                return true;
            } catch (e) {
                console.error('Error stopping speech:', e);
                return false;
            }
        }
        return false;
    }

    async speakResponse(text) {
        console.log(`speakResponse called with text length: ${text.length}`);
        if (!this.isVoiceModeActive) {
            console.log('speakResponse: Voice mode not active, returning.');
            return;
        }
        if (!text) {
            console.log('speakResponse: No text to speak, starting listening.');
            this.startListening();
            return;
        }

        // Stop recognition while speaking
        try { this.recognition.stop(); } catch (e) { console.log('speakResponse: Error stopping recognition:', e); }

        this.voiceState = 'speaking';
        this.updateVoiceUI('Speaking...');
        this.isSpeaking = true;
        this.wasInterrupted = false;
        this.remainingChunks = null;

        // Start mic interruption detection immediately
        this.startMicInterruptionDetection();

        // Clear idle timer while speaking
        this.clearIdleTimer();

        return new Promise((resolve) => {
            // Split text into smaller chunks for faster response
            const sentences = text.match(/[^.!?]+[.!?]+/g) || [text];
            const combinedSentences = [];
            let currentChunk = '';
            let wordCount = 0;
            const MAX_WORDS_PER_CHUNK = 8; // Reduced chunk size for faster response

            // Combine sentences into smaller chunks
            for (let i = 0; i < sentences.length; i++) {
                const sentence = sentences[i].trim();
                const sentenceWordCount = sentence.split(/\s+/).length;

                if (wordCount + sentenceWordCount <= MAX_WORDS_PER_CHUNK) {
                    currentChunk += (currentChunk ? ' ' : '') + sentence;
                    wordCount += sentenceWordCount;
                } else {
                    if (currentChunk) {
                        combinedSentences.push(currentChunk);
                    }
                    currentChunk = sentence;
                    wordCount = sentenceWordCount;
                }
            }
            if (currentChunk) {
                combinedSentences.push(currentChunk);
            }

            this.remainingChunks = combinedSentences;
            let currentSentenceIndex = 0;

            const speakNextSentence = () => {
                if (this.wasInterrupted) {
                    console.log('speakNextSentence: Speech was interrupted, stopping immediately.');
                    this.remainingChunks = null;
                    cleanupSpeech('interrupted');
                    return;
                }

                if (currentSentenceIndex >= combinedSentences.length) {
                    this.remainingChunks = null;
                    cleanupSpeech('completed');
                    return;
                }

                const utterance = new SpeechSynthesisUtterance(combinedSentences[currentSentenceIndex]);
                utterance.rate = this.voiceSpeed || 1.0;
                utterance.pitch = 1.0;
                utterance.volume = 1.0;

                // Set voice based on selected option
                const voices = this.synthesis.getVoices();
                let selectedVoice = null;

                switch (this.aiVoice) {
                    case 'en-GB-female':
                        selectedVoice = voices.find(v => v.lang === 'en-GB' && v.name.includes('Female'));
                        break;
                    case 'en-GB-male':
                        selectedVoice = voices.find(v => v.lang === 'en-GB' && v.name.includes('Male'));
                        break;
                    case 'en-US-female':
                        selectedVoice = voices.find(v => v.lang === 'en-US' && v.name.includes('Female'));
                        break;
                    case 'en-US-male':
                        selectedVoice = voices.find(v => v.lang === 'en-US' && v.name.includes('Male'));
                        break;
                }

                if (selectedVoice) {
                    utterance.voice = selectedVoice;
                } else {
                    // Fallback to default voice if selected voice not found
                    utterance.lang = this.aiVoice.split('-')[0] + '-' + this.aiVoice.split('-')[1];
                }

                utterance.onend = () => {
                    if (this.wasInterrupted) {
                        this.remainingChunks = null;
                        cleanupSpeech('interrupted');
                        return;
                    }

                    currentSentenceIndex++;
                    if (currentSentenceIndex < combinedSentences.length) {
                        // Reduced delay between chunks
                        setTimeout(() => {
                            if (!this.wasInterrupted) {
                                speakNextSentence();
                            }
                        }, 50); // Reduced delay to 50ms
                    } else {
                        this.remainingChunks = null;
                        cleanupSpeech('completed');
                    }
                };

                utterance.onerror = (event) => {
                    console.error('SpeechSynthesis error:', event.error);
                    if (!this.wasInterrupted) {
                        currentSentenceIndex++;
                        speakNextSentence();
                    }
                };

                this.currentUtterance = utterance;

                try {
                    this.synthesis.speak(utterance);
                } catch (e) {
                    console.error('Error calling synthesis.speak():', e);
                    if (!this.wasInterrupted) {
                        currentSentenceIndex++;
                        speakNextSentence();
                    }
                }
            };

            const cleanupSpeech = (reason = 'unknown') => {
                this.isSpeaking = false;
                this.stopMicInterruptionDetection();
                this.remainingChunks = null;

                if (this.isVoiceModeActive) {
                    this.startListening();
                } else {
                    this.voiceState = 'idle';
                    this.updateVoiceUI('Idle');
                    this.clearIdleTimer();
                }
                resolve();
            };

            // Start speaking immediately
            speakNextSentence();
        });
    }

    toggleVoiceMode() {
        const voiceConversationMode = document.getElementById('voice-conversation-mode');

        if (!this.isVoiceModeActive) {
            this.isVoiceModeActive = true;
            voiceConversationMode.classList.remove('hidden');

            // Start recognition
            try {
                this.recognition.start();
            } catch (e) {
                console.log('Recognition start error:', e);
            }
        } else {
            this.isVoiceModeActive = false;
            voiceConversationMode.classList.add('hidden');
            this.stopAISpeech();

            try {
                this.recognition.stop();
            } catch (e) {
                console.log('Recognition stop error:', e);
            }
        }
    }

    async processVoiceInput(transcript) {
        if (!transcript.trim()) return;

        try {
            // Add user message to chat
            this.addMessage('user', transcript);

            const response = await fetch(`${this.apiBaseUrl}/api/${this.companyId}/chat`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json',
                    'X-Response-Type': 'concise'
                },
                body: JSON.stringify({
                    message: transcript,
                    session_id: this.sessionId,
                    is_voice: true
                })
            });

            const data = await response.json();

            if (data.success) {
                this.addMessage('assistant', data.response);

                // Speak the response if we're still in voice mode
                if (this.isVoiceModeActive) {
                    await this.speakResponse(data.response);
                }
            }
        } catch (error) {
            console.error('Error processing voice input:', error);
            this.updateVoiceUI('Error occurred. Please try again.');
        }
    }

    updateVoiceUI(status, transcript = '', isListening = false) {
        const statusElement = document.getElementById('voice-status-text');
        const voiceIndicator = document.querySelector('.voice-indicator');

        if (statusElement) {
            statusElement.textContent = status;

            // Clear any existing transcript element
            const existingTranscript = statusElement.querySelector('.transcript');
            if (existingTranscript) {
                existingTranscript.remove();
            }

            if (transcript) {
                const transcriptElement = document.createElement('div');
                transcriptElement.className = 'transcript';
                transcriptElement.style.fontSize = '14px';
                transcriptElement.style.color = '#666';
                transcriptElement.style.marginTop = '10px';
                transcriptElement.textContent = transcript;
                statusElement.appendChild(transcriptElement);
            }
        }

        // Update visual feedback
        if (voiceIndicator) {
            voiceIndicator.classList.toggle('listening', isListening);
            voiceIndicator.classList.toggle('speaking', this.isSpeaking);
        }
    }

    updateVoiceButtonState(isActive) {
        const startVoiceButton = document.getElementById('start-voice');
        if (startVoiceButton) {
            startVoiceButton.classList.toggle('active', isActive);
            startVoiceButton.classList.toggle('listening', isActive);
        }
    }

    async loadSettings() {
        try {
            const response = await fetch(`${this.apiBaseUrl}api/${this.companyId}/widget-settings`);
            const data = await response.json();

            if (data.success) {

                this.widgetColor = data.settings[0] || this.widgetColor;
                this.voiceSpeed = parseFloat(data.settings[1]) || this.voiceSpeed;
                this.idleReminderSeconds = parseInt(data.settings[2]) || 4;
                this.aiVoice = data.settings[3] || this.aiVoice;
                this.updateWidgetStyles();
            }
        } catch (error) {
            console.error("Error loading widget settings:", error);
        }
    }

    updateWidgetStyles() {
        const styles = `
            /* ... existing styles ... */
            .chat-toggle-btn {
                background: ${this.widgetColor};
            }
            .chat-toggle-btn:hover {
                background: ${this.adjustColor(this.widgetColor, -20)};
            }
            .chat-header {
                background: ${this.widgetColor};
            }
            .footer-widget {
                background: ${this.widgetColor};
            }
            .voice-indicator {
                background: ${this.widgetColor};
            }
            .voice-waves {
                background: ${this.widgetColor};
            }
            #send-message {
                background: ${this.widgetColor};
            }
            #send-message:hover {
                background: ${this.adjustColor(this.widgetColor, -20)};
            }
        `;

        // Update or create style element
        let styleElement = document.getElementById('ronnie-chat-widget-styles');
        if (!styleElement) {
            styleElement = document.createElement('style');
            styleElement.id = 'ronnie-chat-widget-styles';
            document.head.appendChild(styleElement);
        }
        styleElement.textContent = styles;
    }

    adjustColor(color, amount) {
        if (!color) return '#F42941'; // Return default color if no color provided

        try {
            // Remove the hash if present
            const hex = color.replace('#', '');

            // Convert to RGB
            const r = parseInt(hex.substr(0, 2), 16);
            const g = parseInt(hex.substr(2, 2), 16);
            const b = parseInt(hex.substr(4, 2), 16);

            // Adjust each component
            const adjustR = Math.min(255, Math.max(0, r + amount));
            const adjustG = Math.min(255, Math.max(0, g + amount));
            const adjustB = Math.min(255, Math.max(0, b + amount));

            // Convert back to hex
            const newHex = '#' +
                adjustR.toString(16).padStart(2, '0') +
                adjustG.toString(16).padStart(2, '0') +
                adjustB.toString(16).padStart(2, '0');

            return newHex;
        } catch (error) {
            console.error('Error adjusting color:', error);
            return '#F42941'; // Return default color if there's an error
        }
    }

    setupVoiceConversation() {
        if (!('webkitSpeechRecognition' in window)) return;

        this.recognition = new webkitSpeechRecognition();
        this.recognition.continuous = true;
        this.recognition.interimResults = false;
        this.recognition.lang = 'en-US';

        // Add these properties for speech tracking
        this.lastSpeechTime = Date.now();
        this.isUserSpeaking = false;
        this.isContinuousSpeech = false;

        this.synthesis = window.speechSynthesis;
        this.currentUtterance = null;
        this.voices = [];
        this.voiceState = 'idle';

        // Load voices
        const loadVoices = () => {
            this.voices = this.synthesis.getVoices();
            if (this.voices.length === 0) setTimeout(loadVoices, 100);
        };
        this.synthesis.onvoiceschanged = loadVoices;
        loadVoices();

        // Modified onstart handler
        this.recognition.onstart = () => {
            console.log('onstart, listening from 3 onstart');
            this.voiceState = 'listening';
            this.isUserSpeaking = true;
            this.isContinuousSpeech = true;
            this.lastSpeechTime = Date.now();
            this.updateVoiceUI('Listening...');
            this.clearIdleTimer(); // Clear idle timer when speech starts
        };

        // Modified onend handler
        this.recognition.onend = () => {
            console.log('setupVoiceConversation onend triggered');
            // Set a delay before considering speech as ended and potentially restarting recognition
            setTimeout(() => {
                if (Date.now() - this.lastSpeechTime > 2000) { // 2 second threshold for speech end
                    this.isUserSpeaking = false;
                    this.isContinuousSpeech = false;
                    // If we are still in listening state and voice mode, try to restart recognition
                    if (this.voiceState === 'listening' && this.isVoiceModeActive) {
                        // Call startListening which handles the actual recognition.start logic
                        this.startListening();
                    } else {
                        console.log('Not restarting recognition: not in listening state or voice mode.');
                    }
                } else {
                    // If it ended quickly (e.g. brief pause), assume continuous speech
                    console.log('Speech ended quickly, likely a pause. Not changing state.');
                    // We might need to handle rapid onend/onstart cycles here if they occur
                    // For now, the logic in onresult and onspeechend is intended to manage this
                }
                this.recognition.isListening = false; // Ensure this is cleared when onend fires
            }, 2000); // 2 second delay after onend fires before potentially restarting recognition
        };

        // Modified onresult handler
        this.recognition.onresult = async (event) => {
            if (!this.isVoiceModeActive) return;

            // Update speech timing
            this.lastSpeechTime = Date.now();
            this.isUserSpeaking = true;
            this.isContinuousSpeech = true;
            this.clearIdleTimer(); // Clear idle timer when speech is detected

            let transcript = '';
            for (let i = event.resultIndex; i < event.results.length; ++i) {
                transcript += event.results[i][0].transcript;
            }
            transcript = transcript.trim();
            if (transcript) {
                this.handleUserVoiceInput(transcript);
            }
        };

        // Detect user interruption WHILE AI is speaking
        this.recognition.onsoundstart = () => {
            if (this.voiceState === 'speaking') {
                this.stopAISpeech(true); // true = interrupted
            }
        };
    }

    toggleVoiceMode() {
        const voiceConversationMode = document.getElementById('voice-conversation-mode');
        if (!this.isVoiceModeActive) {
            this.isVoiceModeActive = true;
            voiceConversationMode.classList.remove('hidden');
            this.startListening();
        } else {
            this.isVoiceModeActive = false;
            voiceConversationMode.classList.add('hidden');
            this.stopAISpeech();
            try { this.recognition.stop(); } catch (e) { }
            this.voiceState = 'idle';
            this.clearIdleTimer();
        }
    }

    startListening() {
        console.log('startListening called.');
        if (!this.isVoiceModeActive) {
            console.log('startListening: Voice mode not active, returning.');
            return;
        }
        // Cancel any pending AI speech if starting to listen (redundant with stopAISpeech, but safe)
        if (this.synthesis && this.synthesis.speaking) {
            console.log('startListening: Canceling AI speech.');
            this.synthesis.cancel();
            this.isSpeaking = false; // Ensure speaking flag is false
        }

        // Ensure the state is 'listening' when we intend to listen
        if (this.voiceState !== 'listening') {
            this.voiceState = 'listening';
            this.updateVoiceUI('Listening...');
            console.log('startListening: State set to listening, UI updated.');
        } else {
            console.log('startListening: State already listening.');
        }

        // Only attempt to start recognition if it's not already listening
        // and we are in voice mode and the state is listening
        if (this.recognition && !this.isListening && this.isVoiceModeActive && this.voiceState === 'listening') {
            console.log('startListening: Conditions met to attempt recognition.start().');
            try {
                // Small delay before starting recognition
                setTimeout(() => {
                    // Double check conditions before starting after delay
                    if (this.isVoiceModeActive && this.voiceState === 'listening' && this.recognition && !this.isListening) {
                        try {
                            this.recognition.start();
                            console.log('startListening timeout: recognition.start() called successfully.');
                        } catch (e) {
                            console.error('startListening timeout: Recognition start error:', e);
                        }
                    } else {
                        console.log('startListening timeout: Conditions not met for recognition.start() after delay.');
                        // If recognition couldn't start after delay, maybe log state for debugging
                        console.log(`startListening timeout state: voiceMode=${this.isVoiceModeActive}, voiceState=${this.voiceState}, recognition=${!!this.recognition}, isListening=${this.isListening}`);
                    }
                }, 100); // 100ms delay
            } catch (e) {
                console.error('startListening: Recognition start error directly:', e);
            }
        } else if (this.recognition && this.isListening) {
            console.log('startListening: Recognition already listening according to this.isListening flag.');
        } else {
            console.log('startListening: Conditions not met to attempt recognition.start().');
            // Log state if conditions are not met
            console.log(`startListening state: voiceMode=${this.isVoiceModeActive}, voiceState=${this.voiceState}, recognition=${!!this.recognition}, isListening=${this.isListening}`);
        }

        // Start idle timer now that we are in a listening state (or attempting to enter it)
        // This timer will be cleared by speech activity
        console.log('startListening: Starting idle timer.');
        this.startIdleTimer();
    }

    async handleUserVoiceInput(transcript) {
        this.startRecording();
        // Stop recognition while processing
        try { this.recognition.stop(); } catch (e) { }
        this.voiceState = 'processing';
        this.updateVoiceUI('Processing...');
        this.clearIdleTimer();

        // Show typing indicator before API call
        const typingIndicator = this.showTypingIndicator();
        const startTime = Date.now();

        // Call your backend for AI response
        let aiResponse = '';
        try {
            const response = await fetch(`${this.apiBaseUrl}/api/${this.companyId}/chat`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-Response-Type': 'concise' },
                body: JSON.stringify({
                    message: transcript,
                    session_id: this.sessionId,
                    is_voice: true
                })
            });
            const data = await response.json();
            aiResponse = data.response || '';

            this.addMessage('assistant', aiResponse);
            console.log('hello world!');

            // Stop recording and get the audio blob
            const audioBlob = await this.stopRecording();

            // Create FormData to send both transcript and audio
            const formData = new FormData();
            formData.append('audio', audioBlob, 'voice_message.mp3');
            formData.append('transcript', transcript);
            formData.append('session_id', this.sessionId);

            // Send the audio file
            await fetch(`${this.apiBaseUrl}/api/${this.companyId}/store-voice-message`, {
                method: 'POST',
                body: formData
            });

        } catch (e) {
            console.error('Error processing voice input:', e);
            this.updateVoiceUI('Error getting response');
            // Ensure typing indicator is removed even on error
            if (typingIndicator) {
                typingIndicator.remove();
            }
            this.startListening();
            return;
        }

        // Calculate time spent fetching and wait if less than 2 seconds
        const elapsedTime = Date.now() - startTime;
        if (elapsedTime < 2000) {
            await new Promise(resolve => setTimeout(resolve, 2000 - elapsedTime));
        }

        // Remove typing indicator
        if (typingIndicator) { // Check if indicator exists before removing
            typingIndicator.remove();
        }

        // Speak the response if we're still in voice mode
        if (this.isVoiceModeActive) {
            await this.speakResponse(aiResponse);
            // Add the assistant message to chat after speaking is complete (optional, but common for voice)
            this.addMessage('assistant', aiResponse);
        } else {
            // If voice mode was deactivated while processing, just add the message
            this.addMessage('assistant', aiResponse);
        }
    }

    startMicInterruptionDetection() {
        if (this.isDetectingInterruption) return;
        this.isDetectingInterruption = true;

        navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {
            this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
            this.mediaStream = stream;
            const source = this.audioContext.createMediaStreamSource(stream);
            const processor = this.audioContext.createScriptProcessor(1024, 1, 1); // Reduced buffer size for lower latency

            source.connect(processor);
            processor.connect(this.audioContext.destination);

            // Improved interruption detection logic
            let aboveThresholdStart = null;
            const RMS_THRESHOLD = 0.08; // Lowered threshold to be more sensitive
            const MIN_SPEAK_MS = 100;   // Reduced minimum speak time for faster response
            let consecutiveAboveThreshold = 0;
            const CONSECUTIVE_THRESHOLD = 3; // Number of consecutive samples above threshold

            processor.onaudioprocess = (e) => {
                const input = e.inputBuffer.getChannelData(0);
                let sum = 0.0;
                for (let i = 0; i < input.length; ++i) {
                    sum += input[i] * input[i];
                }
                const rms = Math.sqrt(sum / input.length);

                const now = Date.now();
                if (rms > RMS_THRESHOLD) {
                    consecutiveAboveThreshold++;
                    if (!aboveThresholdStart) {
                        aboveThresholdStart = now;
                    }

                    // Trigger interruption if we have enough consecutive samples above threshold
                    if (consecutiveAboveThreshold >= CONSECUTIVE_THRESHOLD &&
                        now - aboveThresholdStart > MIN_SPEAK_MS) {
                        this.stopAISpeech(true);
                        consecutiveAboveThreshold = 0;
                        aboveThresholdStart = null;
                    }
                } else {
                    consecutiveAboveThreshold = 0;
                    aboveThresholdStart = null;
                }
            };

            this.micProcessor = processor;
        }).catch(err => {
            console.warn('Mic access denied for interruption detection', err);
        });
    }

    stopMicInterruptionDetection() {
        this.isDetectingInterruption = false;
        if (this.micProcessor) {
            this.micProcessor.disconnect();
            this.micProcessor = null;
        }
        if (this.audioContext) {
            this.audioContext.close();
            this.audioContext = null;
        }
        if (this.mediaStream) {
            this.mediaStream.getTracks().forEach(track => track.stop());
            this.mediaStream = null;
        }
    }

    stopAISpeech(interrupted = false) {
        console.log(`stopAISpeech called (interrupted: ${interrupted}).`);

        // Immediately set interruption flag
        if (interrupted) {
            this.wasInterrupted = true;
            this.remainingChunks = null; // Clear remaining chunks
        }

        // Cancel any ongoing speech
        if (this.synthesis && this.synthesis.speaking) {
            console.log('stopAISpeech: Canceling SpeechSynthesis.');
            this.synthesis.cancel();
        }

        // Stop mic interruption detection
        this.stopMicInterruptionDetection();
        console.log('stopAISpeech: Mic interruption detection stopped.');

        this.isSpeaking = false;
        this.currentUtterance = null;

        if (interrupted) {
            console.log('stopAISpeech: AI speech was interrupted by user audio.');
            this.voiceState = 'listening';
            this.updateVoiceUI('Interrupted. Listening...');
            // Immediately transition to listening mode
            this.startListening();
        } else if (this.voiceState === 'speaking') {
            console.log('stopAISpeech: Called directly while in speaking state, performing cleanup.');
            this.cleanupSpeech('manual stop');
        } else {
            console.log('stopAISpeech: Not in speaking state, assuming cleanup already handled.');
            if (!this.isVoiceModeActive || this.voiceState !== 'listening') {
                this.clearIdleTimer();
            }
        }
    }

    // Add cleanupSpeech method to the class
    cleanupSpeech(reason = 'unknown') {
        console.log(`cleanupSpeech called from global method (Reason: ${reason}).`);
        // Ensure watchdog timeout is cleared if it exists
        if (this.speechWatchdogTimeout) {
            clearTimeout(this.speechWatchdogTimeout);
            this.speechWatchdogTimeout = null;
            console.log('cleanupSpeech global: Watchdog timeout cleared.');
        }

        this.isSpeaking = false;
        this.currentUtterance = null; // Clear current utterance reference
        this.stopMicInterruptionDetection();
        this.remainingChunks = null; // Clear remaining chunks
        console.log('cleanupSpeech global: State reset, mic detection stopped.');

        // Transition back to listening state or idle
        if (this.isVoiceModeActive) {
            console.log('cleanupSpeech global: Voice mode active, calling startListening().');
            this.startListening(); // startListening handles setting voiceState to 'listening', UI, etc.
        } else {
            console.log('cleanupSpeech global: Voice mode not active, setting state to idle.');
            this.voiceState = 'idle';
            this.updateVoiceUI('Idle'); // Update UI
            this.clearIdleTimer(); // Ensure timer is cleared
        }
    }

    // Modify the startIdleTimer method
    startIdleTimer() {
        this.clearIdleTimer();

        // Only start idle timer if we're in the right state and not in continuous speech
        if (this.voiceState === 'listening' &&
            !this.isProcessingSpeech &&
            this.isVoiceModeActive &&
            !this.isUserSpeaking &&
            !this.isContinuousSpeech) {

            this.idleTimer = setTimeout(async () => {
                // Double check conditions before triggering reminder
                if (this.isVoiceModeActive &&
                    this.voiceState === 'listening' &&
                    !this.isProcessingSpeech &&
                    !this.isUserSpeaking &&
                    !this.isContinuousSpeech &&
                    Date.now() - this.lastSpeechTime > this.idleReminderSeconds * 1000) {

                    const reminderMessage = "Is there anything else I can help you with?";
                    console.log('reminderMessage', reminderMessage);
                    this.addMessage('assistant', reminderMessage);

                    try {
                        this.recognition.stop();
                    } catch (e) { }

                    await this.speakResponse(reminderMessage);

                    if (this.isVoiceModeActive) {
                        try {
                            this.recognition.start();
                        } catch (e) { }
                    }
                }
            }, this.idleReminderSeconds * 1000);
        }
    }

    resetIdleTimer() {
        this.clearIdleTimer();
        if (this.isVoiceModeActive &&
            this.voiceState === 'listening' &&
            !this.isUserSpeaking &&
            !this.isContinuousSpeech) {
            this.startIdleTimer();
        }
    }

    // Modify the clearIdleTimer method
    clearIdleTimer() {
        if (this.idleTimer) {
            clearTimeout(this.idleTimer);
            this.idleTimer = null;
        }
        if (this.speechTimeout) {
            clearTimeout(this.speechTimeout);
            this.speechTimeout = null;
        }
    }

    // Add this new method to handle speech end
    handleSpeechEnd() {
        // Set a longer delay before marking user as not speaking
        this.speechTimeout = setTimeout(() => {
            if (Date.now() - this.lastSpeechTime > 2000) { // 2 second threshold
                this.isUserSpeaking = false;
                // Only start idle timer if we're not processing speech
                if (!this.isProcessingSpeech) {
                    this.startIdleTimer();
                }
            }
        }, 2000); // 2 second delay
    }
    // Add this method to start recording
    startRecording() {
        if (this.isRecording) return;

        this.audioChunks = [];
        navigator.mediaDevices.getUserMedia({ audio: true })
            .then(stream => {
                this.mediaRecorder = new MediaRecorder(stream);
                this.isRecording = true;

                this.mediaRecorder.ondataavailable = (event) => {
                    if (event.data.size > 0) {
                        this.audioChunks.push(event.data);
                    }
                };

                this.mediaRecorder.start();
            })
            .catch(err => {
                console.error('Error accessing microphone:', err);
            });
    }

    // Add this method to stop recording and get the audio blob
    async stopRecording() {
        if (!this.isRecording) return null;

        return new Promise((resolve) => {
            this.mediaRecorder.onstop = () => {
                const audioBlob = new Blob(this.audioChunks, { type: 'audio/mp3' });
                this.isRecording = false;
                this.audioChunks = [];
                resolve(audioBlob);
            };

            this.mediaRecorder.stop();
            this.mediaRecorder.stream.getTracks().forEach(track => track.stop());
        });
    }

    makeLinksClickable(text) {
        // Convert [HELPDESK_LINK] to clickable link
        text = text.replace(/\[HELPDESK_LINK\]/g, '<a href="/intranet-helpdesk" target="_blank">Helpdesk</a>');
        
        // Convert other URLs to clickable links
        text = text.replace(/(https?:\/\/[^\s]+)/g, '<a href="$1" target="_blank">$1</a>');
        
        return text;
    }
}