console.log("Script execution started.");
// --- Global Variables ---
let generatedCode = [];
let currentCleanedCode = [];
let evolutionTimeline = [];
let activeTimelineIndex = -1;
let selectedVariationGridIndex = -1;
let currentFullscreenHistoryIndex = -1;
let originalUserPromptForCurrentGeneration = '';
let lastPreviewUpdateTime = [];
let previewUpdateInterval = 500;
let numVariationsToGenerate = 4;
let activeApiControllers = [];
let lastGenerationConfig = {
    prompt: '',
    isRefinement: false,
    numVariations: 4,
    refinedTimelineIndex: -1
};
// --- DOM Element References ---
let apiKeyEl, codeOutputEl, errorMessageEl;
let modelSelEl;
let selectButtons = [];
let fullscreenButtons = [];
let previewItems = [];
let refinementLoadingIndicator;
let mainContentEl, configButtonEl;
let intervalSliderEl, intervalValueDisplayEl;
let fullscreenOverlayEl, fullscreenIframeEl, exitFullscreenBtnEl;
let perspectiveViewportEl, previewGridWrapperEl;
let historyPanelEl, historyPanelPlaceholderEl;
let selectedCodeTitleH3El;
let mainContentTitleH1El, mainContentSubtitleH2El;
let fullscreenHistoryNavEl, historyNavPrevBtnEl, historyNavNextBtnEl;
let promptModalOverlayEl, promptModalContentEl, modalUserPromptEl, modalGenerateBtnEl, modalCancelBtnEl, modalLoadingIndicatorEl;
let modalRefinementCheckboxEl, numVariationsSliderEl, numVariationsValueDisplayEl;
let configModalOverlayEl, configModalContentEl, configModalCloseBtnEl, copyCodeButtonEl;
let historyToggleButtonEl, historyArrowDownEl, historyArrowUpEl;
let exportCodeButtonEl;
let newButtonEl;
let confirmModalOverlayEl, confirmModalMessageEl, confirmModalConfirmBtnEl, confirmModalCancelBtnEl;
let currentConfirmCallback = null;
let historyNavLeftBtnEl, historyNavRightBtnEl;
let promptDisplayModalOverlayEl, promptDisplayModalContentEl, fullPromptTextEl, promptDisplayModalCloseBtnEl;
let showPromptModalButtonEl; // Added for the new button
let modalContextSizeValueEl, modalMaxTokensValueEl, modalMaxTokensSliderEl; // Added for new modal elements
// --- Constants ---
const API_BASE_URL = 'https://api.novita.ai/v3/openai'; // New Novita API
const MODEL_DETAILS = {
    "deepseek/deepseek-v3-turbo": { context: 64000, maxOutput: 16000, defaultOutput: 8192 },
    "deepseek/deepseek-r1-turbo": { context: 64000, maxOutput: 16000, defaultOutput: 8192 },
    "qwen/qwen3-235b-a22b-fp8": { context: 128000, maxOutput: 128000, defaultOutput: 16384 },
    "qwen/qwen3-30b-a3b-fp8": { context: 128000, maxOutput: 128000, defaultOutput: 16384 },
    "qwen/qwen3-32b-fp8": { context: 128000, maxOutput: 128000, defaultOutput: 16384 },
    "google/gemma-3-27b-it": { context: 32000, maxOutput: 32000, defaultOutput: 8192 },
    "mistralai/mistral-nemo": { context: 131072, maxOutput: 131072, defaultOutput: 16384 },
    "meta-llama/llama-4-scout-17b-16e-instruct": { context: 131072, maxOutput: 131072, defaultOutput: 16384 },
    "meta-llama/llama-4-maverick-17b-128e-instruct-fp8": { context: 1048576, maxOutput: 1048576, defaultOutput: 16384 }
};
// --- Helper Function to Process Stream for One Variation ---
async function processStreamForVariation(apiKey, userPrompt, variationIndex, modelName, signal) {
    console.log(`[Variation ${variationIndex + 1}] Starting generation with model ${modelName}...`);
    const previewFrame = document.getElementById(`preview-frame-${variationIndex + 1}`);
    const loader = document.getElementById(`preview-loader-${variationIndex + 1}`);
    const selectBtn = selectButtons[variationIndex];
    const fullscreenBtn = fullscreenButtons[variationIndex];
    if (!previewFrame) { console.error(`[Variation ${variationIndex + 1}] Preview frame missing.`); return false; }
    if (!loader) { console.warn(`[Variation ${variationIndex + 1}] Loader missing.`); }
    if (loader) loader.classList.remove('hidden');
    if (selectBtn) selectBtn.disabled = true;
    if (fullscreenBtn) fullscreenBtn.disabled = true;
    if (previewFrame) updateLivePreviewInGrid(variationIndex, '
', false);
    if(lastPreviewUpdateTime[variationIndex] !== undefined) lastPreviewUpdateTime[variationIndex] = 0;
    const API_ENDPOINT = `${API_BASE_URL}/chat/completions`; // New Novita API endpoint
    let rawGeneratedCode = '';
    let htmlBlockStarted = false;
    let success = false;
    let isInsideThinkBlock = false; // Flag to track if we are inside a  block
    // Construct conversation history for Novita API
    // The prompt passed to this function (userPrompt) is already formatted with instructions and user request.
    const conversationHistory = [
        { role: "user", content: userPrompt }
    ];
    try {
        console.log(`[Variation ${variationIndex + 1}] Novita API call with model: ${modelName}`);
        const response = await fetch(API_ENDPOINT, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${apiKey}` // Novita uses Bearer token
            },
            body: JSON.stringify({
                model: modelName, // Model name for Novita
                messages: conversationHistory,
                stream: true,
                reasoning: { exclude: true }, // Added reasoning parameter
                max_tokens: parseInt(modalMaxTokensSliderEl.value, 10) // Send max_tokens
            }),
            signal: signal
        });
        if (!response.ok) {
            let errorDetails = `API Error: ${response.status} ${response.statusText}`;
            try { 
                const errorDataText = await response.text(); // Try to get text first for more detailed errors
                console.error(`[Variation ${variationIndex + 1}] Novita API Error Response Text:`, errorDataText);
                const errorData = JSON.parse(errorDataText); // Then try to parse as JSON
                errorDetails += ` - ${errorData?.error?.message || errorData?.detail || errorDataText || 'No specific message.'}`;
            } catch (e) { 
                errorDetails += ` - Could not parse error response.`;
            }
            throw new Error(errorDetails);
        }
        const reader = response.body.getReader();
        const decoder = new TextDecoder();
        let sseBuffer = ""; // Buffer for incomplete SSE messages
        let streamEnded = false;
        while (!streamEnded) {
            const { done, value } = await reader.read();
            if (done) {
                streamEnded = true;
                break;
            }
            sseBuffer += decoder.decode(value, { stream: true });
            let eolIndex;
            while ((eolIndex = sseBuffer.indexOf('\n')) >= 0) {
                const line = sseBuffer.substring(0, eolIndex).trim();
                sseBuffer = sseBuffer.substring(eolIndex + 1);
                if (line.startsWith('data: ')) {
                    const data = line.substring(6).trim();
                    if (data === '[DONE]') {
                        streamEnded = true;
                        break;
                    }
                    try {
                        const json = JSON.parse(data);
                        const deltaContent = json.choices?.[0]?.delta?.content;
                        
                        if (deltaContent) {
                            let currentChunk = deltaContent;
                            let processedChunkForThisDelta = '';
                            while (currentChunk.length > 0) {
                                if (isInsideThinkBlock) {
                                    const endThinkTagIndex = currentChunk.indexOf('');
                                    if (endThinkTagIndex !== -1) {
                                        // Found the end tag. Content after it is actual.
                                        processedChunkForThisDelta += currentChunk.substring(endThinkTagIndex + ''.length);
                                        isInsideThinkBlock = false;
                                        currentChunk = ''; // Current delta's relevant part processed
                                    } else {
                                        // Still inside think block, discard this part of the chunk
                                        currentChunk = ''; // Discard and move to next delta if any
                                    }
                                } else {
                                    const startThinkTagIndex = currentChunk.indexOf('');
                                    if (startThinkTagIndex !== -1) {
                                        // Found a start tag. Content before it is actual.
                                        processedChunkForThisDelta += currentChunk.substring(0, startThinkTagIndex);
                                        isInsideThinkBlock = true;
                                        // The rest of currentChunk starts after 
                                        currentChunk = currentChunk.substring(startThinkTagIndex + ''.length);
                                        // This remaining part of currentChunk will be re-evaluated in the next iteration
                                        // of this inner while loop, now with isInsideThinkBlock = true.
                                    } else {
                                        // No think tags, entire chunk is actual content
                                        processedChunkForThisDelta += currentChunk;
                                        currentChunk = '';
                                    }
                                }
                            }
                            if (processedChunkForThisDelta.length > 0) {
                                rawGeneratedCode += processedChunkForThisDelta;
                                // The htmlBlockStarted logic might need re-evaluation.
                                // For now, assume content is part of the HTML stream.
                                if (!htmlBlockStarted) {
                                    // Try to detect '```html' or start accumulating if it appears
                                    const marker = "```html";
                                    let tempAccumulated = rawGeneratedCode; // Use the cleaned rawGeneratedCode
                                    const markerIndex = tempAccumulated.indexOf(marker);
                                    if (markerIndex !== -1) {
                                        htmlBlockStarted = true;
                                        let codeStartIndex = markerIndex + marker.length;
                                        if (tempAccumulated[codeStartIndex] === '\n') {
                                            codeStartIndex++;
                                        }
                                        rawGeneratedCode = tempAccumulated.substring(codeStartIndex);
                                    } else if (tempAccumulated.trim().startsWith("= previewUpdateInterval)) {
                                        // Strip markdown for preview if still present at this stage
                                        let previewCode = rawGeneratedCode; // Use the cleaned rawGeneratedCode
                                        if (previewCode.includes("```html")) {
                                             previewCode = previewCode.substring(previewCode.indexOf("```html") + 7).trimStart();
                                        }
                                        if (previewCode.endsWith("```")) {
                                            previewCode = previewCode.substring(0, previewCode.length - 3).trimEnd();
                                        }
                                        updateLivePreviewInGrid(variationIndex, previewCode, true);
                                        lastPreviewUpdateTime[variationIndex] = now;
                                    }
                                }
                            }
                        }
                    } catch (e) { 
                        console.warn(`[Var ${variationIndex + 1}] JSON parse error in stream:`, e, "Problematic Line:", line, "Data:", data);
                    }
                }
            }
            if (streamEnded) break; // Exit outer loop if [DONE] was processed
        }
        console.log(`[Variation ${variationIndex + 1}] Streaming finished. Raw content length: ${rawGeneratedCode.length}`);
        let finalExtractedHtml = null; 
        let processingErrorMessage = null; 
        // Process the rawGeneratedCode after stream ends
        // This needs to handle potential markdown ```html ... ``` blocks
        let tempHtml = rawGeneratedCode.trim();
        const htmlMarker = "```html";
        const markerIndex = tempHtml.indexOf(htmlMarker);
        if (markerIndex !== -1) {
            htmlBlockStarted = true; // Confirm block started if marker found
            tempHtml = tempHtml.substring(markerIndex + htmlMarker.length).trimStart();
        }
        // Remove trailing ``` if present
        if (tempHtml.endsWith("```")) {
            tempHtml = tempHtml.substring(0, tempHtml.length - 3).trimEnd();
        }
        // If no ```html was found, but it looks like html, use it directly
        if (!htmlBlockStarted && (tempHtml.startsWith(" 0) {
            finalExtractedHtml = tempHtml;
            const minLength = 20;
            const hasStructuralTag = /]*>|]*>|]*>/i.test(finalExtractedHtml);
            const hasAnyTag = /<[a-zA-Z][^>]*>/.test(finalExtractedHtml);
            if (finalExtractedHtml.length >= minLength && (hasStructuralTag || hasAnyTag)) {
                success = true;
                console.log(`[Variation ${variationIndex + 1}] HTML validation SUCCEEDED.`);
            } else {
                success = false; 
                console.warn("[Variation " + (variationIndex + 1) + "] HTML validation FAILED (length: " + finalExtractedHtml.length + ", structural: " + hasStructuralTag + ", anyTag: " + hasAnyTag + "). Review content manually.");
                processingErrorMessage = "// Warning: Generated content did not pass basic HTML validation.";
                if (!finalExtractedHtml) finalExtractedHtml = processingErrorMessage; // Ensure some content for display
            }
        } else if (tempHtml.length > 0 && !htmlBlockStarted) { // Content received but not identified as HTML block
             processingErrorMessage = `// Warning: Content received, but 'Written by Novita AI' or similar marker not found, or content doesn't look like HTML. Length: ${tempHtml.length}`;
             console.warn(`[Variation ${variationIndex + 1}] ${processingErrorMessage}`);
             finalExtractedHtml = tempHtml; // Display what was received
             success = false; // Treat as not fully successful if not identified as clean HTML
        } else {
            processingErrorMessage = `// Error: No meaningful content generated or 'Written by Novita AI' marker not found.`;
            console.warn(`[Variation ${variationIndex + 1}] ${processingErrorMessage}`);
            finalExtractedHtml = processingErrorMessage; // Show error message
            success = false;
        }
        if (success && finalExtractedHtml) {
            let processedHtml = finalExtractedHtml;
            const requiredHeadContent = `
                        
                        
                         blocks (that are not JSON-LD or other non-executable script types). If no functional