// Handles key down event to send message on Enter
 function handleKeyDown(event) {
    if (event.key === 'Enter' && !event.shiftKey) {
        event.preventDefault();
        sendMessage();
    }
}

// Sends a message to the chat API
async function sendMessage() {
    const messageInput = document.getElementById('messageInput');
    let message = messageInput.value.trim();

    if (message === '') return;

    // Encode the message to avoid XSS attacks
    message = he.encode(message);

    // Display the user's message in the chat
    displayMessage(message, 'user');
    messageInput.value = ''; // Clear the input
    toggleLoading(true); // Show loading indicator

    try {
        const response = await fetch('https://infer.x64.world/chat', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ message: message })
        });

        if (response.ok) {
            const data = await response.json();
            displayMessage(data, 'assistant');
        } else {
            handleErrorResponse(response.status);
        }
    } catch (error) {
        displayMessage('Error: ' + error.message, 'assistant');
    } finally {
        toggleLoading(false); // Hide loading indicator
    }
}

// Toggles the loading indicator
function toggleLoading(show) {
    const loadingElement = document.getElementById('loading');
    loadingElement.style.display = show ? 'block' : 'none';
}

// Displays a message in the chat window
function displayMessage(content, sender) {
    const messages = document.getElementById('messages');
    const messageElement = document.createElement('div');
    messageElement.classList.add('message', sender);

    // Decode HTML entities and render Markdown
    const decodedContent = he.decode(content);
    const htmlContent = marked(decodedContent);
    messageElement.innerHTML = htmlContent;

    messages.appendChild(messageElement);
    messages.scrollTop = messages.scrollHeight; // Scroll to the bottom of the chat

    // Highlight code blocks if any
    document.querySelectorAll('pre code').forEach((block) => {
        hljs.highlightElement(block);
        if (sender === 'assistant') {
            addCopyButton(block); // Add copy button to code blocks
        }
    });

    // Add "Copy Full Response" button after each assistant response
    if (sender === 'assistant') {
        addCopyFullResponseButton(messages, messageElement);
    }
}

// Adds a copy button to a code block
function addCopyButton(block) {
    const button = document.createElement('button');
    button.classList.add('copy-button-code');
    button.textContent = 'Copy';
    button.addEventListener('click', () => copyToClipboard(block));
    block.parentNode.appendChild(button);
}

// Adds "Copy Full Response" button below the assistant response
function addCopyFullResponseButton(messagesContainer, messageElement) {
    const copyFullResponseButton = document.createElement('button');
    copyFullResponseButton.classList.add('copy-button');
    copyFullResponseButton.textContent = 'Copy Full Response';
    copyFullResponseButton.addEventListener('click', () => copyFullResponse(messageElement));

    messagesContainer.appendChild(copyFullResponseButton);
}

// Copies code block content to the clipboard
function copyToClipboard(block) {
    const text = block.innerText;
    navigator.clipboard.writeText(text).then(() => {
        displayAlert('success', 'The code block was copied to the clipboard!');
    }).catch((err) => {
        displayAlert('error', 'Failed to copy code: ' + err);
    });
}

// Copies the full response content to the clipboard in Markdown format
function copyFullResponse(messageElement) {
    const markdownContent = convertToMarkdown(messageElement);
    navigator.clipboard.writeText(markdownContent).then(() => {
        displayAlert('success', 'Full response copied to clipboard!');
    }).catch((err) => {
        displayAlert('error', 'Failed to copy response: ' + err);
    });
}

// Converts the HTML content of the response to Markdown, including language identifier
function convertToMarkdown(element) {
    let markdown = '';
    const nodes = element.childNodes;

    nodes.forEach(node => {
        if (node.nodeName === 'P') {
            markdown += `${node.innerText}\n\n`;
        } else if (node.nodeName === 'PRE') {
            const codeBlock = node.querySelector('code');
            const languageClass = codeBlock.className.match(/language-(\w+)/); // Extract language from class if available
            const language = languageClass ? languageClass[1] : ''; // Default to empty if no language found
            const codeText = codeBlock.innerText;

            // Add language identifier to the Markdown code block
            markdown += `\`\`\`${language}\n${codeText}\n\`\`\`\n\n`;
        }
    });

    return markdown;
}

// Displays an alert message with animation
function displayAlert(type, message) {
    const alertElement = document.getElementById(`${type}-alert`);
    alertElement.textContent = message;
    alertElement.style.display = 'flex'; // Show the alert
    alertElement.classList.remove('fade-out'); // Remove fade-out class if present
    alertElement.style.opacity = '1'; // Ensure it's fully visible

    // Automatically hide the alert after 3 seconds with animation
    setTimeout(() => {
        alertElement.classList.add('fade-out'); // Add fade-out class to trigger animation
        setTimeout(() => {
            alertElement.style.display = 'none'; // Hide after animation finishes
        }, 500); // Match this time to the animation duration
    }, 3000); // Show the alert for 3 seconds before hiding
}

// Handles error responses based on status code
function handleErrorResponse(status) {
    const messages = document.getElementById('messages');
    const lastMessage = messages.lastElementChild;

    if (status === 429) {
        displayAlert('error', 'Sorry, I am currently too busy at the moment!');
        // Remove the last user message if the status is 429
        if (lastMessage && lastMessage.classList.contains('user')) {
            messages.removeChild(lastMessage);
        }
    } else {
        displayMessage('Error: ' + status, 'assistant');
        // Remove the last user message for any other errors
        if (lastMessage && lastMessage.classList.contains('user')) {
            messages.removeChild(lastMessage);
        }
    }
}

// Helper function to reset the conversation on the server
async function sendResetRequest() {
    const response = await fetch('https://infer.x64.world/reset-conversation', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        }
    });
    return response;
}

// Resets the chat messages and optionally displays a success message
async function resetChat(displaySuccessMessage = true) {
    try {
        const response = await sendResetRequest();

        if (response.ok) {
            const messagesContainer = document.getElementById('messages');
            messagesContainer.innerHTML = ''; // Clear all messages

            if (displaySuccessMessage) {
                displayAlert('success', 'Messages Cleared!');
            }
        } else {
            displayAlert('error', 'Failed to reset conversation. Please try again.');
        }
    } catch (error) {
        displayAlert('error', 'An error occurred while resetting the conversation.');
    }
}

// Resets the chat on page load without displaying the success message
document.addEventListener('DOMContentLoaded', function () {
    resetChat(false);
});

function openWindow(url, windowName, width, height) {
    window.open(url, windowName, `width=${width},height=${height},menubar=no,toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes`);
}

function openGpuStats() {
    openWindow('https://raven-scott.fyi/smi.html', 'gpuStatsWindow', 800, 600);
}

function openLiveLog() {
    openWindow('https://llama-live-log.x64.world/', 'liveLogWindow', 600, 600);
}

function openTop() {
    openWindow('https://ai-top.x64.world/', 'liveLogGtopWindow', 800, 600);
}

function openNetdata() {
    openWindow('https://ai-monitor.x64.world/', 'netDataWindow', 800, 650);
}

function openAbout() {
    openWindow('https://raven-scott.fyi/about-rayai', 'aboutRAIWindow', 800, 650);
}