/**
 * WP Bootstrap Studio — Chat Panel
 * Handles the AI page builder chat interface in the editor.
 *
 * Large pages are generated in chunks. Each chunk is a separate
 * server request that fits within Vercel's 300s function limit.
 * The browser drives the continuation loop.
 *
 * EDITS are safe: they never auto-replace your content. The result
 * is shown in preview only, and you must click Accept to apply it.
 */
(function($) {
    'use strict';

    const $messages = $('#wpbs-chat-messages');
    const $input = $('#wpbs-chat-input');
    const $sendBtn = $('#wpbs-chat-send');
    const $loading = $('#wpbs-chat-loading');
    const $editMode = $('#wpbs-edit-mode');
    const $qualityTier = $('#wpbs-quality-tier');

    // Generated HTML storage
    let generatedHtml = '';
    // Stores the edit result pending user acceptance
    let pendingEditHtml = '';
    // Backup of the page HTML before the last edit
    let preEditHtml = '';
    // Track consecutive edit rejections — triggers visual QA after 2
    let rejectedEdits = 0;

    const MAX_CHUNKS = 8;

    /**
     * Add a message to the chat
     */
    function addMessage(content, type) {
        const cls = type === 'user' ? 'wpbs-msg-user' : type === 'error' ? 'wpbs-msg-error' : 'wpbs-msg-ai';
        const $msg = $('<div class="wpbs-chat-msg ' + cls + '"></div>').text(content);

        // Remove welcome message on first interaction
        $('.wpbs-chat-welcome').remove();

        $messages.append($msg);
        $messages.scrollTop($messages[0].scrollHeight);
        return $msg;
    }

    /**
     * Add a message with HTML content (for buttons)
     */
    function addHtmlMessage(html, type) {
        const cls = type === 'user' ? 'wpbs-msg-user' : type === 'error' ? 'wpbs-msg-error' : 'wpbs-msg-ai';
        const $msg = $('<div class="wpbs-chat-msg ' + cls + '"></div>').html(html);
        $('.wpbs-chat-welcome').remove();
        $messages.append($msg);
        $messages.scrollTop($messages[0].scrollHeight);
        return $msg;
    }

    /**
     * Update an existing message in place
     */
    function updateMessage($msg, content) {
        $msg.text(content);
        $messages.scrollTop($messages[0].scrollHeight);
    }

    /**
     * Send a generate or edit request with automatic continuation
     */
    async function sendRequest() {
        const prompt = $input.val().trim();
        if (!prompt) return;

        const isEdit = $editMode.is(':checked');

        addMessage(prompt, 'user');
        $input.val('');
        $loading.show();
        $sendBtn.prop('disabled', true);
        // Reset rejection counter on new prompt
        rejectedEdits = 0;

        try {
            if (isEdit) {
                await handleEditRequest(prompt);
            } else {
                await handleGenerateRequest(prompt);
            }
        } catch (err) {
            const msg = err.responseJSON?.error || err.statusText || 'Request failed';
            addMessage('Error: ' + msg, 'error');
        } finally {
            $loading.hide();
            $sendBtn.prop('disabled', false);
        }
    }

    /**
     * Assemble a unified HTML document: embed CSS in <style> and JS in <script>
     * so the API works with ONE complete document throughout the pipeline.
     */
    function assembleCompleteHtml(html, css, js) {
        let complete = '';
        if (css && css.trim()) {
            complete += '<style>\n' + css.trim() + '\n</style>\n\n';
        }
        complete += html;
        if (js && js.trim()) {
            complete += '\n\n<script>\n' + js.trim() + '\n<\/script>';
        }
        return complete;
    }

    /**
     * Handle an edit request — result shown in preview only, never auto-applied
     */
    async function handleEditRequest(prompt) {
        const currentHtml = getCurrentPageHtml();
        if (!currentHtml || !currentHtml.trim()) {
            addMessage('No existing content found. Uncheck "Edit existing content" to generate a new page.', 'error');
            return;
        }

        // Assemble unified HTML: embed CSS and JS into the document
        const assembledHtml = assembleCompleteHtml(
            currentHtml,
            $('textarea[name="_wpbs_custom_css"]').val() || '',
            $('textarea[name="_wpbs_custom_js"]').val() || ''
        );

        // Save original so we can restore it
        preEditHtml = currentHtml;
        pendingEditHtml = '';
        console.log('[wpbs] Edit starting. Original HTML length:', currentHtml.length, 'Assembled:', assembledHtml.length);

        const $status = addMessage('Editing...', 'ai');

        const editBody = {
            instructions: prompt,
            current_html: assembledHtml,
            post_id: wpbs.postId,
            tier: $qualityTier.val(),
        };
        if (rejectedEdits >= 2) {
            editBody.use_qa = true;
            addMessage('Visual QA enabled for better accuracy.', 'ai');
        }

        const response = await $.ajax({
            url: wpbs.restUrl + 'edit',
            method: 'POST',
            headers: { 'X-WP-Nonce': wpbs.nonce },
            contentType: 'application/json',
            data: JSON.stringify(editBody),
            timeout: 0,
        });

        if (!response.success || !response.html) {
            addMessage('Error: ' + (response.error || 'Unknown error'), 'error');
            return;
        }

        const editedHtml = response.html;
        const ops = response.operations;

        console.log('[wpbs] Edit complete. Original:', currentHtml.length, 'Result:', editedHtml.length);
        if (ops) {
            console.log('[wpbs] Operations:', ops.applied, 'applied,', ops.skipped, 'skipped');
        }

        // Show warning if result looks suspicious
        if (response.warning) {
            addMessage('Warning: ' + response.warning, 'error');
        }

        // Check if the result is identical (no changes made)
        if (editedHtml === assembledHtml) {
            updateMessage($status, 'No changes were made — the edit instructions may not have matched any content on the page.');
            return;
        }

        // Store pending edit — DO NOT update code editor yet
        pendingEditHtml = editedHtml;

        // Show edit result in preview only
        updatePreview(editedHtml);

        // Remove old accept/reject buttons if any
        $('.wpbs-edit-actions').remove();

        updateMessage($status, 'Edit preview ready. Review the preview below, then Accept or Reject:');

        // Add Accept / Reject buttons
        addHtmlMessage(
            '<button class="button button-primary wpbs-accept-edit" style="margin-right:8px;">Accept Edit</button>' +
            '<button class="button wpbs-reject-edit">Reject Edit</button>' +
            (ops ? '<br><small style="color:#888;margin-top:4px;display:inline-block;">' + ops.applied + ' change(s) applied' + (ops.skipped > 0 ? ', ' + ops.skipped + ' skipped' : '') + '</small>' : ''),
            'ai'
        );
    }

    /**
     * Handle a generate request with continuation loop
     */
    async function handleGenerateRequest(prompt) {
        let fullHtml = '';
        let complete = false;
        let chunk = 0;
        const $status = addMessage('Generating...', 'ai');

        while (!complete && chunk < MAX_CHUNKS) {
            chunk++;
            if (chunk > 1) {
                updateMessage($status, 'Generating... (part ' + chunk + ' of page)');
            }

            const body = {
                prompt: prompt,
                post_id: wpbs.postId,
                tier: $qualityTier.val(),
            };
            if (fullHtml) {
                body.continuation = fullHtml;
            }

            const response = await $.ajax({
                url: wpbs.restUrl + 'generate',
                method: 'POST',
                headers: { 'X-WP-Nonce': wpbs.nonce },
                contentType: 'application/json',
                data: JSON.stringify(body),
                timeout: 0,
            });

            if (response.success && response.html) {
                fullHtml += response.html;
                complete = response.complete !== false;
                updatePreview(fullHtml);
                updateCodeEditor(fullHtml);
            } else {
                addMessage('Error: ' + (response.error || 'Unknown error'), 'error');
                return;
            }
        }

        generatedHtml = fullHtml;

        if (complete) {
            updateMessage($status, 'Page generated! Check the Bootstrap Preview below. Click "Apply to Page" to save it.');
        } else {
            updateMessage($status, 'Page generated (may be partial — reached chunk limit). Check the Bootstrap Preview below.');
        }
    }

    // Accept edit — split unified HTML back into HTML + CSS/JS meta fields
    $(document).on('click', '.wpbs-accept-edit', function() {
        if (!pendingEditHtml) return;

        // Extract CSS/JS from the unified HTML and update meta boxes
        const { css, js, html } = extractAssets(pendingEditHtml);
        if (css) $('textarea[name="_wpbs_custom_css"]').val(css);
        if (js) $('textarea[name="_wpbs_custom_js"]').val(js);

        // Put clean HTML (without <style>/<script>) in the code editor
        updateCodeEditor(html);
        generatedHtml = html;
        pendingEditHtml = '';
        preEditHtml = '';
        $('.wpbs-edit-actions').remove();
        $(this).closest('.wpbs-chat-msg').remove();
        addMessage('Edit accepted! CSS and JS updated. Click "Apply to Page" to save it.', 'ai');
    });

    // Reject edit — restore original in preview and discard pending
    $(document).on('click', '.wpbs-reject-edit', function() {
        if (preEditHtml) {
            updatePreview(preEditHtml);
        }
        pendingEditHtml = '';
        preEditHtml = '';
        rejectedEdits++;
        $('.wpbs-edit-actions').remove();
        $(this).closest('.wpbs-chat-msg').remove();
        if (rejectedEdits >= 2) {
            addMessage('Edit rejected. Visual QA will be enabled on the next edit for better accuracy.', 'ai');
        } else {
            addMessage('Edit rejected. Original content preserved.', 'ai');
        }
    });

    /**
     * Get current page HTML from the WordPress editor
     */
    function getCurrentPageHtml() {
        const codeEditor = $('#wpbs-code-editor').val();
        if (codeEditor && codeEditor.trim()) return codeEditor;

        if (typeof wp !== 'undefined' && wp.data) {
            const content = wp.data.select('core/editor')?.getEditedPostContent();
            if (content) return content;
        }

        const $textarea = $('#content');
        if ($textarea.length) return $textarea.val();

        return generatedHtml || '';
    }

    /**
     * Update the preview iframe.
     * Extracts <style> blocks from the HTML and places them in <head>
     * for proper rendering (unified HTML may have embedded CSS).
     */
    function updatePreview(html) {
        const iframe = document.getElementById('wpbs-preview-frame');
        if (!iframe) return;

        // Extract <style> blocks from the HTML to place in <head>
        const styleBlocks = [];
        const cleanHtml = html.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, function(match) {
            styleBlocks.push(match);
            return '';
        });

        const doc = iframe.contentDocument || iframe.contentWindow.document;
        doc.open();
        doc.write(`<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="${wpbs.bootstrapCss}" rel="stylesheet">
    <link href="${wpbs.bootstrapIcons}" rel="stylesheet">
    <style>body { margin: 0; padding: 0; }</style>
    ${styleBlocks.join('\n    ')}
</head>
<body>${cleanHtml}<script src="${wpbs.bootstrapJs}"><\/script></body>
</html>`);
        doc.close();

        iframe.onload = function() {
            try {
                const height = iframe.contentDocument.body.scrollHeight;
                iframe.style.height = Math.max(600, height + 50) + 'px';
            } catch(e) {}
        };
    }

    /**
     * Update the code editor
     */
    function updateCodeEditor(html) {
        $('#wpbs-code-editor').val(html);
    }

    // Event handlers
    $sendBtn.on('click', sendRequest);

    $input.on('keydown', function(e) {
        if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
            sendRequest();
        }
    });

    // Preview size buttons
    $(document).on('click', '.wpbs-preview-size', function() {
        $('.wpbs-preview-size').removeClass('active');
        $(this).addClass('active');
        $('#wpbs-preview-frame').css('width', $(this).data('width'));
    });

    // Toggle code view
    $('#wpbs-toggle-code').on('click', function() {
        $('#wpbs-code-editor-wrapper').toggle();
        $('#wpbs-preview-frame').toggle();
    });

    /**
     * Extract <style> and <script> blocks from raw HTML.
     * Returns { css, js, html } where html has those tags removed.
     */
    function extractAssets(rawHtml) {
        let css = '';
        let js = '';

        // Extract all <style> blocks
        const styleRegex = /<style[^>]*>([\s\S]*?)<\/style>/gi;
        let match;
        while ((match = styleRegex.exec(rawHtml)) !== null) {
            css += match[1] + '\n';
        }

        // Extract all <script> blocks
        const scriptRegex = /<script[^>]*>([\s\S]*?)<\/script>/gi;
        while ((match = scriptRegex.exec(rawHtml)) !== null) {
            // Skip external script tags (ones with src attribute)
            if (/src\s*=/.test(match[0])) continue;
            js += match[1] + '\n';
        }

        // Remove style and inline script tags from the HTML
        let cleanHtml = rawHtml.replace(styleRegex, '').replace(/<script(?![^>]*\bsrc\s*=)[^>]*>[\s\S]*?<\/script>/gi, '').trim();

        return { css: css.trim(), js: js.trim(), html: cleanHtml };
    }

    // Apply HTML to page
    $('#wpbs-apply-html').on('click', async function() {
        const rawHtml = $('#wpbs-code-editor').val() || generatedHtml;
        if (!rawHtml || !rawHtml.trim()) {
            alert('No HTML to apply. Generate a page first.');
            return;
        }

        // Guard: warn if content looks empty/tiny
        const strippedLen = rawHtml.replace(/<[^>]*>/g, '').trim().length;
        if (strippedLen < 50) {
            if (!confirm('Warning: The page content appears to be empty or very short (' + strippedLen + ' characters of text). Are you sure you want to apply this?')) {
                return;
            }
        }

        const $btn = $(this);
        $btn.prop('disabled', true).text('Saving...');

        try {
            const { css, js, html } = extractAssets(rawHtml);

            // Fill the CSS and JS meta boxes — only overwrite if extracted content is non-empty
            // (edits may return HTML without <style>/<script> blocks, and we must not
            // wipe existing CSS/JS that's stored separately in the meta fields)
            if (css) $('textarea[name="_wpbs_custom_css"]').val(css);
            if (js) $('textarea[name="_wpbs_custom_js"]').val(js);

            // Put clean HTML into the Classic Editor
            const $textarea = $('#content');
            if ($textarea.length) {
                // Switch to Text/HTML tab if TinyMCE is active
                if (typeof switchEditors !== 'undefined') {
                    switchEditors.go('content', 'html');
                }
                $textarea.val(html);
            }

            // Save via WP REST API — only include meta fields that have content
            // to avoid wiping existing CSS/JS when the edit didn't touch them
            const meta = {};
            if (css) meta._wpbs_custom_css = css;
            if (js) meta._wpbs_custom_js = js;

            const postData = {
                content: html,
                meta,
            };

            await $.ajax({
                url: wpbs.wpRestUrl + wpbs.postType + '/' + wpbs.postId,
                method: 'POST',
                headers: { 'X-WP-Nonce': wpbs.nonce },
                contentType: 'application/json',
                data: JSON.stringify(postData),
            });

            addMessage('Page saved! CSS and JS applied. View your page to see the result.', 'ai');
        } catch (err) {
            const msg = err.responseJSON?.message || err.statusText || 'Save failed';
            addMessage('Error saving: ' + msg, 'error');
        } finally {
            $btn.prop('disabled', false).text('Apply to Page');
        }
    });

    // Load existing content into preview on page load
    $(document).ready(function() {
        const existingHtml = getCurrentPageHtml();
        if (existingHtml && existingHtml.trim()) {
            updatePreview(existingHtml);
            updateCodeEditor(existingHtml);
        }
    });

})(jQuery);
