// webvue.js
document.addEventListener('DOMContentLoaded', () => {

    // --- STATE MANAGEMENT ---
    let isEditMode = false;
    let selectedElement = null;
    let dragState = {
        isDragging: false,
        isResizing: false,
        isDraggingWindow: false,
        isScrubbing: false,
        targetWindow: null,
        scrubbingInput: null,
        initialX: 0, initialY: 0,
        offsetX: 0, offsetY: 0, // Untuk offset mouse di dalam elemen
        initialElWidth: 0, initialElHeight: 0,
        initialValue: 0
    };

    // --- DOM ELEMENT SELECTORS ---
    // Mengubah target canvas ke #app untuk Vue
    const editorCanvas = document.getElementById('app');
    const propertiesPanel = document.getElementById('properties-panel');
    const toolbox = document.getElementById('toolbox');
    const modeToggle = document.getElementById('mode-toggle');
    const saveButton = document.getElementById('save-button');
    const deleteButton = document.getElementById('delete-button');
    const resetButton = document.getElementById('reset-button');
    const exportButton = document.getElementById('export-button');
    const printButton = document.getElementById('print-button');
    const tabButtons = document.querySelectorAll('.ve-tab-button');
    const tabPanes = document.querySelectorAll('.ve-tab-pane');

    // BARU: Objek untuk menyimpan instance Vue yang dibuat secara dinamis
    const vueInstances = {};

    // BARU: Definisikan komponen Vue kustom kita
    const CustomVueComponent = {
        props: {
            message: {
                type: String,
                default: 'Kalkulator Sederhana'
            }
        },
        data() {
            return {
                num1: '', // Input pertama
                num2: '', // Input kedua
                operation: '+', // Operasi default
                result: null // Hasil perhitungan
            };
        },
        methods: {
            calculate() {
                const n1 = parseFloat(this.num1);
                const n2 = parseFloat(this.num2);
                if (isNaN(n1) || isNaN(n2)) {
                    this.result = 'Masukkan angka valid';
                    return;
                }
                switch (this.operation) {
                    case '+':
                        this.result = n1 + n2;
                        break;
                    case '-':
                        this.result = n1 - n2;
                        break;
                    case '*':
                        this.result = n1 * n2;
                        break;
                    case '/':
                        this.result = n2 !== 0 ? n1 / n2 : 'Tidak bisa membagi dengan 0';
                        break;
                    default:
                        this.result = 'Operasi tidak valid';
                }
            },
            clear() {
                this.num1 = '';
                this.num2 = '';
                this.operation = '+';
                this.result = null;
            }
        },
        template: `
        <div style="padding: 15px; border: 1px dashed blue; background-color: #e6f7ff; font-family: Arial, sans-serif;">
            <p><strong>{{ message }}</strong></p>
            <div style="margin-bottom: 10px;">
                <input v-model="num1" type="number" placeholder="Angka pertama" style="padding: 5px; margin-right: 5px; width: 120px;">
                <select v-model="operation" style="padding: 5px; margin-right: 5px;">
                    <option value="+">+</option>
                    <option value="-">-</option>
                    <option value="*">×</option>
                    <option value="/">÷</option>
                </select>
                <input v-model="num2" type="number" placeholder="Angka kedua" style="padding: 5px; width: 120px;">
            </div>
            <div style="margin-bottom: 10px;">
                <button @click="calculate" style="padding: 5px 10px; margin-right: 5px; background-color: #007BFF; color: white; border: none; border-radius: 4px;">Hitung</button>
                <button @click="clear" style="padding: 5px 10px; background-color: #6C757D; color: white; border: none; border-radius: 4px;">Reset</button>
            </div>
            <p v-if="result !== null">Hasil: {{ result }}</p>
        </div>
    `
    };

    // --- INITIALIZATION ---
    function init() {
        // adoptNativeElements(); // Tidak lagi relevan karena #app adalah root Vue
        loadState();
        setupEventListeners();
        enterViewMode();
        // BARU: Setelah loadState, scan ulang untuk komponen Vue yang disimpan
        editorCanvas.querySelectorAll('[data-vue-component="true"]').forEach(el => {
            mountVueComponent(el);
        });
    }

    // --- EVENT LISTENERS SETUP ---
    function setupEventListeners() {
        modeToggle.addEventListener('click', toggleEditMode);
        editorCanvas.addEventListener('mousedown', handleCanvasMouseDown);
        document.addEventListener('mousemove', handleDocumentMouseMove);
        document.addEventListener('mouseup', handleDocumentMouseUp);

        editorCanvas.addEventListener('contextmenu', (e) => {
            if (isEditMode && e.target === editorCanvas) {
                e.preventDefault();
                deselectElement();
            }
        });

        propertiesPanel.addEventListener('input', handlePropertyChange);
        propertiesPanel.addEventListener('mousedown', handleScrubberMouseDown);

        saveButton.addEventListener('click', saveState);
        deleteButton.addEventListener('click', deleteSelectedElement);
        resetButton.addEventListener('click', resetAllSettings);
        exportButton.addEventListener('click', exportToHtml);
        printButton.addEventListener('click', printPage);
        toolbox.addEventListener('click', handleToolboxClick);

        document.querySelectorAll('.ve-window-header').forEach(header => {
            header.addEventListener('mousedown', handleWindowDragStart);
        });

        tabButtons.forEach(button => {
            button.addEventListener('click', () => {
                tabButtons.forEach(btn => btn.classList.remove('ve-active'));
                tabPanes.forEach(pane => pane.classList.remove('ve-active'));
                button.classList.add('ve-active');
                document.getElementById(button.dataset.tab).classList.add('ve-active');
            });
        });
    }

    // --- MODE MANAGEMENT ---
    function toggleEditMode() {
        isEditMode = !isEditMode;
        isEditMode ? enterEditMode() : enterViewMode();
    }

    function enterEditMode() {
        document.body.classList.add('edit-mode');
        if (selectedElement) propertiesPanel.classList.remove('ve-hidden');
        toolbox.classList.remove('ve-hidden');
        modeToggle.querySelector('.fa-eye').style.display = 'none';
        modeToggle.querySelector('.fa-pencil').style.display = 'block';
        if (printButton) printButton.classList.remove('ve-hidden');

        // BARU: Unmount Vue instance saat masuk mode edit
        Object.values(vueInstances).forEach(app => {
            if (app && app._container) { // Periksa apakah app masih terpasang
                app.unmount();
                // Hapus konten yang dihasilkan Vue, simpan elemen induk aslinya
                const parent = app._container;
                parent.innerHTML = '';
                // Kembalikan placeholder jika diperlukan
                if (parent.dataset.vueComponentPlaceholder) {
                    parent.innerHTML = parent.dataset.vueComponentPlaceholder;
                }
            }
        });
        // Kosongkan instance setelah unmount semua
        for (const key in vueInstances) {
            delete vueInstances[key];
        }
    }

    function enterViewMode() {
        deselectElement();
        document.body.classList.remove('edit-mode');
        toolbox.classList.add('ve-hidden');
        if (propertiesPanel) propertiesPanel.classList.add('ve-hidden');
        modeToggle.querySelector('.fa-eye').style.display = 'block';
        modeToggle.querySelector('.fa-pencil').style.display = 'none';
        if (printButton) printButton.classList.add('ve-hidden');
        // Jalankan onRefresh scripts
        editorCanvas.querySelectorAll('[data-onrefresh]').forEach(el => {
            const onRefreshScript = el.dataset.onrefresh;
            if (onRefreshScript) {
                try {
                    const result = new Function(`return ${onRefreshScript}`).call(el);
                    el.innerHTML = result;
                } catch (err) { console.error(`Error executing onRefresh for #${el.id}:`, err); }
            }
        });

        // BARU: Mount Vue instance saat masuk mode lihat
        editorCanvas.querySelectorAll('[data-vue-component="true"]').forEach(el => {
            if (!vueInstances[el.id]) { // Mount hanya jika belum ada instance
                mountVueComponent(el);
            }
        });
    }

    // BARU: Fungsi untuk me-mount komponen Vue
    function mountVueComponent(element) {
        if (vueInstances[element.id]) {
            // Jika sudah ada, update props-nya
            vueInstances[element.id].componentProps.message = element.dataset.vueMessage || 'Pesan dari Komponen Vue';
            return;
        }

        // Simpan konten asli atau placeholder jika ada, sebelum diisi oleh Vue
        if (!element.dataset.vueComponentPlaceholder) {
            element.dataset.vueComponentPlaceholder = element.innerHTML || 'Ini adalah komponen Vue.';
        }
        element.innerHTML = ''; // Kosongkan elemen untuk Vue

        const app = Vue.createApp(CustomVueComponent, {
            message: element.dataset.vueMessage || 'Pesan dari Komponen Vue'
        });
        app.mount(element);
        vueInstances[element.id] = app;
        console.log(`Komponen Vue #${element.id} dimount.`);
    }


    // --- ELEMENT CREATION & DELETION ---
    function handleToolboxClick(e) {
        if (e.target.closest('button')) {
            const type = e.target.closest('button').dataset.type;
            let newElementState = {
                tag: type.toUpperCase(),
                id: `el-${Date.now()}`,
                style: `position: absolute; top: 100px; left: 100px; z-index: 10;`,
                innerHTML: `Elemen ${type} Baru`,
                attributes: {}
            };

            if (type === 'img') {
                newElementState.style += `width: 150px; height: 100px;`;
                newElementState.attributes.src = 'https://via.placeholder.com/150x100.png?text=Gambar+Baru';
                newElementState.innerHTML = '';
            }
            if (type === 'button') newElementState.style += `width: 120px; height: 40px;`;
            if (type === 'div') newElementState.style += `width: 150px; height: 150px; background-color: #ddeeff; border: 1px solid #ccc;`;
            if (type === 'label') newElementState.innerHTML = `Label Baru`;
            if (type === 'input') {
                newElementState.style += `width: 200px; height: 30px;`;
                newElementState.attributes.placeholder = `Masukkan teks...`;
                newElementState.innerHTML = '';
                newElementState.attributes.type = 'text';
            }
            // BARU: Menangani pembuatan komponen Vue
            if (type === 'vue-component') {
                newElementState.tag = 'DIV'; // Vue akan me-mount ke div ini
                newElementState.style = `position: absolute; top: 100px; left: 100px; width: 250px; height: 150px; z-index: 10;`;
                newElementState.innerHTML = 'Memuat Komponen Vue...';
                newElementState.attributes['data-vue-component'] = 'true'; // Penanda khusus
                newElementState.attributes['data-vue-message'] = 'Halo dari editor!'; // Default prop Vue
            }


            const newElement = createElementFromState(newElementState);

            const parentTarget = (selectedElement && selectedElement.tagName === 'DIV') ? selectedElement : editorCanvas;
            parentTarget.appendChild(newElement);

            selectElement(newElement);
        }
    }

    function deleteSelectedElement() {
        if (selectedElement && confirm('Anda yakin ingin menghapus elemen ini?')) {
            const elId = selectedElement.id;
            // BARU: Unmount Vue instance jika yang dihapus adalah komponen Vue
            if (vueInstances[elId]) {
                vueInstances[elId].unmount();
                delete vueInstances[elId];
                console.log(`Komponen Vue #${elId} diunmount.`);
            }
            selectedElement.remove();
            deselectElement();
            console.log(`Elemen #${elId} telah dihapus.`);
        }
    }

    function resetAllSettings() {
        if (confirm('Anda yakin ingin mereset semua perubahan? Tindakan ini akan menghapus data dari local storage dan memuat ulang halaman.')) {
            localStorage.removeItem('visualEditorState');
            // BARU: Unmount semua instance Vue sebelum reload
            Object.values(vueInstances).forEach(app => app.unmount());
            alert('Pengaturan telah direset. Halaman akan dimuat ulang.');
            location.reload();
        }
    }

    // --- ELEMENT SELECTION ---
    function selectElement(element) {
        if (selectedElement) selectedElement.classList.remove('selected');
        selectedElement = element;
        selectedElement.classList.add('selected');
        propertiesPanel.classList.remove('ve-hidden');

        const selectedIdSpan = document.getElementById('selected-element-id');
        if (selectedIdSpan) {
            selectedIdSpan.textContent = selectedElement.id;
        }

        updatePropertiesPanel();
    }

    function deselectElement() {
        if (selectedElement) selectedElement.classList.remove('selected');
        selectedElement = null;
        propertiesPanel.classList.add('ve-hidden');

        const selectedIdSpan = document.getElementById('selected-element-id');
        if (selectedIdSpan) {
            selectedIdSpan.textContent = 'Tidak ada';
        }
    }

    // --- DRAGGING, RESIZING & SCRUBBING LOGIC ---
    function handleWindowDragStart(e) {
        if (e.target.classList.contains('ve-window-header')) {
            dragState.isDraggingWindow = true;
            dragState.targetWindow = e.currentTarget.closest('.ve-floating-window');
            dragState.initialX = e.clientX - dragState.targetWindow.offsetLeft;
            dragState.initialY = e.clientY - dragState.targetWindow.offsetTop;
        }
    }

    function handleCanvasMouseDown(e) {
        if (!isEditMode) return;

        if (e.button === 2) {
            const target = e.target.closest('.editable-element');
            if (!target || !editorCanvas.contains(target)) {
                e.preventDefault();
                deselectElement();
            }
            return;
        }

        const target = e.target.closest('.editable-element');

        if (target && editorCanvas.contains(target)) {
            e.stopPropagation();

            if (selectedElement === target && e.offsetX >= target.offsetWidth - 12 && e.offsetY >= target.offsetHeight - 12) {
                dragState.isResizing = true;
                dragState.initialX = e.clientX;
                dragState.initialY = e.clientY;
                dragState.initialElWidth = target.offsetWidth;
                dragState.initialElHeight = target.offsetHeight;
            } else {
                dragState.isDragging = true;
                dragState.initialX = e.clientX;
                dragState.initialY = e.clientY;
                dragState.initialElLeft = target.offsetLeft;
                dragState.initialElTop = target.offsetTop;
            }
            selectElement(target);
        } else {
            // Do nothing on left-click on empty canvas
        }
    }


    function handleScrubberMouseDown(e) {
        if (!e.target.classList.contains('ve-scrubber')) return;
        e.preventDefault();

        dragState.isScrubbing = true;
        dragState.scrubbingInput = e.target.parentElement.querySelector('input');
        dragState.initialX = e.clientX;
        dragState.initialValue = parseFloat(dragState.scrubbingInput.value) || 0;
    }

    function handleDocumentMouseMove(e) {
        if (dragState.isDraggingWindow) {
            e.preventDefault();
            dragState.targetWindow.style.left = `${e.clientX - dragState.initialX}px`;
            dragState.targetWindow.style.top = `${e.clientY - dragState.initialY}px`;
        }

        if (dragState.isDragging && selectedElement) {
            e.preventDefault();

            const dx = e.clientX - dragState.initialX;
            const dy = e.clientY - dragState.initialY;

            const newLeft = dragState.initialElLeft + dx;
            const newTop = dragState.initialElTop + dy;

            selectedElement.style.left = `${newLeft}px`;
            selectedElement.style.top = `${newTop}px`;
            selectedElement.style.transform = '';
        }

        if (dragState.isResizing && selectedElement) {
            e.preventDefault();
            const dw = e.clientX - dragState.initialX;
            const dh = e.clientY - dragState.initialY;
            selectedElement.style.width = `${dragState.initialElWidth + dw > 20 ? dragState.initialElWidth + dw : 20}px`;
            selectedElement.style.height = `${dragState.initialElHeight + dh > 20 ? dragState.initialElHeight + dh : 20}px`;
        }

        if (dragState.isScrubbing) {
            e.preventDefault();
            const dx = e.clientX - dragState.initialX;
            let step = e.shiftKey ? 10 : 1;
            const newValue = Math.round(dragState.initialValue + (dx * step));
            dragState.scrubbingInput.value = newValue;
            dragState.scrubbingInput.dispatchEvent(new Event('input', { bubbles: true }));
        }
    }

    function handleDocumentMouseUp() {
        dragState.isDragging = false;
        dragState.isResizing = false;
        dragState.isDraggingWindow = false;
        dragState.isScrubbing = false;
        dragState.targetWindow = null;
        dragState.scrubbingInput = null;
    }

    // --- PROPERTIES PANEL LOGIC ---
    function handlePropertyChange(e) {
        if (!selectedElement) return;
        const propPath = e.target.dataset.prop;
        if (!propPath) return;

        let currentObject = selectedElement;
        const pathParts = propPath.split('.');

        // Menangani dataset properties secara khusus
        if (pathParts[0] === 'dataset') {
            const datasetKey = pathParts[1];
            selectedElement.dataset[datasetKey] = e.target.value;
            // BARU: Jika ini adalah komponen Vue, update props-nya secara langsung
            if (selectedElement.dataset.vueComponent === 'true' && datasetKey === 'vueMessage' && vueInstances[selectedElement.id]) {
                vueInstances[selectedElement.id].componentProps.message = e.target.value;
            }
            return;
        }

        if (propPath === 'innerHTML') {
            selectedElement.innerHTML = e.target.value;
            return;
        }
        if (propPath === 'src' && selectedElement.tagName === 'IMG') {
            selectedElement.src = e.target.value;
            return;
        }
        if (propPath === 'placeholder' && selectedElement.tagName === 'INPUT') {
            selectedElement.placeholder = e.target.value;
            return;
        }
        if (propPath === 'type' && selectedElement.tagName === 'INPUT') {
            selectedElement.type = e.target.value;
            return;
        }

        for (let i = 0; i < pathParts.length - 1; i++) {
            currentObject = currentObject[pathParts[i]];
        }
        const finalProp = pathParts[pathParts.length - 1];
        let value = e.target.value;

        if (e.target.type === 'number' && value && propPath.startsWith('style.')) {
            value += 'px';
        }

        currentObject[finalProp] = value;
    }

    function updatePropertiesPanel() {
        if (!selectedElement) return;

        propertiesPanel.querySelectorAll('.ve-prop-group').forEach(group => {
            const tags = group.dataset.forTag ? group.dataset.forTag.split(' ') : [];
            // BARU: Periksa juga untuk tag kustom seperti VUE-COMPONENT
            if (tags.length > 0) {
                if (selectedElement.dataset.vueComponent === 'true') {
                    group.hidden = !tags.includes('VUE-COMPONENT');
                } else {
                    group.hidden = !tags.includes(selectedElement.tagName);
                }
            } else {
                group.hidden = false; // Jika tidak ada data-for-tag, selalu tampilkan
            }
        });

        propertiesPanel.querySelectorAll('[data-prop]').forEach(input => {
            const propPath = input.dataset.prop;
            let currentObject = selectedElement;
            const pathParts = propPath.split('.');

            if (pathParts[0] === 'dataset') {
                const datasetKey = pathParts[1];
                input.value = selectedElement.dataset[datasetKey] || '';
                return;
            }

            if (propPath === 'innerHTML') {
                input.value = selectedElement.innerHTML;
                return;
            }
            if (propPath === 'src' && selectedElement.tagName === 'IMG') {
                input.value = selectedElement.src;
                return;
            }
            if (propPath === 'placeholder' && selectedElement.tagName === 'INPUT') {
                input.value = selectedElement.placeholder;
                return;
            }
            if (propPath === 'type' && selectedElement.tagName === 'INPUT') {
                input.value = selectedElement.type;
                return;
            }


            for (let i = 0; i < pathParts.length - 1; i++) {
                if (currentObject) {
                    currentObject = currentObject[pathParts[i]];
                } else {
                    currentObject = undefined;
                    break;
                }
            }

            if (!currentObject) {
                input.value = '';
                return;
            }

            const finalProp = pathParts[pathParts.length - 1];
            let value = currentObject[finalProp] || '';

            if (typeof value === 'string') {
                value = value.replace(/"/g, '').replace(/px$/, '');
            }

            if (input.type === 'range') {
                input.value = parseFloat(value) || 0;
            } else {
                input.value = value;
            }
        });
    }

    // --- DATA PERSISTENCE & EXPORT ---
    function saveState() {
        const canvasState = [];
        editorCanvas.querySelectorAll('.editable-element').forEach(el => {
            const elState = {
                tag: el.tagName,
                id: el.id,
                style: el.getAttribute('style'),
                // BARU: Simpan placeholder untuk komponen Vue
                innerHTML: el.dataset.vueComponent === 'true' ? (el.dataset.vueComponentPlaceholder || '') : el.innerHTML,
                parentId: el.parentElement.id === editorCanvas.id ? null : el.parentElement.id,
                attributes: {
                    'data-onrefresh': el.dataset.onrefresh || '',
                    'data-onclick': el.dataset.onclick || '',
                    // BARU: Simpan atribut data-vue-component
                    'data-vue-component': el.dataset.vueComponent || '',
                    'data-vue-message': el.dataset.vueMessage || ''
                }
            };
            if (el.tagName === 'IMG') elState.attributes.src = el.src;
            if (el.tagName === 'INPUT') {
                elState.attributes.placeholder = el.placeholder;
                elState.attributes.type = el.type;
            }

            canvasState.push(elState);
        });
        localStorage.setItem('visualEditorState', JSON.stringify(canvasState));
        alert('Pengaturan berhasil disimpan!');
    }

    function loadState() {
        const savedState = JSON.parse(localStorage.getItem('visualEditorState'));
        if (savedState && savedState.length > 0) {
            // Hapus elemen bawaan di dalam #app (kecuali elemen Vue asli seperti h1, pesan, nama)
            Array.from(editorCanvas.children).forEach(child => {
                // Pertahankan elemen yang bukan 'editable-element' atau yang berasal dari Vue app root
                if (!child.classList.contains('editable-element') && child.id !== 'halo' && child.tagName !== 'H1' && child.textContent.indexOf('{{pesan}}') === -1) {
                    child.remove();
                } else if (child.classList.contains('editable-element')) {
                    child.remove(); // Hapus yang sudah ada dari editor
                }
            });


            const elementMap = new Map();
            savedState.forEach(elState => {
                const el = createElementFromState(elState);
                elementMap.set(el.id, { el, elState });
            });

            elementMap.forEach(({ el, elState }) => {
                if (elState.parentId && elementMap.has(elState.parentId)) {
                    elementMap.get(elState.parentId).el.appendChild(el);
                } else {
                    editorCanvas.appendChild(el);
                }
            });
        }
    }

    function exportToHtml() {
        const clone = editorCanvas.cloneNode(true);

        clone.querySelectorAll('*').forEach(el => {
            el.classList.remove('editable-element', 'selected');
            el.removeAttribute('data-onrefresh');
            el.removeAttribute('data-onclick');
            // Hapus atribut data Vue yang digunakan editor
            el.removeAttribute('data-vue-component');
            el.removeAttribute('data-vue-message');
            el.removeAttribute('data-vue-component-placeholder');


            const onclickScript = el.dataset.onclick;
            if (onclickScript) {
                el.setAttribute('onclick', onclickScript);
            }
        });

        // BARU: Perlu menyertakan definisi komponen Vue di HTML hasil ekspor
        const vueComponentDefinition = `
        <script>
            const { createApp } = Vue;

            const CustomVueComponent = {
                props: {
                    message: {
                        type: String,
                        default: 'Pesan dari Komponen Vue'
                    }
                },
                data() {
                    return {
                        count: 0
                    };
                },
                template: \`
                    <div style="padding: 10px; border: 1px dashed blue; background-color: #e6f7ff;">
                        <p><strong>Komponen Vue Reaktif</strong></p>
                        <p>Pesan 3: {{ message }}</p>
                        <p>Hitungan: {{ count }}</p>
                        <button @click="count++">Tambah Hitungan</button>
                    </div>
                \`
            };

            // Cari semua elemen dengan data-vue-component="true" dan mount komponen Vue di sana
            document.querySelectorAll('[data-vue-component-export="true"]').forEach(element => {
                createApp(CustomVueComponent, {
                    message: element.dataset.vueMessageExport || 'Pesan dari Komponen Vue'
                }).mount(element);
            });
        </script>
        `;

        // BARU: Tandai komponen Vue yang akan diekspor agar Vue dapat me-mount-nya di file hasil ekspor
        clone.querySelectorAll('[data-vue-component="true"]').forEach(el => {
            el.setAttribute('data-vue-component-export', 'true');
            if (el.dataset.vueMessage) {
                el.setAttribute('data-vue-message-export', el.dataset.vueMessage);
            }
            // Hapus innerHTML sementara jika itu placeholder, biarkan Vue yang mengisi
            if (el.dataset.vueComponentPlaceholder) {
                el.innerHTML = ''; // Pastikan kosong agar Vue mengisi
            }
        });


        const htmlContent = `<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Halaman Hasil Ekspor</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <style>
        body { font-family: sans-serif; margin: 0; padding: 0; background-color: #f0f0f0; }
        #app { /* Menggunakan #app sesuai vue.html */
            width: 794px;
            min-height: 1123px;
            background-color: white;
            border: 1px solid #ccc;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            margin: 20px auto;
            position: relative;
            overflow: hidden;
            box-sizing: border-box;
        }
        .editable-element {
            position: absolute;
            box-sizing: border-box;
            min-width: 20px;
            min-height: 20px;
        }
        input[type="text"], input[type="number"], textarea, select {
            border: 1px solid #ccc;
            padding: 3px 6px;
            border-radius: 4px;
            font-size: 13px;
        }
    </style>
</head>
<body>
    ${clone.outerHTML}
    ${vueComponentDefinition} </body>
</html>`;

        const blob = new Blob([htmlContent], { type: 'text/html' });
        const a = document.createElement('a');
        a.href = URL.createObjectURL(blob);
        a.download = `halaman-ekspor-${Date.now()}.html`;
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(a.href);

        alert('HTML telah diekspor!');
    }

    function printPage() {
        window.print();
    }

    // Fungsi ini akan mencari elemen yang sudah ada di HTML dan menandainya sebagai editable
    function adoptNativeElements() {
        // Logika adoptNativeElements disesuaikan karena #app sekarang adalah root Vue
        // Kita hanya akan menandai elemen di dalam #app yang bukan bagian dari Vue root
        Array.from(editorCanvas.children).forEach(el => {
            // Lewati elemen yang sudah dikelola oleh root Vue (h1, pesan, halo)
            if (el.id === 'halo' || el.tagName === 'H1' || el.textContent.indexOf('{{pesan}}') !== -1) {
                // Pertahankan elemen ini sebagai Vue root, jangan buat editable-element
                // Atau bisa juga menandai mereka sebagai editable-element jika ingin diedit juga,
                // tapi ini akan membutuhkan integrasi Vue yang lebih mendalam untuk data binding mereka.
                // Untuk demo ini, kita biarkan saja sebagai elemen Vue asli di luar kendali editor.
                return;
            }

            if (el.closest('#tool, .ve-floating-window') || el.classList.contains('editable-element')) return;

            if (!el.id) {
                el.id = `el-native-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
            }
            el.classList.add('editable-element');
            if (!el.style.position) {
                el.style.position = 'absolute';
                el.style.top = `${el.offsetTop}px`;
                el.style.left = `${el.offsetLeft}px`;
            }
            addInteractiveListeners(el);
            // BARU: Jika ini elemen Vue yang sudah ada di HTML, mount
            if (el.dataset.vueComponent === 'true') {
                mountVueComponent(el);
            }
        });
    }

    function createElementFromState(state) {
        const el = document.createElement(state.tag);
        el.id = state.id;
        el.className = 'editable-element';
        if (state.style) el.setAttribute('style', state.style);

        // Jangan set innerHTML untuk IMG/INPUT atau elemen Vue yang akan diisi oleh Vue
        if (state.tag !== 'IMG' && state.tag !== 'INPUT' && state.attributes['data-vue-component'] !== 'true') {
            el.innerHTML = state.innerHTML;
        } else if (state.attributes['data-vue-component'] === 'true') {
            // Untuk komponen Vue, gunakan placeholder awal
            el.innerHTML = state.innerHTML || 'Memuat Komponen Vue...';
            el.dataset.vueComponentPlaceholder = state.innerHTML || 'Memuat Komponen Vue...';
        }

        for (const [key, value] of Object.entries(state.attributes)) {
            if (value) el.setAttribute(key, value);
        }
        addInteractiveListeners(el);

        // BARU: Jika ini adalah komponen Vue baru, mount langsung (di mode edit akan unmount segera)
        if (state.attributes['data-vue-component'] === 'true') {
            // Ini akan di-unmount saat masuk mode edit, dan di-mount ulang saat view mode.
            // Biarkan editor merender placeholder-nya dulu.
        }
        return el;
    }

    function addInteractiveListeners(el) {
        el.addEventListener('click', (e) => {
            if (!isEditMode && e.currentTarget === el) {
                const onclickScript = el.dataset.onclick;
                if (onclickScript) {
                    try {
                        new Function(onclickScript).call(el);
                    } catch (err) { console.error(`Error executing onClick for #${el.id}:`, err); }
                }
            }
        });
    }

    // --- START THE APP ---
    init();
});