// Initialize Fabric Canvas
const canvas = new fabric.Canvas('c', {
    preserveObjectStacking: true, // Keep selection on top
    selection: true
});

// --- Custom Selection Controls ---
// We need to ensure controls are visible even if we customize them
fabric.Object.prototype.set({
    transparentCorners: false,     
    cornerColor: '#ffffff',        
    cornerStrokeColor: '#4f46e5',  
    borderColor: '#4f46e5',        
    cornerSize: 12,                
    padding: 10,                   
    cornerStyle: 'circle',         
    borderDashArray: [4, 4],
    borderScaleFactor: 2 // Thicker selection border
});

// --- Override toObject to include custom 'name' property in JSON ---
const originalToObject = fabric.Object.prototype.toObject;
fabric.Object.prototype.toObject = function(propertiesToInclude) {
    propertiesToInclude = propertiesToInclude || [];
    if (!propertiesToInclude.includes('name')) {
        propertiesToInclude.push('name');
    }
    if (!propertiesToInclude.includes('isButton')) {
        propertiesToInclude.push('isButton');
    }
    const obj = originalToObject.call(this, propertiesToInclude);
    // Ensure name is always included in the serialized object
    if (this.name !== undefined && this.name !== null) {
        obj.name = this.name;
    }
    return obj;
};

// --- Data: Presets ---
const gradients = [
    { name: 'Hyper', c1: '#ec4899', c2: '#8b5cf6' },
    { name: 'Ocean', c1: '#06b6d4', c2: '#3b82f6' },
    { name: 'Sunset', c1: '#f97316', c2: '#db2777' },
    { name: 'Forest', c1: '#84cc16', c2: '#15803d' },
    { name: 'Night', c1: '#1e293b', c2: '#0f172a' },
    { name: 'Laravel', c1: '#1e1e2e', c2: '#d63384' },
    { name: 'Peach', c1: '#fca5a5', c2: '#fcd34d' },
    { name: 'Gray', c1: '#f3f4f6', c2: '#d1d5db' },
    { name: 'Aurora', c1: '#22d3ee', c2: '#34d399' },
    { name: 'Candy', c1: '#f472b6', c2: '#60a5fa' },
    { name: 'Mint', c1: '#a7f3d0', c2: '#14b8a6' },
    { name: 'Royal', c1: '#6366f1', c2: '#f59e0b' }
];

const colorPalettes = [
    '#ffffff', '#000000', '#1f2937', '#dc2626', 
    '#ea580c', '#d97706', '#65a30d', '#059669',
    '#0891b2', '#2563eb', '#4f46e5', '#7c3aed',
    '#db2777', '#e11d48', '#f59e0b', '#10b981'
];

const fontFamilies = [
    { name: 'Inter', family: 'Inter', type: 'Sans' },
    { name: 'Roboto', family: 'Roboto', type: 'Sans' },
    { name: 'Montserrat', family: 'Montserrat', type: 'Sans' },
    { name: 'Oswald', family: 'Oswald', type: 'Display' },
    { name: 'Bebas Neue', family: 'Bebas Neue', type: 'Display' },
    { name: 'Playfair Display', family: 'Playfair Display', type: 'Serif' },
    { name: 'Abril Fatface', family: 'Abril Fatface', type: 'Display' },
    { name: 'Lobster', family: 'Lobster', type: 'Cursive' },
    { name: 'Pacifico', family: 'Pacifico', type: 'Hand' },
    { name: 'Dancing Script', family: 'Dancing Script', type: 'Hand' },
    { name: 'Space Mono', family: 'Space Mono', type: 'Mono' },
];

const emojiCategories = {
    "Smileys & People": ["😀", "😃", "😄", "😁", "😆", "😅", "🤣", "😂", "🙂", "🙃", "😉", "😊", "😇", "🥰", "😍", "🤩", "😘", "😗", "😚", "😙", "😋", "😛", "😜", "🤪", "😝", "🤑", "🤗", "🤭", "🤫", "🤔", "🤐", "🤨", "😐", "😑", "😶", "😏", "😒", "🙄", "😬", "🤥", "😌", "😔", "😪", "🤤", "😴", "😷", "🤒", "🤕", "🤢", "🤮", "🤧", "🥵", "🥶", "🥴", "😵", "🤯", "🤠", "🥳", "😎", "🤓", "🧐", "😕", "😟", "🙁", "☹️", "😮", "😯", "😲", "😳", "🥺", "😦", "😧", "😨", "😰", "😥", "😢", "😭", "😱", "😖", "😣", "😞", "😓", "😩", "😫", "🥱", "😤", "😡", "😠", "🤬", "😈", "👿", "💀", "☠️", "💩", "🤡", "👹", "👺", "👻", "👽", "👾", "🤖", "😺", "😸", "😹", "😻", "😼", "😽", "🙀", "😿", "😾", "👋", "🤚", "🖐", "✋", "🖖", "👌", "🤏", "✌️", "🤞", "🤟", "🤘", "🤙", "👈", "👉", "👆", "🖕", "👇", "☝️", "👍", "👎", "✊", "👊", "🤛", "🤜", "👏", "🙌", "👐", "🤲", "🤝", "🙏", "✍️", "💅", "🤳", "💪", "🦾", "🦵", "🦿", "🦶", "👂", "🦻", "👃", "🧠", "🦷", "🦴", "👀", "👁", "👅", "👄", "💋", "🩸"],
    "Animals & Nature": ["🐶", "🐱", "🐭", "🐹", "🐰", "🦊", "🐻", "🐼", "🐨", "🐯", "🦁", "🐮", "🐷", "🐽", "🐸", "🐵", "🐵", "🙉", "🙊", "🐒", "🐔", "🐧", "🐦", "🐤", "🐣", "🐥", "🦆", "🦅", "🦉", "🦇", "🐺", "🐗", "🐴", "🦄", "🐝", "🐛", "🦋", "🐌", "🐞", "🐜", "🦟", "🦗", "🕷", "🕸", "🦂", "🐢", "🐍", "🦎", "🦖", "🦕", "🐙", "🦑", "🦐", "🦞", "🦀", "🐡", "🐠", "🐟", "🐬", "🐳", "🐋", "🦈", "🐊", "🐅", "🐆", "🦓", "🦍", "🦧", "🦣", "🐘", "🦛", "🦏", "🐪", "🐫", "🦒", "🦘", "🦬", "🐃", "🐂", "🐄", "🐎", "🐖", "🐏", "🐑", "🦙", "🐐", "🦌", "🐕", "🐩", "🦮", "🐕‍🦺", "🐈", "🐈‍⬛", "🐓", "🦃", "🦚", "🦜", "🦢", "🦩", "🕊", "🐇", "🦝", "🦨", "🦡", "🦫", "🦦", "🦥", "🐁", "🐀", "🐿", "🦔", "🐾", "🐉", "🐲", "🌵", "🎄", "🌲", "🌳", "🌴", "🌱", "🌿", "☘️", "🍀", "🎍", "🎋", "🍃", "🍂", "🍁", "🍄", "🐚", "🌾", "💐", "🌷", "🌹", "🥀", "🌺", "🌸", "🌼", "🌻", "🌞", "🌝", "🌛", "🌜", "🌚", "🌕", "🌖", "🌗", "🌘", "🌑", "🌒", "🌓", "🌔", "🌙", "🌎", "🌍", "🌏", "🪐", "💫", "⭐️", "🌟", "✨", "⚡️", "☄️", "💥", "🔥", "🌪", "🌈", "☀️", "🌤", "⛅️", "🌥", "☁️", "🌦", "🌧", "⛈", "🌩", "🌨", "❄️", "☃️", "⛄️", "🌬", "💨", "💧", "💦", "☔️", "☂️", "🌊", "🌫"],
    "Food & Drink": ["🍏", "🍎", "🍐", "🍊", "🍋", "🍌", "🍉", "🍇", "🍓", "🍈", "🍒", "🍑", "🥭", "🍍", "🥥", "🥝", "🍅", "🍆", "🥑", "🥦", "🥬", "🥒", "🌶", "🌽", "🥕", "🧄", "🧅", "🥔", "🍠", "🥐", "🥯", "🍞", "🥖", "🥨", "🧀", "🥚", "🍳", "🧈", "🥞", "🧇", "🥓", "🥩", "🍗", "🍖", "🦴", "🌭", "🍔", "🍟", "🍕", "🥪", "🥙", "🧆", "🌮", "🌯", "🥗", "🥘", "🥫", "🍝", "🍜", "🍲", "🍛", "🍣", "🍱", "🥟", "🦪", "🍤", "🍙", "🍚", "🍘", "🍥", "🥠", "🥮", "🍢", "🍡", "🍧", "🍨", "🍦", "🥧", "🧁", "🍰", "🎂", "🍮", "🍭", "🍬", "🍫", "🍿", "🍩", "🍪", "🌰", "🥜", "🍯", "🥛", "🍼", "☕️", "🍵", "🧃", "🥤", "🍶", "🍺", "🍻", "🥂", "🍷", "🥃", "🍸", "🍹", "🧉", "🍾", "🧊", "🥄", "🍴", "🍽", "🥣", "🥡", "🥢", "🧂"],
    "Objects": ["⌚️", "📱", "📲", "💻", "⌨️", "🖥", "🖨", "🖱", "🖲", "🕹", "🗜", "💽", "💾", "💿", "📀", "📼", "📷", "📸", "📹", "🎥", "📽", "🎞", "📞", "☎️", "📟", "📠", "📺", "📻", "🎙", "🎚", "🎛", "🧭", "⏱", "⏲", "⏰", "🕰", "⌛️", "⏳", "📡", "🔋", "🔌", "💡", "🔦", "🕯", "🪔", "🧯", "🛢", "💸", "💵", "💴", "💶", "💷", "💰", "💳", "💎", "⚖️", "🧰", "🔧", "🔨", "⚒", "🛠", "⛏", "🪓", "🔩", "⚙️", "⛓", "🔫", "💣", "🧨", "🔪", "🗡", "⚔️", "🛡", "🚬", "⚰️", "⚱️", "🏺", "🔮", "📿", "🧿", "💈", "⚗️", "🔭", "🔬", "🕳", "🩹", "🩺", "💊", "💉", "🩸", "🧬", "🦠", "🧫", "🧪", "🌡", "🧹", "🧺", "🧻", "🚽", "🚰", "🚿", "🛁", "🛀", "🧼", "🪒", "🧽", "🧴", "🔑", "🗝", "🚪", "🪑", "🛋", "🛏", "🛌", "🧸", "🖼", "🛍", "🛒", "🎁", "🎈", "🎏", "🎀", "🎊", "🎉", "🎎", "🏮", "🎐", "🧧", "✉️", "📩", "📨", "📧", "💌", "📥", "📤", "📦", "🏷", "📪", "📫", "📬", "📭", "📮", "📯", "📜", "📃", "📄", "📑", "🧾", "📊", "📈", "📉", "🗒", "🗓", "📆", "📅", "🗑", "📇", "🗃", "🗳", "🗄", "📋", "📁", "📂", "🗂", "🗞", "📰", "📓", "📔", "📒", "📕", "📗", "📘", "📙", "📚", "📖", "🔖", "🧷", "🔗", "📎", "🖇", "📐", "📏", "🧮", "📌", "📍", "✂️", "🖊", "🖋", "✒️", "🖌", "🖍", "📝", "✏️", "🔍", "🔎", "🔏", "🔐", "🔒", "🔓"],
    "Symbols": ["❤️", "🧡", "💛", "💚", "💙", "💜", "🖤", "🤍", "🤎", "💔", "❣️", "💕", "💞", "💓", "💗", "💖", "💘", "💝", "💟", "☮️", "✝️", "☪️", "🕉", "☸️", "✡️", "🔯", "🕎", "☯️", "☦️", "🛐", "⛎", "♈️", "♉️", "♊️", "♋️", "♌️", "♍️", "♎️", "♏️", "♐️", "♑️", "♒️", "♓️", "🆔", "⚛️", "🉑", "☢️", "☣️", "📴", "📳", "🈶", "🈚️", "🈸", "🈺", "🈷️", "✴️", "🆚", "💮", "🉐", "㊙️", "㊗️", "🈴", "🈵", "🈹", "🈲", "🅰️", "🅱️", "🆎", "🆑", "🅾️", "🆘", "❌", "⭕️", "🛑", "⛔️", "📛", "🚫", "💯", "💢", "♨️", "🚷", "🚯", "🚳", "🚱", "🔞", "📵", "🚭", "❗️", "❕", "❓", "❔", "‼️", "⁉️", "🔅", "🔆", "〽️", "⚠️", "🚸", "🔱", "⚜️", "🔰", "♻️", "✅", "🈯️", "💹", "❇️", "✳️", "❎", "🌐", "💠", "Ⓜ️", "🌀", "💤", "🏧", "🚾", "♿️", "🅿️", "🈳", "🈂️", "🛂", "🛃", "🛄", "🛅", "🚹", "🚺", "🚼", "🚻", "🚮", "🎦", "📶", "🈁", "🔣", "ℹ️", "🔤", "🔡", "🔠", "🆖", "🆗", "🆙", "🆒", "🆕", "🆓", "0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣", "🔟", "🔢", "#️⃣", "*️⃣", "⏏️", "▶️", "⏸", "⏯", "⏹", "⏺", "⏭", "⏮", "⏩", "⏪", "⏫", "⏬", "◀️", "🔼", "🔽", "➡️", "⬅️", "⬆️", "⬇️", "↗️", "↘️", "↙️", "↖️", "↕️", "↔️", "↪️", "↩️", "⤴️", "⤵️", "🔀", "🔁", "🔂", "🔄", "🔃", "🎵", "🎶", "➕", "➖", "➗", "✖️", "♾", "💲", "💱", "™️", "©️", "®️", "👁‍🗨", "🔚", "🔙", "🔛", "🔝", "🔜", "〰️", "➰", "➿", "✔️", "☑️", "🔘", "🔴", "🟠", "🟡", "🟢", "🔵", "🟣", "⚫️", "⚪️", "🟤", "🔺", "🔻", "🔸", "🔹", "🔶", "🔷", "🔳", "🔲", "▪️", "▫️", "◾️", "◽️", "◼️", "◻️", "🟥", "🟧", "🟨", "🟩", "🟦", "🟪", "⬛️", "⬜️", "🟫", "🔈", "🔇", "🔉", "🔊", "🔔", "🔕", "📣", "📢", "💬", "💭", "🗯", "♠️", "♣️", "♥️", "♦️", "🃏", "🎴", "🀄️", "🕐", "🕑", "🕒", "🕓", "🕔", "🕕", "🕖", "🕗", "🕘", "🕙", "🕚", "🕛", "🕜", "🕝", "🕞", "🕟", "🕠", "🕡", "🕢", "🕣", "🕤", "🕥", "🕦", "🕧"]
};

// --- State Management ---
let activeObject = null;
let objectNameCounter = { text: 0, shape: 0, image: 0, emoji: 0, code: 0, qrcode: 0 };

// State: Canvas Dimensions & Zoom
let artboardBase = { w: 1200, h: 675 };
let zoomLevel = 1;

// --- Multi-Page State ---
let pages = [];
let currentPageId = null;
let pageCounter = 0;

// --- Clipboard State ---
let clipboardData = null;

// --- Copy/Paste Functions ---
function generateUniqueCopyName(originalName) {
    if (!originalName) return generateDefaultName('object');
    
    // Get all existing object names on canvas
    const existingNames = canvas.getObjects()
        .filter(obj => obj.name)
        .map(obj => obj.name);
    
    // Check if original name already ends with _copy or _copyN
    const copyPattern = /^(.+?)(_copy(\d+)?)?$/;
    const match = originalName.match(copyPattern);
    const baseName = match ? match[1] : originalName;
    
    // Find the next available copy number
    let copyNum = 1;
    let newName = `${baseName}_copy`;
    
    while (existingNames.includes(newName)) {
        copyNum++;
        newName = `${baseName}_copy${copyNum}`;
    }
    
    return newName;
}

function copySelection() {
    const activeObj = canvas.getActiveObject();
    if (!activeObj) return;
    
    // Clone the object(s)
    activeObj.clone((cloned) => {
        clipboardData = cloned;
        
        // Also send to native pasteboard if available
        if (window.webkit?.messageHandlers?.nativeCopy) {
            const json = JSON.stringify(cloned.toJSON(['name', 'isButton']));
            window.webkit.messageHandlers.nativeCopy.postMessage({ data: json });
        }
        
        console.log('📋 Copied to clipboard');
    }, ['name', 'isButton']);
}

function cutSelection() {
    const activeObj = canvas.getActiveObject();
    if (!activeObj) return;
    
    copySelection();
    
    // Small delay to ensure copy completes before removing
    setTimeout(() => {
        canvas.remove(activeObj);
        canvas.discardActiveObject();
        canvas.requestRenderAll();
        triggerSave();
        console.log('✂️ Cut to clipboard');
    }, 50);
}

function pasteFromClipboard() {
    if (!clipboardData) {
        // Try to get from native pasteboard
        if (window.webkit?.messageHandlers?.nativePaste) {
            window.webkit.messageHandlers.nativePaste.postMessage({});
        }
        return;
    }
    
    pasteObject(clipboardData);
}

function pasteObject(obj) {
    obj.clone((clonedObj) => {
        canvas.discardActiveObject();
        
        // Offset the pasted object slightly
        clonedObj.set({
            left: clonedObj.left + 20,
            top: clonedObj.top + 20,
            evented: true,
        });
        
        // Generate unique name based on original with _copy suffix
        if (clonedObj.type === 'activeSelection') {
            // Multiple objects selected
            clonedObj.canvas = canvas;
            clonedObj.forEachObject((obj) => {
                obj.name = generateUniqueCopyName(obj.name);
                canvas.add(obj);
            });
            clonedObj.setCoords();
        } else {
            clonedObj.name = generateUniqueCopyName(clonedObj.name);
            canvas.add(clonedObj);
        }
        
        // Update clipboard offset for next paste
        clipboardData.top += 20;
        clipboardData.left += 20;
        
        canvas.setActiveObject(clonedObj);
        canvas.requestRenderAll();
        triggerSave();
        console.log('📥 Pasted from clipboard');
    }, ['name', 'isButton']);
}

// Handle paste from native pasteboard (called from Swift)
window.handleNativePasteContent = function(jsonString) {
    try {
        const parsed = JSON.parse(jsonString);
        
        fabric.util.enlivenObjects([parsed], (objects) => {
            if (objects.length > 0) {
                const obj = objects[0];
                clipboardData = obj;
                pasteObject(obj);
            }
        });
    } catch (e) {
        console.log('⚠️ Could not parse clipboard data:', e);
    }
};

// Generate unique page ID
function generatePageId() {
    pageCounter++;
    return `page_${pageCounter}_${Date.now()}`;
}

// Create a new page object with given or default settings
function createPageObject(options = {}) {
    const id = generatePageId();
    return {
        id: id,
        name: options.name || `Page ${pages.length + 1}`,
        artboardBase: options.artboardBase || { w: 1200, h: 675 },
        background: options.background || {
            type: 'gradient',
            color1: '#4f46e5',
            color2: '#ec4899',
            direction: 'to right',
            solidColor: '#4f46e5'
        },
        fabric: options.fabric || { version: fabric.version, objects: [] }
    };
}

// Get current page state (serialize current canvas to page object)
function getCurrentPageState() {
    // Temporarily remove guidelines for serialization
    const guidelines = canvas.getObjects().filter(obj => obj.name?.startsWith('__guideline'));
    guidelines.forEach(guideline => canvas.remove(guideline));
    
    const canvasJson = canvas.toJSON();
    
    // Restore guidelines
    guidelines.forEach(guideline => {
        canvas.add(guideline);
        canvas.moveTo(guideline, 0);
    });
    
    return {
        artboardBase: { ...artboardBase },
        background: {
            type: bgType,
            color1: bgColor1 ? bgColor1.value : '#4f46e5',
            color2: bgColor2 ? bgColor2.value : '#ec4899',
            direction: bgDirection ? bgDirection.value : 'to right',
            solidColor: bgSolidColor ? bgSolidColor.value : '#4f46e5'
        },
        fabric: canvasJson
    };
}

// Save current canvas state to the current page in pages array
function saveCurrentPageToArray() {
    if (!currentPageId) return;
    
    const pageIndex = pages.findIndex(p => p.id === currentPageId);
    if (pageIndex === -1) return;
    
    const currentState = getCurrentPageState();
    pages[pageIndex] = {
        ...pages[pageIndex],
        artboardBase: currentState.artboardBase,
        background: currentState.background,
        fabric: currentState.fabric
    };
}

// Helper function to generate default names (ensures safe format)
function generateDefaultName(type) {
    const typeMap = {
        'i-text': 'text',
        'text': 'text',
        'textbox': 'text',
        'rect': 'shape',
        'circle': 'shape',
        'path': 'shape',
        'polygon': 'shape',
        'image': 'image',
        'emoji': 'emoji',
        'code': 'code',
        'group': 'group',
        'qrcode': 'qrcode'
    };
    const category = typeMap[type] || (type === 'group' ? 'group' : 'object');
    objectNameCounter[category] = (objectNameCounter[category] || 0) + 1;
    // Ensure generated name is safe (alphanumeric and underscore only)
    return `${category}_${objectNameCounter[category]}`;
}

// Helper function to sanitize object names
function sanitizeObjectName(name) {
    if (!name) return '';
    // Remove any invalid characters, only keep alphanumeric and underscore
    return name.replace(/[^a-zA-Z0-9_]/g, '');
}

// --- DOM Elements (Getters with checks) ---
const getEl = (id) => document.getElementById(id);

// Import / Export
const exportJsonBtn = getEl('exportJsonBtn');
const importJsonBtn = getEl('importJsonBtn');
const jsonInput = getEl('jsonInput');
const undoBtn = getEl('undoBtn');
const redoBtn = getEl('redoBtn');

// Rotation
const rotationInput = getEl('rotationInput');
const rotationValue = getEl('rotationValue');

// Canvas Resizing
const canvasPreset = getEl('canvasPreset');
const canvasWidthInput = getEl('canvasWidth');
const canvasHeightInput = getEl('canvasHeight');
const canvasSizeLabel = getEl('canvasSizeLabel');

// Zoom
const zoomInBtn = getEl('zoomInBtn');
const zoomOutBtn = getEl('zoomOutBtn');
const zoomDisplay = getEl('zoomDisplay');

// Background
const bgColor1 = getEl('bgColor1');
const bgColor2 = getEl('bgColor2');
const bgDirection = getEl('bgDirection');
const bgColor1Preview = getEl('bgColor1Preview');
const bgColor2Preview = getEl('bgColor2Preview');
const gradientPresetsContainer = getEl('gradientPresets');
const bgTypeSolid = getEl('bgTypeSolid');
const bgTypeGradient = getEl('bgTypeGradient');
const bgSolidSection = getEl('bgSolidSection');
const bgGradientSection = getEl('bgGradientSection');
const bgSolidColor = getEl('bgSolidColor');
const bgSolidColorBtn = getEl('bgSolidColorBtn');
const bgSolidColorHex = getEl('bgSolidColorHex');
const solidColorPresetsContainer = getEl('solidColorPresets');

// Background type state: 'gradient' or 'solid'
let bgType = 'gradient';

// Object Controls
const objectControls = getEl('objectControls');
const propertiesTitle = getEl('propertiesTitle');
const deleteObjBtn = getEl('deleteObjBtn');
const objectName = getEl('objectName');

// Layer Controls
const bringFrontBtn = getEl('bringFrontBtn');
const bringForwardBtn = getEl('bringForwardBtn');
const sendBackwardBtn = getEl('sendBackwardBtn');
const sendBackBtn = getEl('sendBackBtn');

// Text Specific
const textSpecificControls = getEl('textSpecificControls');
const textContent = getEl('textContent');
const fontPickerContainer = getEl('fontPicker');
const textColor = getEl('textColor');
const textColorPreview = getEl('textColorPreview');
const colorPresetsContainer = getEl('colorPresets');
const boldBtn = getEl('boldBtn');
const italicBtn = getEl('italicBtn');
const fontSizeInput = getEl('fontSizeInput');
const alignLeftBtn = getEl('alignLeftBtn');
const alignCenterBtn = getEl('alignCenterBtn');
const alignRightBtn = getEl('alignRightBtn');

// Shape Specific
const shapeSpecificControls = getEl('shapeSpecificControls');
const shapeColor = getEl('shapeColor');
const shapeColorPreview = getEl('shapeColorPreview');
const shapeColorPresetsContainer = getEl('shapeColorPresets');
const cornerRadiusControl = getEl('cornerRadiusControl');
const cornerRadiusInput = getEl('cornerRadiusInput');
const cornerRadiusValue = getEl('cornerRadiusValue');

// Stroke
const enableStroke = getEl('enableStroke');
const strokeControls = getEl('strokeControls');
const strokeColor = getEl('strokeColor');
const strokeColorDisplay = getEl('strokeColorDisplay');
const strokeWidth = getEl('strokeWidth');

// Shadow
const enableShadow = getEl('enableShadow');
const shadowControls = getEl('shadowControls');
const shadowColor = getEl('shadowColor');
const shadowColorDisplay = getEl('shadowColorDisplay');
const shadowBlur = getEl('shadowBlur');
const shadowOffsetX = getEl('shadowOffsetX');
const shadowOffsetY = getEl('shadowOffsetY');

// Actions
const addTextBtn = getEl('addTextBtn');
const addImageBtn = getEl('addImageBtn');
const addCodeBtn = getEl('addCodeBtn');
const addEmojiBtn = getEl('addEmojiBtn');
const addShapesBtn = getEl('addShapesBtn');
const addButtonBtn = getEl('addButtonBtn');
const imgLoader = getEl('imgLoader');
const downloadBtn = getEl('downloadBtn');
const downloadMenuBtn = getEl('downloadMenuBtn');
const downloadMenu = getEl('downloadMenu');
const downloadPngBtn = getEl('downloadPngBtn');
const downloadJpgBtn = getEl('downloadJpgBtn');
const downloadPdfBtn = getEl('downloadPdfBtn');
const downloadAllPngBtn = getEl('downloadAllPngBtn');
const downloadAllPdfBtn = getEl('downloadAllPdfBtn');
const resetBtn = getEl('resetBtn');

// Code Modal Elements
const codeModal = getEl('codeModal');
const closeCodeModal = getEl('closeCodeModal');
const cancelCodeBtn = getEl('cancelCodeBtn');
const insertCodeBtn = getEl('insertCodeBtn');
const codeInput = getEl('codeInput');
const codeLanguage = getEl('codeLanguage');
const codePreview = getEl('codePreview');
const codeCapture = getEl('codeCapture');

// Emoji Modal Elements
const emojiModal = getEl('emojiModal');
const closeEmojiModal = getEl('closeEmojiModal');
const emojiGrid = getEl('emojiGrid');

// Shapes Modal Elements
const shapesModal = getEl('shapesModal');
const closeShapesModal = getEl('closeShapesModal');
const shapeBtns = document.querySelectorAll('.shape-btn');

// Clear Modal Elements
const clearModal = getEl('clearModal');
const confirmClearBtn = getEl('confirmClearBtn');
const cancelClearBtn = getEl('cancelClearBtn');

// QR Code Modal Elements
const qrModal = getEl('qrModal');
const closeQRModal = getEl('closeQRModal');
const cancelQRBtn = getEl('cancelQRBtn');
const insertQRBtn = getEl('insertQRBtn');
const qrPreview = getEl('qrPreview');
const addQRCodeBtn = getEl('addQRCodeBtn');

// QR Code Options Elements
const qrUrl = getEl('qrUrl');
const qrContentSection = getEl('qrContentSection');
const qrColor = getEl('qrColor');
const qrColorText = getEl('qrColorText');
const qrColorDisplay = getEl('qrColorDisplay');
const qrBgColor = getEl('qrBgColor');
const qrBgColorText = getEl('qrBgColorText');
const qrBgColorDisplay = getEl('qrBgColorDisplay');
const qrCornerSquareStyle = getEl('qrCornerSquareStyle');
const qrCornerDotStyle = getEl('qrCornerDotStyle');
const qrErrorCorrection = getEl('qrErrorCorrection');

// Page Strip Elements
const pageStrip = getEl('pageStrip');
const pageThumbnails = getEl('pageThumbnails');
const addPageBtn = getEl('addPageBtn');

// --- Custom HTML Color Picker ---
// Replaces native color picker for reliable positioning in WKWebView
const CustomColorPicker = (function() {
    const modal = document.getElementById('colorPickerModal');
    const popup = document.getElementById('colorPickerPopup');
    const preview = document.getElementById('cpPreview');
    const hexInput = document.getElementById('cpHexInput');
    const palette = document.getElementById('cpPalette');
    const gradient = document.getElementById('cpGradient');
    const gradientMarker = document.getElementById('cpGradientMarker');
    const hueSlider = document.getElementById('cpHueSlider');
    const applyBtn = document.getElementById('cpApplyBtn');
    const closeBtn = document.getElementById('closeColorPicker');
    
    let currentHue = 0;
    let currentSat = 100;
    let currentLight = 50;
    let currentColor = '#000000';
    let onColorChange = null;
    let targetInput = null;
    let targetPreview = null;
    
    // Extended color palette
    const paletteColors = [
        '#ffffff', '#f8fafc', '#f1f5f9', '#e2e8f0', '#cbd5e1', '#94a3b8', '#64748b', '#000000',
        '#fef2f2', '#fee2e2', '#fecaca', '#fca5a5', '#f87171', '#ef4444', '#dc2626', '#b91c1c',
        '#fff7ed', '#ffedd5', '#fed7aa', '#fdba74', '#fb923c', '#f97316', '#ea580c', '#c2410c',
        '#fefce8', '#fef9c3', '#fef08a', '#fde047', '#facc15', '#eab308', '#ca8a04', '#a16207',
        '#f0fdf4', '#dcfce7', '#bbf7d0', '#86efac', '#4ade80', '#22c55e', '#16a34a', '#15803d',
        '#ecfeff', '#cffafe', '#a5f3fc', '#67e8f9', '#22d3ee', '#06b6d4', '#0891b2', '#0e7490',
        '#eff6ff', '#dbeafe', '#bfdbfe', '#93c5fd', '#60a5fa', '#3b82f6', '#2563eb', '#1d4ed8',
        '#f5f3ff', '#ede9fe', '#ddd6fe', '#c4b5fd', '#a78bfa', '#8b5cf6', '#7c3aed', '#6d28d9',
        '#fdf4ff', '#fae8ff', '#f5d0fe', '#f0abfc', '#e879f9', '#d946ef', '#c026d3', '#a21caf',
        '#fdf2f8', '#fce7f3', '#fbcfe8', '#f9a8d4', '#f472b6', '#ec4899', '#db2777', '#be185d'
    ];
    
    // Initialize palette
    function initPalette() {
        if (!palette) return;
        palette.innerHTML = '';
        paletteColors.forEach(color => {
            const btn = document.createElement('button');
            btn.className = 'w-5 h-5 rounded border border-zinc-200 hover:scale-110 transition-transform';
            btn.style.backgroundColor = color;
            btn.onclick = () => setColor(color);
            palette.appendChild(btn);
        });
    }
    
    // HSL to Hex conversion
    function hslToHex(h, s, l) {
        s /= 100;
        l /= 100;
        const a = s * Math.min(l, 1 - l);
        const f = n => {
            const k = (n + h / 30) % 12;
            const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
            return Math.round(255 * color).toString(16).padStart(2, '0');
        };
        return `#${f(0)}${f(8)}${f(4)}`;
    }
    
    // Hex to HSL conversion
    function hexToHsl(hex) {
        let r = parseInt(hex.slice(1, 3), 16) / 255;
        let g = parseInt(hex.slice(3, 5), 16) / 255;
        let b = parseInt(hex.slice(5, 7), 16) / 255;
        
        const max = Math.max(r, g, b), min = Math.min(r, g, b);
        let h, s, l = (max + min) / 2;
        
        if (max === min) {
            h = s = 0;
        } else {
            const d = max - min;
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
            switch (max) {
                case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break;
                case g: h = ((b - r) / d + 2) / 6; break;
                case b: h = ((r - g) / d + 4) / 6; break;
            }
            h *= 360;
        }
        return { h: Math.round(h), s: Math.round(s * 100), l: Math.round(l * 100) };
    }
    
    // Update color display
    function updateColorDisplay() {
        currentColor = hslToHex(currentHue, currentSat, currentLight);
        if (preview) preview.style.backgroundColor = currentColor;
        if (hexInput) hexInput.value = currentColor.toUpperCase();
        if (gradient) {
            gradient.style.background = `linear-gradient(to bottom, rgba(0,0,0,0), rgba(0,0,0,1)), linear-gradient(to right, #ffffff, hsl(${currentHue}, 100%, 50%))`;
        }
    }
    
    // Set color from hex
    function setColor(hex) {
        if (!/^#[0-9A-Fa-f]{6}$/.test(hex)) return;
        const hsl = hexToHsl(hex);
        currentHue = hsl.h;
        currentSat = hsl.s;
        currentLight = hsl.l;
        if (hueSlider) hueSlider.value = currentHue;
        updateGradientMarker();
        updateColorDisplay();
    }
    
    // Update gradient marker position
    function updateGradientMarker() {
        if (!gradientMarker) return;
        // Convert saturation and lightness to x,y position
        const x = currentSat;
        const y = 100 - (currentLight * 2);
        gradientMarker.style.left = `${Math.max(0, Math.min(100, x))}%`;
        gradientMarker.style.top = `${Math.max(0, Math.min(100, y))}%`;
    }
    
    // Handle gradient click/drag
    function handleGradientInteraction(e) {
        if (!gradient) return;
        const rect = gradient.getBoundingClientRect();
        const x = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
        const y = Math.max(0, Math.min(1, (e.clientY - rect.top) / rect.height));
        
        currentSat = Math.round(x * 100);
        currentLight = Math.round((1 - y) * 50);
        
        updateGradientMarker();
        updateColorDisplay();
    }
    
    // Setup gradient interaction
    if (gradient) {
        let isDragging = false;
        gradient.addEventListener('mousedown', (e) => {
            isDragging = true;
            handleGradientInteraction(e);
        });
        document.addEventListener('mousemove', (e) => {
            if (isDragging) handleGradientInteraction(e);
        });
        document.addEventListener('mouseup', () => {
            isDragging = false;
        });
    }
    
    // Setup hue slider
    if (hueSlider) {
        hueSlider.addEventListener('input', (e) => {
            currentHue = parseInt(e.target.value);
            updateColorDisplay();
        });
    }
    
    // Setup hex input
    if (hexInput) {
        hexInput.addEventListener('input', (e) => {
            const val = e.target.value;
            if (/^#[0-9A-Fa-f]{6}$/.test(val)) {
                setColor(val);
            }
        });
    }
    
    // Apply button
    if (applyBtn) {
        applyBtn.addEventListener('click', () => {
            if (targetInput) {
                targetInput.value = currentColor;
                targetInput.dispatchEvent(new Event('input', { bubbles: true }));
            }
            if (targetPreview) {
                const previewDiv = targetPreview.querySelector('div') || targetPreview;
                previewDiv.style.backgroundColor = currentColor;
            }
            if (onColorChange) {
                onColorChange(currentColor);
            }
            close();
        });
    }
    
    // Close button and backdrop
    if (closeBtn) {
        closeBtn.addEventListener('click', close);
    }
    if (modal) {
        modal.addEventListener('click', (e) => {
            if (e.target === modal) close();
        });
    }
    
    function close() {
        if (modal) {
            modal.style.display = 'none';
            modal.classList.add('hidden');
        }
    }
    
    function open(triggerRect, initialColor, inputEl, previewEl, callback) {
        if (!modal || !popup) return;
        
        targetInput = inputEl;
        targetPreview = previewEl;
        onColorChange = callback;
        
        // Set initial color
        setColor(initialColor || '#000000');
        
        // Position popup
        const popupWidth = 256;
        const popupHeight = 380;
        const gap = 12;
        
        // Calculate position: right of element, vertically centered to element
        let posX = triggerRect.right + gap;
        let posY = triggerRect.top + (triggerRect.height / 2) - (popupHeight / 2);
        
        // If doesn't fit on right, try left
        if (posX + popupWidth > window.innerWidth - 20) {
            posX = triggerRect.left - popupWidth - gap;
        }
        
        // If still doesn't fit (left side), center horizontally
        if (posX < 20) {
            posX = (window.innerWidth - popupWidth) / 2;
        }
        
        // Keep within vertical bounds
        posY = Math.max(20, Math.min(posY, window.innerHeight - popupHeight - 20));
        
        popup.style.left = posX + 'px';
        popup.style.top = posY + 'px';
        
        // Show modal
        modal.style.display = 'flex';
        modal.classList.remove('hidden');
    }
    
    // Initialize
    initPalette();
    
    return { open, close, setColor };
})();

// Setup function for color inputs to use custom picker
window.setupColorPicker = function(colorInput, previewElement, callback) {
    if (!colorInput) return;
    
    const wrapper = colorInput.parentElement;
    if (!wrapper) return;
    
    // Hide native color input interaction
    colorInput.style.pointerEvents = 'none';
    
    // Handle click on wrapper
    wrapper.addEventListener('click', (e) => {
        e.preventDefault();
        e.stopPropagation();
        
        const rect = wrapper.getBoundingClientRect();
        CustomColorPicker.open(
            rect,
            colorInput.value,
            colorInput,
            previewElement,
            callback
        );
    });
};

// --- Multi-Page Functions ---

// Generate a thumbnail from the canvas
function generateThumbnail(pageData) {
    // Create a temporary canvas to render the thumbnail
    const tempCanvas = document.createElement('canvas');
    const aspectRatio = pageData.artboardBase.w / pageData.artboardBase.h;
    const thumbWidth = 64;
    const thumbHeight = thumbWidth / aspectRatio;
    
    tempCanvas.width = thumbWidth;
    tempCanvas.height = thumbHeight;
    const ctx = tempCanvas.getContext('2d');
    
    // Draw background
    const bg = pageData.background;
    if (bg.type === 'solid') {
        // Solid color background
        ctx.fillStyle = bg.solidColor || '#4f46e5';
        ctx.fillRect(0, 0, thumbWidth, thumbHeight);
    } else {
        // Gradient background
        const gradient = ctx.createLinearGradient(
            bg.direction?.includes('right') ? 0 : thumbWidth / 2,
            bg.direction?.includes('bottom') || bg.direction?.includes('top') ? 0 : thumbHeight / 2,
            bg.direction?.includes('right') ? thumbWidth : thumbWidth / 2,
            bg.direction?.includes('bottom') ? thumbHeight : (bg.direction?.includes('top') ? 0 : thumbHeight / 2)
        );
        gradient.addColorStop(0, bg.color1 || '#4f46e5');
        gradient.addColorStop(1, bg.color2 || '#ec4899');
        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, thumbWidth, thumbHeight);
    }
    
    return tempCanvas.toDataURL('image/png');
}

// Render page thumbnails in the strip
function renderPageThumbnails() {
    if (!pageThumbnails) return;
    
    pageThumbnails.innerHTML = '';
    
    pages.forEach((page, index) => {
        const thumb = document.createElement('div');
        thumb.className = `page-thumbnail ${page.id === currentPageId ? 'active' : ''}`;
        thumb.dataset.pageId = page.id;
        thumb.title = page.name;
        
        // Generate thumbnail image
        const thumbImg = generateThumbnail(page);
        thumb.innerHTML = `
            <img src="${thumbImg}" alt="${page.name}">
            <span class="page-thumbnail-label">${index + 1}</span>
            <div class="page-thumbnail-actions">
                <button class="page-thumbnail-btn duplicate" title="Duplicate">
                    <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                        <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
                        <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
                    </svg>
                </button>
                ${pages.length > 1 ? `
                <button class="page-thumbnail-btn delete" title="Delete">
                    <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                        <path d="M18 6L6 18M6 6l12 12"></path>
                    </svg>
                </button>
                ` : ''}
            </div>
        `;
        
        // Click to switch page
        thumb.addEventListener('click', (e) => {
            if (e.target.closest('.page-thumbnail-btn')) return;
            switchToPage(page.id);
        });
        
        // Duplicate button
        const dupBtn = thumb.querySelector('.duplicate');
        if (dupBtn) {
            dupBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                duplicatePage(page.id);
            });
        }
        
        // Delete button
        const delBtn = thumb.querySelector('.delete');
        if (delBtn) {
            delBtn.addEventListener('click', (e) => {
                e.stopPropagation();
                deletePage(page.id);
            });
        }
        
        pageThumbnails.appendChild(thumb);
    });
}

// Switch to a specific page
function switchToPage(pageId) {
    if (pageId === currentPageId) return;
    if (isRestoring) return;
    
    // Save current page state first
    saveCurrentPageToArray();
    
    // Find the target page
    const targetPage = pages.find(p => p.id === pageId);
    if (!targetPage) return;
    
    currentPageId = pageId;
    
    // Restore the target page state
    restorePageState(targetPage);
    
    // Update thumbnails
    renderPageThumbnails();
    
    // Trigger save to persist the page switch
    triggerSave();
}

// Restore a page state to canvas
function restorePageState(pageData) {
    isRestoring = true;
    
    // Update artboard and background
    artboardBase = pageData.artboardBase || { w: 1200, h: 675 };
    bgType = pageData.background?.type || 'gradient';
    if(bgColor1) bgColor1.value = pageData.background?.color1 || '#4f46e5';
    if(bgColor2) bgColor2.value = pageData.background?.color2 || '#ec4899';
    if(bgDirection) bgDirection.value = pageData.background?.direction || 'to right';
    if(bgSolidColor) bgSolidColor.value = pageData.background?.solidColor || '#4f46e5';
    
    // Update UI
    if(canvasWidthInput) canvasWidthInput.value = artboardBase.w;
    if(canvasHeightInput) canvasHeightInput.value = artboardBase.h;
    if(bgColor1Preview && bgColor1) bgColor1Preview.style.backgroundColor = bgColor1.value;
    if(bgColor2Preview && bgColor2) bgColor2Preview.style.backgroundColor = bgColor2.value;
    if(canvasSizeLabel) canvasSizeLabel.innerText = `${artboardBase.w} x ${artboardBase.h} px`;
    
    // Update background type UI
    updateBgTypeUI();
    
    // Load canvas objects
    canvas.loadFromJSON(pageData.fabric, function() {
        // Process loaded objects (same as restoreState)
        canvas.getObjects().forEach(obj => {
            if ((obj.type === 'i-text' || obj.type === 'text' || obj.type === 'textbox') && !obj.styles) {
                obj.styles = {};
            }
            if (obj.type === 'i-text' || obj.type === 'text' || obj.type === 'textbox') {
                obj.set('objectCaching', false);
                if (obj.fontFamily) {
                    obj.set('fontFamily', obj.fontFamily);
                }
            }
            if (obj.strokeWidth > 0) {
                obj.set('strokeLineJoin', 'round');
                obj.set('strokeLineCap', 'round');
                obj.set('strokeMiterLimit', 10);
                if (obj.type === 'i-text' || obj.type === 'text' || obj.type === 'textbox') {
                    obj.set('paintFirst', 'stroke');
                }
            }
            if (obj.name) {
                const sanitized = sanitizeObjectName(obj.name);
                if (sanitized !== obj.name) {
                    obj.set('name', sanitized || generateDefaultName(obj.type));
                }
            } else {
                obj.set('name', generateDefaultName(obj.type));
            }
            if (obj.isButton) {
                obj.setControlsVisibility({
                    mt: true, mb: true, ml: true, mr: true,
                    bl: true, br: true, tl: true, tr: true,
                    mtr: true
                });
            }
        });
        
        applyZoom(zoomLevel);
        updateBackground();
        canvas.renderAll();
        
        setTimeout(() => {
            isRestoring = false;
        }, 100);
    });
}

// Create a new page
function createNewPage(options = {}) {
    // Save current page state first
    if (currentPageId) {
        saveCurrentPageToArray();
    }
    
    // Create new page with default or copied settings
    const newPage = createPageObject({
        name: options.name || `Page ${pages.length + 1}`,
        artboardBase: options.artboardBase || { ...artboardBase },
        background: options.background || {
            type: bgType,
            color1: bgColor1 ? bgColor1.value : '#4f46e5',
            color2: bgColor2 ? bgColor2.value : '#ec4899',
            direction: bgDirection ? bgDirection.value : 'to right',
            solidColor: bgSolidColor ? bgSolidColor.value : '#4f46e5'
        },
        fabric: options.fabric || { version: fabric.version, objects: [] }
    });
    
    pages.push(newPage);
    currentPageId = newPage.id;
    
    // Clear canvas for new page (unless fabric data provided)
    if (!options.fabric || options.fabric.objects.length === 0) {
        canvas.clear();
        updateBackground();
    } else {
        restorePageState(newPage);
    }
    
    renderPageThumbnails();
    triggerSave();
    
    return newPage;
}

// Duplicate a page
function duplicatePage(pageId) {
    const sourcePage = pages.find(p => p.id === pageId);
    if (!sourcePage) return;
    
    // If duplicating current page, save it first
    if (pageId === currentPageId) {
        saveCurrentPageToArray();
    }
    
    // Find index to insert after source
    const sourceIndex = pages.findIndex(p => p.id === pageId);
    
    // Create duplicate
    const newPage = createPageObject({
        name: `${sourcePage.name} (copy)`,
        artboardBase: { ...sourcePage.artboardBase },
        background: { ...sourcePage.background },
        fabric: JSON.parse(JSON.stringify(sourcePage.fabric))
    });
    
    // Insert after source
    pages.splice(sourceIndex + 1, 0, newPage);
    
    // Switch to the new page
    currentPageId = newPage.id;
    restorePageState(newPage);
    renderPageThumbnails();
    triggerSave();
    
    return newPage;
}

// Delete a page
function deletePage(pageId) {
    if (pages.length <= 1) return; // Can't delete last page
    
    const pageIndex = pages.findIndex(p => p.id === pageId);
    if (pageIndex === -1) return;
    
    // Remove the page
    pages.splice(pageIndex, 1);
    
    // If we deleted current page, switch to another
    if (pageId === currentPageId) {
        const newIndex = Math.min(pageIndex, pages.length - 1);
        currentPageId = pages[newIndex].id;
        restorePageState(pages[newIndex]);
    }
    
    renderPageThumbnails();
    triggerSave();
}

// Initialize pages (called on app load)
function initializePages() {
    if (pages.length === 0) {
        // Create first page with current canvas state
        const firstPage = createPageObject({
            name: 'Page 1',
            artboardBase: { ...artboardBase },
            background: {
                type: bgType,
                color1: bgColor1 ? bgColor1.value : '#4f46e5',
                color2: bgColor2 ? bgColor2.value : '#ec4899',
                direction: bgDirection ? bgDirection.value : 'to right',
                solidColor: bgSolidColor ? bgSolidColor.value : '#4f46e5'
            },
            fabric: canvas.toJSON()
        });
        pages.push(firstPage);
        currentPageId = firstPage.id;
    }
    renderPageThumbnails();
}

// --- Auto-Save & History Logic ---
let isRestoring = false; // Flag to prevent save loops during load
let saveTimeout;

// History State
const historyStack = [];
let historyIndex = -1;
const MAX_HISTORY = 50;

function getCurrentState() {
    // Temporarily remove guidelines for serialization
    const guidelines = canvas.getObjects().filter(obj => obj.name?.startsWith('__guideline'));
    guidelines.forEach(guideline => canvas.remove(guideline));
    
    const canvasJson = canvas.toJSON();
    
    // Restore guidelines and ensure they're at the back
    guidelines.forEach(guideline => {
        canvas.add(guideline);
        canvas.moveTo(guideline, 0);
    });
    
    return {
        artboardBase: artboardBase,
        background: {
            type: bgType,
            color1: bgColor1 ? bgColor1.value : '#4f46e5',
            color2: bgColor2 ? bgColor2.value : '#ec4899',
            direction: bgDirection ? bgDirection.value : 'to right',
            solidColor: bgSolidColor ? bgSolidColor.value : '#4f46e5'
        },
        fabric: canvasJson
    };
}

function addToHistory(state) {
    // Avoid duplicate states (compare with current)
    if (historyStack.length > 0 && historyIndex >= 0) {
        const currentState = JSON.stringify(historyStack[historyIndex]);
        const newState = JSON.stringify(state);
        if (currentState === newState) return;
    }

    // If we are in the middle of the stack (undoed), remove forward history
    if (historyIndex < historyStack.length - 1) {
        historyStack.splice(historyIndex + 1);
    }
    
    historyStack.push(state);
    if (historyStack.length > MAX_HISTORY) {
        historyStack.shift();
        // If we shifted, the index stays the same (pointing to the new end which shifted down)
    } else {
        historyIndex++;
    }
    
    updateUndoRedoUI();
}

function updateUndoRedoUI() {
    if (undoBtn) undoBtn.disabled = historyIndex <= 0;
    if (redoBtn) redoBtn.disabled = historyIndex >= historyStack.length - 1;
}

function undo() {
    if (isRestoring) return;

    // If there's a pending save (e.g. user just moved an object), force it to be recorded
    // so that we can undo FROM it.
    if (saveTimeout) {
        clearTimeout(saveTimeout);
        saveToLocalStorage(); 
    }

    if (historyIndex > 0) {
        historyIndex--;
        const state = historyStack[historyIndex];
        restoreState(state, true);
        updateUndoRedoUI();
    }
}

function redo() {
    if (isRestoring) return;

    if (historyIndex < historyStack.length - 1) {
        historyIndex++;
        const state = historyStack[historyIndex];
        restoreState(state, true);
        updateUndoRedoUI();
    }
}

function saveToLocalStorage() {
    if (isRestoring) return;

    try {
        // Save current page state to pages array
        saveCurrentPageToArray();
        
        // Build full state with all pages
        const fullState = {
            pages: pages,
            currentPageId: currentPageId,
            pageCounter: pageCounter
        };
        
        // Add current page state to history (for undo/redo within page)
        const currentPageState = getCurrentState();
        addToHistory(currentPageState);
        
        // Save to local storage
        localStorage.setItem('gradientEditorState', JSON.stringify(fullState));
        
        // Update thumbnails after save
        renderPageThumbnails();
    } catch (e) {
        console.error("Auto-save failed:", e);
    }
}

function triggerSave() {
    if (isRestoring) return;
    clearTimeout(saveTimeout);
    saveTimeout = setTimeout(saveToLocalStorage, 500); // Debounce 500ms
}

// Unified State Restorer
function restoreState(state, fromHistory = false) {
    isRestoring = true; // Lock auto-save

    // Restore Settings
    artboardBase = state.artboardBase || { w: 1200, h: 675 };
    bgType = state.background?.type || 'gradient';
    if(bgColor1) bgColor1.value = state.background?.color1 || '#4f46e5';
    if(bgColor2) bgColor2.value = state.background?.color2 || '#ec4899';
    if(bgDirection) bgDirection.value = state.background?.direction || 'to right';
    if(bgSolidColor) bgSolidColor.value = state.background?.solidColor || '#4f46e5';
    
    // Update UI
    if(canvasWidthInput) canvasWidthInput.value = artboardBase.w;
    if(canvasHeightInput) canvasHeightInput.value = artboardBase.h;
    if(bgColor1Preview && bgColor1) bgColor1Preview.style.backgroundColor = bgColor1.value;
    if(bgColor2Preview && bgColor2) bgColor2Preview.style.backgroundColor = bgColor2.value;
    if(canvasSizeLabel) canvasSizeLabel.innerText = `${artboardBase.w} x ${artboardBase.h} px`;
    
    // Update background type UI
    updateBgTypeUI();
    
    // Restore Canvas
    canvas.loadFromJSON(state.fabric, function() {
        // Safety check for missing styles and ensure stroke rendering quality
        // Also ensure all objects have names and update counter
        canvas.getObjects().forEach(obj => {
            if ((obj.type === 'i-text' || obj.type === 'text' || obj.type === 'textbox') && !obj.styles) {
                obj.styles = {};
            }
            
            // For text objects, ensure fonts are properly applied
            if (obj.type === 'i-text' || obj.type === 'text' || obj.type === 'textbox') {
                // Disable caching to force re-render with correct fonts
                obj.set('objectCaching', false);
                // Refresh fontFamily to trigger font reload
                if (obj.fontFamily) {
                    const fontFamily = obj.fontFamily;
                    obj.set('fontFamily', fontFamily);
                }
            }
            
            // Ensure stroke rendering quality for objects with stroke
            if (obj.strokeWidth > 0) {
                obj.set('strokeLineJoin', 'round');
                obj.set('strokeLineCap', 'round');
                obj.set('strokeMiterLimit', 10);
                // For text objects, render stroke first to prevent overlap with fill
                if (obj.type === 'i-text' || obj.type === 'text' || obj.type === 'textbox') {
                    obj.set('paintFirst', 'stroke');
                }
            }
            
            // Sanitize existing names and ensure all objects have safe names
            if (obj.name) {
                const sanitized = sanitizeObjectName(obj.name);
                if (sanitized !== obj.name) {
                    obj.set('name', sanitized || generateDefaultName(obj.type));
                }
            } else {
                obj.set('name', generateDefaultName(obj.type));
            }
            
            // Restore Button Controls
            if (obj.isButton) {
                obj.setControlsVisibility({
                    mt: true, mb: true, ml: true, mr: true, 
                    bl: true, br: true, tl: true, tr: true,
                    mtr: true
                });
            }

            // Update counter based on existing names to avoid conflicts
            if (obj.name) {
                const match = obj.name.match(/^(text|shape|image|emoji|code)_(\d+)$/);
                if (match) {
                    const category = match[1];
                    const num = parseInt(match[2], 10);
                    if (objectNameCounter[category] === undefined || objectNameCounter[category] < num) {
                        objectNameCounter[category] = num;
                    }
                }
            }
        });

        // Finish Load
        applyZoom(1); 
        updateBackground(); 
        initPresets(); 
        
        // Force re-render after fonts load to ensure styling is applied
        const renderWithFonts = () => {
            // Force all text objects to refresh their font rendering
            canvas.getObjects().forEach(obj => {
                if (obj.type === 'i-text' || obj.type === 'text' || obj.type === 'textbox') {
                    // Trigger font reload by refreshing fontFamily
                    const fontFamily = obj.fontFamily;
                    if (fontFamily) {
                        obj.set('fontFamily', fontFamily);
                        obj.dirty = true; // Mark as dirty to force re-render
                    }
                }
            });
            canvas.renderAll();
        };
        
        // Always render immediately, then again after fonts are confirmed loaded
        renderWithFonts();
        
        if (document.fonts && document.fonts.ready) {
            // Wait for fonts to load (or if already loaded, this resolves immediately)
            document.fonts.ready.then(() => {
                // Additional render after fonts are confirmed loaded
                setTimeout(renderWithFonts, 50);
            }).catch(() => {
                // Fallback if promise fails
                setTimeout(renderWithFonts, 200);
            });
        } else {
            // Fallback for browsers without Font Loading API
            setTimeout(renderWithFonts, 200);
        }
        
        // Re-enable save after a delay to ensure render is done
        setTimeout(() => {
            isRestoring = false;
            if (!fromHistory) triggerSave(); // Save the clean imported state once (only if not from history)
        }, 300);
    });
}

function loadFromLocalStorage() {
    const saved = localStorage.getItem('gradientEditorState');
    if (!saved) {
        initPresets();
        updateBackground();
        initializePages();
        return;
    }
    try {
        const state = JSON.parse(saved);
        
        // Check if this is the new multi-page format
        if (state.pages && Array.isArray(state.pages)) {
            // New multi-page format
            pages = state.pages;
            currentPageId = state.currentPageId;
            pageCounter = state.pageCounter || pages.length;
            
            // Find and restore current page
            const currentPage = pages.find(p => p.id === currentPageId);
            if (currentPage) {
                restorePageState(currentPage);
            } else if (pages.length > 0) {
                // Fallback to first page
                currentPageId = pages[0].id;
                restorePageState(pages[0]);
            }
            
            initPresets();
            renderPageThumbnails();
        } else {
            // Legacy single-page format - migrate to multi-page
            pages = [];
            const legacyBg = state.background || {};
            const migratedPage = createPageObject({
                name: 'Page 1',
                artboardBase: state.artboardBase || { w: 1200, h: 675 },
                background: {
                    type: legacyBg.type || 'gradient',
                    color1: legacyBg.color1 || '#4f46e5',
                    color2: legacyBg.color2 || '#ec4899',
                    direction: legacyBg.direction || 'to right',
                    solidColor: legacyBg.solidColor || legacyBg.color1 || '#4f46e5'
                },
                fabric: state.fabric || { version: fabric.version, objects: [] }
            });
            pages.push(migratedPage);
            currentPageId = migratedPage.id;
            
            restoreState(state);
            renderPageThumbnails();
        }
    } catch (e) {
        console.error("Error loading state", e);
        localStorage.removeItem('gradientEditorState');
        initPresets();
        updateBackground();
        initializePages();
    }
}

// --- JSON Import Logic ---
// Function to process imported JSON content
function processImportedJson(jsonContent) {
    try {
        const state = JSON.parse(jsonContent);

        // Check if this is multi-page format
        if (state.pages && Array.isArray(state.pages)) {
            // Multi-page project import
            pages = state.pages;
            currentPageId = state.currentPageId;
            pageCounter = state.pageCounter || pages.length;

            // Restore first/current page
            const currentPage = pages.find(p => p.id === currentPageId) || pages[0];
            if (currentPage) {
                currentPageId = currentPage.id;
                restorePageState(currentPage);
            }

            renderPageThumbnails();
            triggerSave();
        } else {
            // Legacy single-page import - create as new page
            pages = [];
            const legacyBg = state.background || {};
            const importedPage = createPageObject({
                name: 'Imported Page',
                artboardBase: state.artboardBase || { w: 1200, h: 675 },
                background: {
                    type: legacyBg.type || 'gradient',
                    color1: legacyBg.color1 || '#4f46e5',
                    color2: legacyBg.color2 || '#ec4899',
                    direction: legacyBg.direction || 'to right',
                    solidColor: legacyBg.solidColor || legacyBg.color1 || '#4f46e5'
                },
                fabric: state.fabric || { version: fabric.version, objects: [] }
            });
            pages.push(importedPage);
            currentPageId = importedPage.id;

            restoreState(state);
            renderPageThumbnails();
        }
    } catch (err) {
        console.error("Invalid JSON file", err);
        alert("Invalid JSON file format.");
    }
}

// Native file picker helper
function nativeFilePicker() {
    if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.nativeFilePicker) {
        window.webkit.messageHandlers.nativeFilePicker.postMessage({ type: 'json' });
        return true;
    }
    return false;
}

// Called from Swift with file content
window.handleNativeFileContent = function(content) {
    processImportedJson(content);
};

if(importJsonBtn && jsonInput) {
    importJsonBtn.addEventListener('click', () => {
        // Try native file picker first (for macOS/iOS app)
        if (!nativeFilePicker()) {
            jsonInput.click();
        }
    });

    jsonInput.addEventListener('change', (e) => {
        const file = e.target.files[0];
        if (!file) return;

        const reader = new FileReader();
        reader.onload = (f) => {
            processImportedJson(f.target.result);
            jsonInput.value = '';
        };
        reader.readAsText(file);
    });
}

// Hook into Fabric events
canvas.on('object:added', triggerSave);
canvas.on('object:removed', triggerSave);
canvas.on('object:modified', triggerSave);
canvas.on('text:changed', triggerSave); 

// Rotate Listener for UI update
canvas.on('object:rotating', (e) => {
    if(e.target && rotationInput && rotationValue) {
        const angle = Math.round(e.target.angle % 360);
        const normalized = angle < 0 ? 360 + angle : angle;
        rotationInput.value = normalized;
        rotationValue.innerText = normalized;
    }
});

// Smart Scaling for Buttons (Resizing instead of Stretching)
canvas.on('object:scaling', (e) => {
    const target = e.target;
    if (!target) return;

    if (target.isButton) {
        const items = target.getObjects();
        const rect = items[0];
        const text = items[1];
        
        // Calculate new dimensions based on scale
        const scaleX = target.scaleX;
        const scaleY = target.scaleY;
        const newWidth = target.width * scaleX;
        const newHeight = target.height * scaleY;
        
        // Reset Group Scale
        target.set({
            scaleX: 1,
            scaleY: 1,
            width: newWidth,
            height: newHeight
        });
        
        // Resize Rect to match Group
        // Note: Group origin is center, so coords relative to center are width/2, height/2
        rect.set({
            width: newWidth,
            height: newHeight,
            scaleX: 1,
            scaleY: 1,
            originX: 'center',
            originY: 'center',
            left: 0, // Center of group
            top: 0
        });
        
        // Keep Text centered and unscaled (restore its original font size if needed, but simpler to just reset scale)
        // We don't want text to stretch, so we ensure its scale is 1
        text.set({
            scaleX: 1,
            scaleY: 1,
            left: 0,
            top: 0,
            originX: 'center',
            originY: 'center'
        });
        
        // Update group coords to keep visual position correct (Fabric does this mostly, but sometimes jumps)
        // No special handling needed usually if we just modify properties during scale
        
        // If we wanted to enforce min dimensions:
        // if (newWidth < 50) ...
    }
});

// --- Init Presets UI ---

function initPresets() {
    // Gradients
    if(gradientPresetsContainer) {
        gradientPresetsContainer.innerHTML = ''; // Clear to avoid dupes on reload
        gradients.forEach(g => {
            const btn = document.createElement('button');
            btn.className = 'w-8 h-8 rounded-full border border-slate-200 color-swatch';
            btn.style.background = `linear-gradient(135deg, ${g.c1}, ${g.c2})`;
            btn.title = g.name;
            btn.onclick = () => {
                if(bgColor1) bgColor1.value = g.c1;
                if(bgColor2) bgColor2.value = g.c2;
                updateBackground();
                triggerSave(); // Save changes
            };
            gradientPresetsContainer.appendChild(btn);
        });
    }
    
    // Solid Background Color Presets
    if(solidColorPresetsContainer) {
        solidColorPresetsContainer.innerHTML = '';
        const bgColorPresets = [
            '#ffffff', '#f8fafc', '#f1f5f9', '#e2e8f0', '#cbd5e1', '#94a3b8',
            '#64748b', '#475569', '#334155', '#1e293b', '#0f172a', '#000000',
            '#4f46e5', '#6366f1', '#8b5cf6', '#a855f7', '#d946ef', '#ec4899',
            '#f43f5e', '#ef4444', '#f97316', '#f59e0b', '#eab308', '#84cc16',
            '#22c55e', '#10b981', '#14b8a6', '#06b6d4', '#0ea5e9', '#3b82f6'
        ];
        bgColorPresets.forEach(c => {
            const btn = document.createElement('button');
            btn.className = 'w-6 h-6 rounded border border-zinc-200 color-swatch hover:scale-110 transition-transform';
            btn.style.backgroundColor = c;
            btn.title = c;
            btn.onclick = () => {
                if(bgSolidColor) bgSolidColor.value = c;
                if(bgSolidColorBtn) bgSolidColorBtn.style.backgroundColor = c;
                if(bgSolidColorHex) bgSolidColorHex.value = c.toUpperCase();
                updateBackground();
                triggerSave();
            };
            solidColorPresetsContainer.appendChild(btn);
        });
    }

    // Colors (Text)
    if(colorPresetsContainer) {
        colorPresetsContainer.innerHTML = '';
        colorPalettes.forEach(c => {
            const btn = document.createElement('button');
            btn.className = 'w-6 h-6 rounded border border-slate-200 color-swatch';
            btn.style.backgroundColor = c;
            btn.onclick = () => {
                if(activeObject) {
                    if (activeObject.isButton) {
                        activeObject.getObjects()[1].set('fill', c); // Text is index 1
                        activeObject.addWithUpdate(); // Important for groups
                        canvas.requestRenderAll();
                        updateUIForSelection(activeObject); 
                        triggerSave();
                    } else if (activeObject.type === 'i-text' || activeObject.type === 'text') {
                        activeObject.set('fill', c);
                        canvas.requestRenderAll();
                        updateUIForSelection(activeObject); 
                        triggerSave(); 
                    }
                }
            };
            colorPresetsContainer.appendChild(btn);
        });
    }

    // Colors (Shapes)
    if(shapeColorPresetsContainer) {
        shapeColorPresetsContainer.innerHTML = '';
        colorPalettes.forEach(c => {
            const btn = document.createElement('button');
            btn.className = 'w-6 h-6 rounded border border-slate-200 color-swatch';
            btn.style.backgroundColor = c;
            btn.onclick = () => {
                if(activeObject) {
                    if(activeObject.isButton) {
                        activeObject.getObjects()[0].set('fill', c); // Rect is index 0
                        activeObject.addWithUpdate();
                        if(shapeColor) shapeColor.value = c;
                        if(shapeColorPreview) shapeColorPreview.querySelector('div').style.backgroundColor = c;
                        canvas.requestRenderAll();
                        triggerSave();
                    } else if(activeObject.type === 'rect' || activeObject.type === 'circle' || activeObject.type === 'path' || activeObject.type === 'polygon') {
                        activeObject.set('fill', c);
                        if(shapeColor) shapeColor.value = c;
                        if(shapeColorPreview) shapeColorPreview.querySelector('div').style.backgroundColor = c;
                        canvas.requestRenderAll();
                        updateUIForSelection(activeObject); 
                        triggerSave(); // Save changes
                    }
                }
            };
            shapeColorPresetsContainer.appendChild(btn);
        });
    }

    // Fonts
    if(fontPickerContainer) {
        fontPickerContainer.innerHTML = '';
        fontFamilies.forEach(font => {
            const btn = document.createElement('button');
            btn.className = 'font-option w-full text-left px-3 py-2 rounded border border-transparent text-sm transition-all flex items-center justify-between group shrink-0';
            btn.style.fontFamily = font.family;
            btn.innerHTML = `
                <span class="text-slate-700 group-hover:text-slate-900 text-lg">${font.name}</span>
                <span class="text-[10px] text-slate-400 font-sans font-normal bg-slate-100 px-1.5 py-0.5 rounded">${font.type}</span>
            `;
            btn.dataset.font = font.family;
            
            btn.onclick = () => {
                if (activeObject) {
                    if (activeObject.isButton) {
                        activeObject.getObjects()[1].set('fontFamily', font.family);
                        activeObject.addWithUpdate();
                        canvas.requestRenderAll();
                        updateFontPickerUI(font.family);
                        triggerSave();
                    } else if (activeObject.type === 'i-text' || activeObject.type === 'text') {
                        activeObject.set('fontFamily', font.family);
                        canvas.requestRenderAll();
                        updateFontPickerUI(font.family);
                        triggerSave(); // Save changes
                    }
                }
            };
            fontPickerContainer.appendChild(btn);
        });
    }

    // Init Emojis
    if(emojiGrid) {
        emojiGrid.innerHTML = '';
        for (const [category, emojis] of Object.entries(emojiCategories)) {
            const categoryTitle = document.createElement('h4');
            categoryTitle.className = 'text-xs font-bold text-slate-500 uppercase tracking-wider mt-4 mb-2 px-2';
            categoryTitle.innerText = category;
            emojiGrid.appendChild(categoryTitle);
            
            const grid = document.createElement('div');
            grid.className = 'grid grid-cols-6 gap-1';
            
            emojis.forEach(emoji => {
               const btn = document.createElement('button');
               btn.className = 'emoji-btn w-full h-10 flex items-center justify-center hover:bg-slate-100 rounded';
               btn.innerText = emoji;
               btn.onclick = () => addEmoji(emoji);
               grid.appendChild(btn);
            });
            emojiGrid.appendChild(grid);
        }
    }
}

function updateFontPickerUI(selectedFont) {
    if(!fontPickerContainer) return;
    const options = fontPickerContainer.querySelectorAll('.font-option');
    options.forEach(opt => {
        if (opt.dataset.font === selectedFont) {
            opt.classList.add('active');
            opt.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
        } else {
            opt.classList.remove('active');
        }
    });
}

// --- Functions ---

function applyZoom(newZoom) {
    // Clamp between 25% and 300%
    zoomLevel = Math.min(Math.max(newZoom, 0.25), 3);
    
    // Update Canvas Dimensions visually (Physical size changes, logical size handled by Fabric scale)
    canvas.setZoom(zoomLevel);
    canvas.setWidth(artboardBase.w * zoomLevel);
    canvas.setHeight(artboardBase.h * zoomLevel);
    
    // Update UI
    if(zoomDisplay) zoomDisplay.innerText = `${Math.round(zoomLevel * 100)}%`;
    canvas.renderAll();
}

function resizeCanvas(w, h) {
    artboardBase = { w, h };
    
    // Re-apply current zoom to new base dimensions
    applyZoom(zoomLevel);
    
    updateBackground(); 
    if(canvasSizeLabel) canvasSizeLabel.innerText = `${w} x ${h} px`;
    triggerSave(); // Save on resize
}

function updateBackground() {
    if (bgType === 'solid') {
        // Solid color background
        const solidColor = bgSolidColor ? bgSolidColor.value : '#4f46e5';
        
        // Update UI previews
        if(bgSolidColorBtn) bgSolidColorBtn.style.backgroundColor = solidColor;
        if(bgSolidColorHex) bgSolidColorHex.value = solidColor.toUpperCase();
        
        canvas.setBackgroundColor(solidColor, canvas.renderAll.bind(canvas));
    } else {
        // Gradient background
        if(!bgColor1 || !bgColor2 || !bgDirection) return;
        
        const color1 = bgColor1.value;
        const color2 = bgColor2.value;
        const direction = bgDirection.value;

        // Update UI previews
        if(bgColor1Preview) bgColor1Preview.style.backgroundColor = color1;
        if(bgColor2Preview) bgColor2Preview.style.backgroundColor = color2;

        // Logical Coordinates (Gradient always covers the full logical board, zoom handles the rest)
        let coords = { x1: 0, y1: 0, x2: 0, y2: artboardBase.h }; // default bottom

        if (direction === 'to right') coords = { x1: 0, y1: 0, x2: artboardBase.w, y2: 0 };
        if (direction === 'to bottom right') coords = { x1: 0, y1: 0, x2: artboardBase.w, y2: artboardBase.h };
        if (direction === 'to top right') coords = { x1: 0, y1: artboardBase.h, x2: artboardBase.w, y2: 0 };

        const gradient = new fabric.Gradient({
            type: 'linear',
            coords: coords,
            colorStops: [
                { offset: 0, color: color1 },
                { offset: 1, color: color2 }
            ]
        });

        canvas.setBackgroundColor(gradient, canvas.renderAll.bind(canvas));
    }
}

// Update background type UI (toggle buttons and sections)
function updateBgTypeUI() {
    if (bgType === 'solid') {
        if(bgTypeSolid) {
            bgTypeSolid.classList.add('bg-indigo-600', 'text-white');
            bgTypeSolid.classList.remove('text-zinc-500', 'hover:text-zinc-700');
        }
        if(bgTypeGradient) {
            bgTypeGradient.classList.remove('bg-indigo-600', 'text-white');
            bgTypeGradient.classList.add('text-zinc-500', 'hover:text-zinc-700');
        }
        if(bgSolidSection) bgSolidSection.classList.remove('hidden');
        if(bgGradientSection) bgGradientSection.classList.add('hidden');
        
        // Update solid color preview
        if(bgSolidColor && bgSolidColorBtn) {
            bgSolidColorBtn.style.backgroundColor = bgSolidColor.value;
        }
        if(bgSolidColor && bgSolidColorHex) {
            bgSolidColorHex.value = bgSolidColor.value.toUpperCase();
        }
    } else {
        if(bgTypeGradient) {
            bgTypeGradient.classList.add('bg-indigo-600', 'text-white');
            bgTypeGradient.classList.remove('text-zinc-500', 'hover:text-zinc-700');
        }
        if(bgTypeSolid) {
            bgTypeSolid.classList.remove('bg-indigo-600', 'text-white');
            bgTypeSolid.classList.add('text-zinc-500', 'hover:text-zinc-700');
        }
        if(bgSolidSection) bgSolidSection.classList.add('hidden');
        if(bgGradientSection) bgGradientSection.classList.remove('hidden');
    }
}

function addText() {
    const text = new fabric.IText('Double click to edit', {
        left: artboardBase.w / 2, // Center in logical coordinates
        top: artboardBase.h / 2,
        originX: 'center',
        originY: 'center',
        fontFamily: 'Inter',
        fontSize: 40,
        fill: '#ffffff',
        fontWeight: 'bold',
        strokeWidth: 0,
        strokeLineJoin: 'round',
        strokeLineCap: 'round',
        strokeMiterLimit: 10,
        name: generateDefaultName('i-text')
    });
    canvas.add(text);
    canvas.setActiveObject(text);
    updateUIForSelection(text);
    triggerSave();
}

function addButton() {
    const rect = new fabric.Rect({
        width: 200,
        height: 60,
        fill: '#4f46e5',
        rx: 10, 
        ry: 10,
        originX: 'center',
        originY: 'center',
        strokeWidth: 0,
        stroke: '#000000'
    });

    const text = new fabric.IText('Button', {
        fontFamily: 'Inter',
        fontSize: 24,
        fill: '#ffffff',
        originX: 'center',
        originY: 'center',
        fontWeight: 'bold'
    });

    const group = new fabric.Group([rect, text], {
        left: artboardBase.w / 2,
        top: artboardBase.h / 2,
        originX: 'center',
        originY: 'center',
        name: generateDefaultName('button'),
        isButton: true // Custom flag
    });

    // Override toObject to include isButton
    // Note: Global override now handles 'isButton', but keeping this for safety if local override needed for specific logic later
    // For now, we can rely on the global one or just ensure it's set.
    
    // Disable default group controls that distort
    group.setControlsVisibility({
        mt: true, 
        mb: true, 
        ml: true, 
        mr: true, 
        bl: true,
        br: true, 
        tl: true, 
        tr: true,
        mtr: true // rotation
    });

    canvas.add(group);
    canvas.setActiveObject(group);
    updateUIForSelection(group);
    triggerSave();
}

function addShape(type) {
    let shape;
    const center = { x: artboardBase.w / 2, y: artboardBase.h / 2 };
    const commonProps = {
        left: center.x,
        top: center.y,
        originX: 'center',
        originY: 'center',
        fill: '#4f46e5',
        strokeWidth: 0,
        strokeLineJoin: 'round',
        strokeLineCap: 'round',
        strokeMiterLimit: 10
    };

    if (type === 'rect') {
        shape = new fabric.Rect({
            ...commonProps,
            width: 200,
            height: 150
        });
    } else if (type === 'square') {
        shape = new fabric.Rect({
            ...commonProps,
            width: 150,
            height: 150
        });
    } else if (type === 'circle') {
        shape = new fabric.Circle({
            ...commonProps,
            radius: 75
        });
    } else if (type === 'triangle') {
        shape = new fabric.Polygon([
            { x: 0, y: -75 },
            { x: -65, y: 65 },
            { x: 65, y: 65 }
        ], {
            ...commonProps
        });
    } else if (type === 'arrow-right') {
        // Arrow pointing right
        const pathData = "M 0 20 L 80 20 L 80 0 L 120 40 L 80 80 L 80 60 L 0 60 Z";
        shape = new fabric.Path(pathData, {
            ...commonProps,
            scaleX: 1,
            scaleY: 1
        });
    } else if (type === 'arrow-left') {
        // Arrow pointing left
        const pathData = "M 120 20 L 40 20 L 40 0 L 0 40 L 40 80 L 40 60 L 120 60 Z";
        shape = new fabric.Path(pathData, {
            ...commonProps,
            scaleX: 1,
            scaleY: 1
        });
    } else if (type === 'arrow-up') {
        // Arrow pointing up
        const pathData = "M 20 120 L 20 40 L 0 40 L 40 0 L 80 40 L 60 40 L 60 120 Z";
        shape = new fabric.Path(pathData, {
            ...commonProps,
            scaleX: 1,
            scaleY: 1
        });
    } else if (type === 'arrow-down') {
        // Arrow pointing down
        const pathData = "M 20 0 L 20 80 L 0 80 L 40 120 L 80 80 L 60 80 L 60 0 Z";
        shape = new fabric.Path(pathData, {
            ...commonProps,
            scaleX: 1,
            scaleY: 1
        });
    } else if (type === 'arrow-double') {
        // Double-ended arrow (left-right)
        const pathData = "M 0 40 L 30 40 L 30 20 L 50 40 L 30 60 L 30 40 L 0 40 M 120 40 L 90 40 L 90 20 L 70 40 L 90 60 L 90 40 L 120 40";
        shape = new fabric.Path(pathData, {
            ...commonProps,
            scaleX: 1,
            scaleY: 1
        });
    } else if (type === 'arrow-curved') {
        // Curved arrow (right)
        const pathData = "M 20 80 Q 40 40, 80 40 L 80 20 L 100 40 L 80 60 L 80 40 Q 50 40, 30 70 Z";
        shape = new fabric.Path(pathData, {
            ...commonProps,
            scaleX: 1,
            scaleY: 1
        });
    } else if (type === 'star') {
        // 5-pointed star
        const points = [];
        const outerRadius = 75;
        const innerRadius = 30;
        const numPoints = 5;
        for (let i = 0; i < numPoints * 2; i++) {
            const radius = i % 2 === 0 ? outerRadius : innerRadius;
            const angle = (Math.PI / numPoints) * i - Math.PI / 2;
            points.push({
                x: Math.cos(angle) * radius,
                y: Math.sin(angle) * radius
            });
        }
        shape = new fabric.Polygon(points, {
            ...commonProps
        });
    } else if (type === 'heart') {
        // Classic heart shape with rounded lobes and sharp point
        const pathData = "M 0 30 C -10 20, -30 0, -45 -15 C -60 -30, -70 -50, -60 -65 C -50 -80, -25 -80, 0 -55 C 25 -80, 50 -80, 60 -65 C 70 -50, 60 -30, 45 -15 C 30 0, 10 20, 0 30 Z";
        shape = new fabric.Path(pathData, {
            ...commonProps,
            scaleX: 1.2,
            scaleY: 1.2
        });
    } else if (type === 'line') {
        // Simple line
        shape = new fabric.Line([0, 0, 150, 0], {
            ...commonProps,
            fill: null,
            stroke: '#4f46e5',
            strokeWidth: 3
        });
    } else if (type === 'speech-bubble') {
        // Speech bubble with tail
        const pathData = "M -60 -40 L 60 -40 Q 80 -40, 80 -20 L 80 20 Q 80 40, 60 40 L 10 40 L -10 60 L -5 40 L -60 40 Q -80 40, -80 20 L -80 -20 Q -80 -40, -60 -40 Z";
        shape = new fabric.Path(pathData, {
            ...commonProps,
            scaleX: 1,
            scaleY: 1
        });
    } else if (type === 'cloud') {
        // Cloud shape
        const pathData = "M -50 10 C -70 10, -80 -10, -65 -25 C -70 -45, -45 -55, -25 -45 C -15 -60, 15 -60, 30 -50 C 50 -65, 80 -45, 75 -20 C 95 -10, 85 20, 65 20 L -50 20 C -70 20, -75 10, -50 10 Z";
        shape = new fabric.Path(pathData, {
            ...commonProps,
            scaleX: 1.2,
            scaleY: 1.2
        });
    } else if (type === 'line-arrow-right') {
        // Thin line arrow right
        shape = new fabric.Path("M 0 40 L 100 40 M 80 20 L 100 40 L 80 60", {
            ...commonProps,
            fill: null,
            stroke: '#4f46e5',
            strokeWidth: 3
        });
    } else if (type === 'line-arrow-left') {
        // Thin line arrow left
        shape = new fabric.Path("M 100 40 L 0 40 M 20 20 L 0 40 L 20 60", {
            ...commonProps,
            fill: null,
            stroke: '#4f46e5',
            strokeWidth: 3
        });
    } else if (type === 'line-arrow-up') {
        // Thin line arrow up
        shape = new fabric.Path("M 40 100 L 40 0 M 20 20 L 40 0 L 60 20", {
            ...commonProps,
            fill: null,
            stroke: '#4f46e5',
            strokeWidth: 3
        });
    } else if (type === 'line-arrow-down') {
        // Thin line arrow down
        shape = new fabric.Path("M 40 0 L 40 100 M 20 80 L 40 100 L 60 80", {
            ...commonProps,
            fill: null,
            stroke: '#4f46e5',
            strokeWidth: 3
        });
    } else if (type === 'line-arrow-double') {
        // Thin double-ended arrow
        shape = new fabric.Path("M 20 20 L 0 40 L 20 60 M 0 40 L 120 40 M 100 20 L 120 40 L 100 60", {
            ...commonProps,
            fill: null,
            stroke: '#4f46e5',
            strokeWidth: 3
        });
    } else if (type === 'lightning') {
        // Lightning bolt shape
        const pathData = "M 50 0 L 20 50 L 40 50 L 10 100 L 55 45 L 35 45 L 65 0 Z";
        shape = new fabric.Path(pathData, {
            ...commonProps,
            scaleX: 1.5,
            scaleY: 1.5
        });
    }

    if (shape) {
        shape.set('name', generateDefaultName(shape.type));
        canvas.add(shape);
        canvas.setActiveObject(shape);
        updateUIForSelection(shape);
        triggerSave();
    }
    if(closeShapesModal) closeShapesModal.click();
}

function addEmoji(emojiChar) {
    const emoji = new fabric.IText(emojiChar, {
        left: artboardBase.w / 2,
        top: artboardBase.h / 2,
        originX: 'center',
        originY: 'center',
        fontSize: 100,
        fontFamily: 'Apple Color Emoji, Segoe UI Emoji, Noto Color Emoji', // Native emoji fonts
        selectable: true,
        strokeWidth: 0,
        strokeLineJoin: 'round',
        strokeLineCap: 'round',
        strokeMiterLimit: 10,
        name: generateDefaultName('emoji')
    });
    canvas.add(emoji);
    canvas.setActiveObject(emoji);
    updateUIForSelection(emoji);
    triggerSave();
    if(closeEmojiModal) closeEmojiModal.click();
}

// --- QR Code Functions ---
let qrCodeInstance = null;
let qrCurrentType = 'url';
let qrCurrentStyle = 'square';

// Content type input templates
const qrContentTemplates = {
    url: {
        label: 'Website URL *',
        placeholder: 'https://yourwebsite.com',
        defaultValue: 'https://example.com',
        inputType: 'text'
    },
    email: {
        label: 'Email Address *',
        placeholder: 'email@example.com',
        defaultValue: 'hello@example.com',
        inputType: 'email'
    },
    phone: {
        label: 'Phone Number *',
        placeholder: '+1234567890',
        defaultValue: '+1234567890',
        inputType: 'tel'
    },
    sms: {
        label: 'Phone Number *',
        placeholder: '+1234567890',
        defaultValue: '+1234567890',
        inputType: 'tel'
    },
    vcard: {
        label: 'V-Card Data',
        placeholder: 'Name, Phone, Email...',
        defaultValue: '',
        inputType: 'vcard'
    },
    text: {
        label: 'Text Content *',
        placeholder: 'Enter your text here...',
        defaultValue: 'Hello World!',
        inputType: 'textarea'
    }
};

function getQRData() {
    // Always get fresh reference since input is dynamically recreated
    const inputEl = document.getElementById('qrUrl');
    const value = inputEl ? inputEl.value : '';
    
    switch (qrCurrentType) {
        case 'url':
            return value;
        case 'email':
            return `mailto:${value}`;
        case 'phone':
            return `tel:${value}`;
        case 'sms':
            return `sms:${value}`;
        case 'vcard':
            // Simple vCard format
            const name = document.getElementById('qrVCardName')?.value || '';
            const phone = document.getElementById('qrVCardPhone')?.value || '';
            const email = document.getElementById('qrVCardEmail')?.value || '';
            const org = document.getElementById('qrVCardOrg')?.value || '';
            return `BEGIN:VCARD\nVERSION:3.0\nFN:${name}\nTEL:${phone}\nEMAIL:${email}\nORG:${org}\nEND:VCARD`;
        case 'text':
        default:
            return value;
    }
}

function updateQRContentSection(type) {
    // Always get fresh reference
    const contentSection = document.getElementById('qrContentSection');
    if (!contentSection) return;
    
    const template = qrContentTemplates[type];
    
    if (type === 'vcard') {
        contentSection.innerHTML = `
            <label class="block text-xs font-bold text-zinc-400 uppercase tracking-wider mb-3">V-Card Details</label>
            <div class="space-y-3" id="qrVCardData">
                <div>
                    <label class="text-xs text-zinc-500 mb-1 block">Full Name *</label>
                    <input type="text" id="qrVCardName" value="John Doe" class="w-full border border-zinc-300 rounded-lg p-2.5 text-sm focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 outline-none" placeholder="John Doe">
                </div>
                <div>
                    <label class="text-xs text-zinc-500 mb-1 block">Phone</label>
                    <input type="tel" id="qrVCardPhone" value="+1234567890" class="w-full border border-zinc-300 rounded-lg p-2.5 text-sm focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 outline-none" placeholder="+1234567890">
                </div>
                <div>
                    <label class="text-xs text-zinc-500 mb-1 block">Email</label>
                    <input type="email" id="qrVCardEmail" value="john@example.com" class="w-full border border-zinc-300 rounded-lg p-2.5 text-sm focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 outline-none" placeholder="email@example.com">
                </div>
                <div>
                    <label class="text-xs text-zinc-500 mb-1 block">Organization</label>
                    <input type="text" id="qrVCardOrg" value="" class="w-full border border-zinc-300 rounded-lg p-2.5 text-sm focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 outline-none" placeholder="Company Name">
                </div>
            </div>
        `;
        // Add event listeners to vCard inputs
        setTimeout(() => {
            const section = document.getElementById('qrContentSection');
            if (section) {
                const vCardInputs = section.querySelectorAll('input');
                vCardInputs.forEach(input => {
                    input.addEventListener('input', updateQRPreview);
                });
            }
            updateQRPreview();
        }, 10);
    } else if (template.inputType === 'textarea') {
        contentSection.innerHTML = `
            <label class="block text-xs font-bold text-zinc-400 uppercase tracking-wider mb-2">${template.label}</label>
            <textarea id="qrUrl" class="w-full border border-zinc-300 rounded-lg p-3 text-sm focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 outline-none h-24 resize-none" placeholder="${template.placeholder}">${template.defaultValue}</textarea>
        `;
    } else {
        contentSection.innerHTML = `
            <label class="block text-xs font-bold text-zinc-400 uppercase tracking-wider mb-2">${template.label}</label>
            <input type="${template.inputType}" id="qrUrl" value="${template.defaultValue}" class="w-full border border-zinc-300 rounded-lg p-3 text-sm focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20 outline-none" placeholder="${template.placeholder}">
        `;
    }
    
    // Re-attach event listener to new input
    const newInput = document.getElementById('qrUrl');
    if (newInput) {
        newInput.addEventListener('input', updateQRPreview);
    }
}

function updateQRPreview() {
    // Always get fresh references
    const previewEl = document.getElementById('qrPreview');
    if (!previewEl) return;
    
    // Clear previous QR code
    previewEl.innerHTML = '';
    
    const data = getQRData();
    if (!data) {
        previewEl.innerHTML = '<p class="text-zinc-400 text-sm">Enter content to generate QR code</p>';
        return;
    }
    
    // Get fresh references for all inputs
    const colorInput = document.getElementById('qrColor');
    const bgColorInput = document.getElementById('qrBgColor');
    const cornerSquareSelect = document.getElementById('qrCornerSquareStyle');
    const cornerDotSelect = document.getElementById('qrCornerDotStyle');
    const errorCorrectionSelect = document.getElementById('qrErrorCorrection');
    
    const dotColor = colorInput ? colorInput.value : '#000000';
    const bgColor = bgColorInput ? bgColorInput.value : '#FFFFFF';
    const cornerSquare = cornerSquareSelect ? cornerSquareSelect.value : 'square';
    const cornerDot = cornerDotSelect ? cornerDotSelect.value : 'square';
    const errorCorrection = errorCorrectionSelect ? errorCorrectionSelect.value : 'M';
    
    qrCodeInstance = new QRCodeStyling({
        width: 220,
        height: 220,
        data: data,
        dotsOptions: {
            color: dotColor,
            type: qrCurrentStyle
        },
        cornersSquareOptions: {
            color: dotColor,
            type: cornerSquare
        },
        cornersDotOptions: {
            color: dotColor,
            type: cornerDot
        },
        backgroundOptions: {
            color: bgColor
        },
        qrOptions: {
            errorCorrectionLevel: errorCorrection
        }
    });
    
    qrCodeInstance.append(previewEl);
}

async function addQRCodeToCanvas() {
    // Generate high-res QR code for canvas
    const data = getQRData();
    if (!data) return;
    
    // Get fresh references for all inputs
    const colorInput = document.getElementById('qrColor');
    const bgColorInput = document.getElementById('qrBgColor');
    const cornerSquareSelect = document.getElementById('qrCornerSquareStyle');
    const cornerDotSelect = document.getElementById('qrCornerDotStyle');
    const errorCorrectionSelect = document.getElementById('qrErrorCorrection');
    
    const dotColor = colorInput ? colorInput.value : '#000000';
    const bgColor = bgColorInput ? bgColorInput.value : '#FFFFFF';
    const cornerSquare = cornerSquareSelect ? cornerSquareSelect.value : 'square';
    const cornerDot = cornerDotSelect ? cornerDotSelect.value : 'square';
    const errorCorrection = errorCorrectionSelect ? errorCorrectionSelect.value : 'M';
    
    const highResQR = new QRCodeStyling({
        width: 400,
        height: 400,
        data: data,
        dotsOptions: {
            color: dotColor,
            type: qrCurrentStyle
        },
        cornersSquareOptions: {
            color: dotColor,
            type: cornerSquare
        },
        cornersDotOptions: {
            color: dotColor,
            type: cornerDot
        },
        backgroundOptions: {
            color: bgColor
        },
        qrOptions: {
            errorCorrectionLevel: errorCorrection
        }
    });
    
    try {
        const blob = await highResQR.getRawData('png');
        const url = URL.createObjectURL(blob);
        
        fabric.Image.fromURL(url, function(img) {
            img.set({
                left: artboardBase.w / 2,
                top: artboardBase.h / 2,
                originX: 'center',
                originY: 'center',
                scaleX: 0.5,
                scaleY: 0.5,
                name: generateDefaultName('qrcode')
            });
            canvas.add(img);
            canvas.setActiveObject(img);
            updateUIForSelection(img);
            triggerSave();
            
            // Clean up blob URL
            URL.revokeObjectURL(url);
        });
        
        // Close modal
        const modal = document.getElementById('qrModal');
        if (modal) {
            modal.classList.add('hidden');
            modal.classList.remove('flex');
        }
    } catch (error) {
        console.error('Error generating QR code:', error);
    }
}

function initQRCodeModal() {
    // Content Type Buttons
    const typeButtons = document.querySelectorAll('.qr-type-btn');
    typeButtons.forEach(btn => {
        btn.addEventListener('click', () => {
            // Update active state
            typeButtons.forEach(b => {
                b.classList.remove('border-2', 'border-indigo-500', 'bg-indigo-50', 'text-indigo-600');
                b.classList.add('border', 'border-zinc-200', 'text-zinc-500');
            });
            btn.classList.remove('border', 'border-zinc-200', 'text-zinc-500');
            btn.classList.add('border-2', 'border-indigo-500', 'bg-indigo-50', 'text-indigo-600');
            
            qrCurrentType = btn.dataset.type;
            updateQRContentSection(qrCurrentType);
            // Small delay to ensure DOM is updated
            setTimeout(() => updateQRPreview(), 10);
        });
    });
    
    // Style Buttons
    const styleButtons = document.querySelectorAll('.qr-style-btn');
    styleButtons.forEach(btn => {
        btn.addEventListener('click', () => {
            // Update active state
            styleButtons.forEach(b => {
                b.classList.remove('border-2', 'border-indigo-500', 'bg-indigo-50');
                b.classList.add('border', 'border-zinc-200');
            });
            btn.classList.remove('border', 'border-zinc-200');
            btn.classList.add('border-2', 'border-indigo-500', 'bg-indigo-50');
            
            qrCurrentStyle = btn.dataset.style;
            updateQRPreview();
        });
    });
    
    // Color inputs
    if (qrColor) {
        qrColor.addEventListener('input', () => {
            if (qrColorDisplay) qrColorDisplay.style.backgroundColor = qrColor.value;
            if (qrColorText) qrColorText.value = qrColor.value.toUpperCase();
            updateQRPreview();
        });
    }
    
    if (qrColorText) {
        qrColorText.addEventListener('input', () => {
            const val = qrColorText.value;
            if (/^#[0-9A-Fa-f]{6}$/.test(val)) {
                if (qrColor) qrColor.value = val;
                if (qrColorDisplay) qrColorDisplay.style.backgroundColor = val;
                updateQRPreview();
            }
        });
    }
    
    if (qrBgColor) {
        qrBgColor.addEventListener('input', () => {
            if (qrBgColorDisplay) qrBgColorDisplay.style.backgroundColor = qrBgColor.value;
            if (qrBgColorText) qrBgColorText.value = qrBgColor.value.toUpperCase();
            updateQRPreview();
        });
    }
    
    if (qrBgColorText) {
        qrBgColorText.addEventListener('input', () => {
            const val = qrBgColorText.value;
            if (/^#[0-9A-Fa-f]{6}$/.test(val)) {
                if (qrBgColor) qrBgColor.value = val;
                if (qrBgColorDisplay) qrBgColorDisplay.style.backgroundColor = val;
                updateQRPreview();
            }
        });
    }
    
    // Corner style selects
    if (qrCornerSquareStyle) {
        qrCornerSquareStyle.addEventListener('change', updateQRPreview);
    }
    
    if (qrCornerDotStyle) {
        qrCornerDotStyle.addEventListener('change', updateQRPreview);
    }
    
    // Error correction select
    if (qrErrorCorrection) {
        qrErrorCorrection.addEventListener('change', updateQRPreview);
    }
    
    // URL/content input
    if (qrUrl) {
        qrUrl.addEventListener('input', updateQRPreview);
    }
    
    // Insert button
    if (insertQRBtn) {
        insertQRBtn.addEventListener('click', addQRCodeToCanvas);
    }
}

function updateUIForSelection(obj) {
    if(!objectControls || !deleteObjBtn || !propertiesTitle) return;

    if (!obj) {
        objectControls.classList.add('opacity-50', 'pointer-events-none');
        deleteObjBtn.classList.add('hidden');
        propertiesTitle.innerText = "Properties";
        activeObject = null;
        if(rotationInput) rotationInput.value = 0;
        if(rotationValue) rotationValue.innerText = 0;
        if(objectName) objectName.value = '';
        return;
    }

    activeObject = obj;
    
    // Ensure the selection border is visible and updated
    obj.set({
        borderColor: '#4f46e5',
        cornerColor: '#ffffff',
        cornerStrokeColor: '#4f46e5',
        transparentCorners: false,
        cornerSize: 12,
        padding: 10
    });
    canvas.requestRenderAll();

    objectControls.classList.remove('opacity-50', 'pointer-events-none');
    deleteObjBtn.classList.remove('hidden');
    
    // Name field
    if(objectName) {
        // If object doesn't have a name, generate one
        if(!obj.name) {
            obj.set('name', generateDefaultName(obj.type));
        }
        objectName.value = obj.name || '';
    }
    
    // Rotation
    if(rotationInput && rotationValue) {
        const angle = Math.round(obj.angle % 360);
        const normalizedAngle = angle < 0 ? 360 + angle : angle;
        rotationInput.value = normalizedAngle;
        rotationValue.innerText = normalizedAngle;
    }

    const isText = obj.type === 'i-text' || obj.type === 'text';
    const isShape = obj.type === 'rect' || obj.type === 'circle' || obj.type === 'path' || obj.type === 'polygon';
    const isButton = obj.isButton === true; // Check custom flag

    // Toggle Specific Controls
    if (isButton) {
        // Show both Text and Shape controls
        if(textSpecificControls) textSpecificControls.style.display = 'block';
        if(shapeSpecificControls) shapeSpecificControls.classList.remove('hidden');
        
        // Corner Radius Control
        if(cornerRadiusControl) cornerRadiusControl.classList.remove('hidden');
        
        propertiesTitle.innerText = "Button Properties";

        const items = obj.getObjects();
        const rectObj = items[0];
        const textObj = items[1];

        // Text Properties
        if(textContent) textContent.value = textObj.text;
        updateFontPickerUI(textObj.fontFamily);
        if(textColor) textColor.value = textObj.fill;
        if(textColorPreview) textColorPreview.querySelector('div').style.backgroundColor = textObj.fill;
        if(fontSizeInput) fontSizeInput.value = textObj.fontSize;

        // Toggles (Text)
        if(boldBtn) {
            boldBtn.classList.toggle('bg-indigo-100', textObj.fontWeight === 'bold');
            boldBtn.classList.toggle('text-indigo-700', textObj.fontWeight === 'bold');
        }
        if(italicBtn) {
            italicBtn.classList.toggle('bg-indigo-100', textObj.fontStyle === 'italic');
            italicBtn.classList.toggle('text-indigo-700', textObj.fontStyle === 'italic');
        }

        // Shape Properties (Background)
        if(shapeColor) shapeColor.value = rectObj.fill;
        if(shapeColorPreview) shapeColorPreview.querySelector('div').style.backgroundColor = rectObj.fill;
        
        // Corner Radius Values
        if(cornerRadiusInput && cornerRadiusValue) {
            const radius = rectObj.rx || 0;
            cornerRadiusInput.value = radius;
            cornerRadiusValue.innerText = radius;
        }

    } else if (isText) {
        if(textSpecificControls) textSpecificControls.style.display = 'block';
        if(shapeSpecificControls) shapeSpecificControls.classList.add('hidden');
        if(cornerRadiusControl) cornerRadiusControl.classList.add('hidden');
        propertiesTitle.innerText = "Text Properties";
        
        // Fill values
        if(textContent) textContent.value = obj.text;
        updateFontPickerUI(obj.fontFamily);
        if(textColor) textColor.value = obj.fill;
        if(textColorPreview) textColorPreview.querySelector('div').style.backgroundColor = obj.fill;

        // Font Size & Alignment
        if(fontSizeInput) fontSizeInput.value = obj.fontSize || 40;
        
        if(alignLeftBtn) {
             alignLeftBtn.classList.toggle('bg-indigo-100', obj.textAlign === 'left');
             alignLeftBtn.classList.toggle('text-indigo-700', obj.textAlign === 'left');
        }
        if(alignCenterBtn) {
             alignCenterBtn.classList.toggle('bg-indigo-100', obj.textAlign === 'center');
             alignCenterBtn.classList.toggle('text-indigo-700', obj.textAlign === 'center');
        }
        if(alignRightBtn) {
             alignRightBtn.classList.toggle('bg-indigo-100', obj.textAlign === 'right');
             alignRightBtn.classList.toggle('text-indigo-700', obj.textAlign === 'right');
        }

        // Toggles
        if(boldBtn) {
            boldBtn.classList.toggle('bg-indigo-100', obj.fontWeight === 'bold');
            boldBtn.classList.toggle('text-indigo-700', obj.fontWeight === 'bold');
        }
        if(italicBtn) {
            italicBtn.classList.toggle('bg-indigo-100', obj.fontStyle === 'italic');
            italicBtn.classList.toggle('text-indigo-700', obj.fontStyle === 'italic');
        }
    } else if (isShape) {
        if(textSpecificControls) textSpecificControls.style.display = 'none';
        if(shapeSpecificControls) shapeSpecificControls.classList.remove('hidden');
        if(cornerRadiusControl) cornerRadiusControl.classList.add('hidden'); // Hide for general shapes for now (unless we want to support rect radius)
        
        // Support corner radius for loose Rectangles too if we want
        if (obj.type === 'rect') {
            if(cornerRadiusControl) {
                cornerRadiusControl.classList.remove('hidden');
                cornerRadiusInput.value = obj.rx || 0;
                cornerRadiusValue.innerText = obj.rx || 0;
            }
        }

        propertiesTitle.innerText = "Shape Properties";
        
        // Shape Color
        if(shapeColor) shapeColor.value = obj.fill;
        if(shapeColorPreview) shapeColorPreview.querySelector('div').style.backgroundColor = obj.fill;
    } else {
        // Image or other object
        if(textSpecificControls) textSpecificControls.style.display = 'none';
        if(shapeSpecificControls) shapeSpecificControls.classList.add('hidden');
        if(cornerRadiusControl) cornerRadiusControl.classList.add('hidden');
        propertiesTitle.innerText = "Image Properties";
    }

    // Common Controls (Stroke & Shadow)
    // Stroke
    const targetForStroke = isButton ? obj.getObjects()[0] : obj; // Stroke on rect for button
    const hasStroke = targetForStroke.strokeWidth > 0;
    
    if(enableStroke) enableStroke.checked = hasStroke;
    if(strokeControls) {
        strokeControls.classList.toggle('opacity-50', !hasStroke);
        strokeControls.classList.toggle('pointer-events-none', !hasStroke);
    }
    if (hasStroke) {
        if(strokeColor) strokeColor.value = targetForStroke.stroke || '#000000';
        if(strokeColorDisplay) strokeColorDisplay.style.backgroundColor = targetForStroke.stroke || '#000000';
        if(strokeWidth) strokeWidth.value = targetForStroke.strokeWidth;
    } else {
        // Preserve stroke color even when disabled, or use default
        if(strokeColor) {
            strokeColor.value = targetForStroke.stroke || '#000000';
        }
        if(strokeColorDisplay) {
            strokeColorDisplay.style.backgroundColor = targetForStroke.stroke || '#000000';
        }
        if(strokeWidth) strokeWidth.value = 0; 
    }

    // Shadow
    const targetForShadow = isButton ? obj.getObjects()[0] : obj; // Shadow on rect for button
    const hasShadow = targetForShadow.shadow && targetForShadow.shadow.blur > 0;
    
    if(enableShadow) enableShadow.checked = hasShadow;
    if(shadowControls) {
        shadowControls.classList.toggle('opacity-50', !hasShadow);
        shadowControls.classList.toggle('pointer-events-none', !hasShadow);
    }
    if (targetForShadow.shadow) {
        if(shadowColor) shadowColor.value = targetForShadow.shadow.color;
        if(shadowColorDisplay) shadowColorDisplay.style.backgroundColor = targetForShadow.shadow.color;
        if(shadowBlur) shadowBlur.value = targetForShadow.shadow.blur;
        if(shadowOffsetX) shadowOffsetX.value = targetForShadow.shadow.offsetX;
        if(shadowOffsetY) shadowOffsetY.value = targetForShadow.shadow.offsetY;
    }
}

function applyShadow() {
    if (!activeObject || !enableShadow) return;
    
    const target = (activeObject.isButton) ? activeObject.getObjects()[0] : activeObject;

    if (enableShadow.checked) {
        target.set('shadow', new fabric.Shadow({
            color: shadowColor ? shadowColor.value : '#000000',
            blur: shadowBlur ? parseInt(shadowBlur.value, 10) : 10,
            offsetX: shadowOffsetX ? parseInt(shadowOffsetX.value, 10) : 5,
            offsetY: shadowOffsetY ? parseInt(shadowOffsetY.value, 10) : 5
        }));
        if(shadowControls) shadowControls.classList.remove('opacity-50', 'pointer-events-none');
    } else {
        target.set('shadow', null);
        if(shadowControls) shadowControls.classList.add('opacity-50', 'pointer-events-none');
    }
    
    if (activeObject.isButton) activeObject.addWithUpdate(); // Update group
    canvas.requestRenderAll();
    triggerSave();
}

// --- Code Snippet Logic ---

function updateCodePreview() {
    if(!codeInput || !codePreview) return;
    const code = codeInput.value || " // Write code here...";
    const lang = codeLanguage ? codeLanguage.value : 'javascript';
    
    // Reset class and content
    codePreview.className = `language-${lang} bg-transparent !p-0 text-sm font-mono leading-relaxed`;
    codePreview.textContent = code;
    
    // Apply Highlight.js
    hljs.highlightElement(codePreview);
}

function openCodeModal() {
    if(!codeModal) return;
    codeModal.classList.remove('hidden');
    codeModal.classList.add('flex');
    if(codeInput && codeInput.value === '') {
         codeInput.value = `function helloWorld() {\n  console.log("Hello Canvas!");\n}`;
         updateCodePreview();
    }
}

function closeCodeModalFunc() {
    if(!codeModal) return;
    codeModal.classList.add('hidden');
    codeModal.classList.remove('flex');
}

// --- Event Listeners (Guarded) ---

// Code Snippet
if(addCodeBtn) addCodeBtn.addEventListener('click', openCodeModal);
if(closeCodeModal) closeCodeModal.addEventListener('click', closeCodeModalFunc);
if(cancelCodeBtn) cancelCodeBtn.addEventListener('click', closeCodeModalFunc);
if(codeInput) codeInput.addEventListener('input', updateCodePreview);
if(codeLanguage) codeLanguage.addEventListener('change', updateCodePreview);

if(insertCodeBtn) {
    insertCodeBtn.addEventListener('click', () => {
        if(!codeCapture) return;
        // Use html2canvas to create image from the preview div
        insertCodeBtn.innerText = "Generating...";
        insertCodeBtn.disabled = true;

        html2canvas(codeCapture, {
            backgroundColor: null, // transparent
            scale: 2 // High resolution
        }).then(canvasEl => {
            const imgData = canvasEl.toDataURL('image/png');
            
            fabric.Image.fromURL(imgData, function(img) {
                // Scale down slightly if it's huge
                const targetWidth = artboardBase.w * 0.6;
                const scale = (img.width > targetWidth) ? (targetWidth / img.width) : 1;

                img.set({
                    left: artboardBase.w / 2,
                    top: artboardBase.h / 2,
                    originX: 'center',
                    originY: 'center',
                    scaleX: scale,
                    scaleY: scale,
                    name: generateDefaultName('code')
                });
                
                canvas.add(img);
                canvas.setActiveObject(img);
                updateUIForSelection(img);
                
                // Reset UI
                closeCodeModalFunc();
                insertCodeBtn.innerText = "Add to Canvas";
                insertCodeBtn.disabled = false;
                triggerSave();
            });
        });
    });
}

// Emoji
if(addEmojiBtn) addEmojiBtn.addEventListener('click', () => {
    if(emojiModal) {
        emojiModal.classList.remove('hidden');
        emojiModal.classList.add('flex');
    }
});
if(closeEmojiModal) closeEmojiModal.addEventListener('click', () => {
     if(emojiModal) {
         emojiModal.classList.add('hidden');
         emojiModal.classList.remove('flex');
     }
});

// Shapes
if(addShapesBtn) addShapesBtn.addEventListener('click', () => {
     if(shapesModal) {
         shapesModal.classList.remove('hidden');
         shapesModal.classList.add('flex');
     }
});
if(closeShapesModal) closeShapesModal.addEventListener('click', () => {
     if(shapesModal) {
         shapesModal.classList.add('hidden');
         shapesModal.classList.remove('flex');
     }
});

if(shapeBtns) {
    shapeBtns.forEach(btn => {
        btn.addEventListener('click', () => {
            const type = btn.dataset.shape;
            addShape(type);
        });
    });
}

// QR Code Modal
if(addQRCodeBtn) addQRCodeBtn.addEventListener('click', () => {
    const modal = document.getElementById('qrModal');
    if(modal) {
        // Reset to URL type when opening
        qrCurrentType = 'url';
        qrCurrentStyle = 'square';
        
        // Reset content section to URL
        updateQRContentSection('url');
        
        // Reset type button states
        const typeButtons = document.querySelectorAll('.qr-type-btn');
        typeButtons.forEach(b => {
            b.classList.remove('border-2', 'border-indigo-500', 'bg-indigo-50', 'text-indigo-600');
            b.classList.add('border', 'border-zinc-200', 'text-zinc-500');
        });
        const urlBtn = document.querySelector('.qr-type-btn[data-type="url"]');
        if (urlBtn) {
            urlBtn.classList.remove('border', 'border-zinc-200', 'text-zinc-500');
            urlBtn.classList.add('border-2', 'border-indigo-500', 'bg-indigo-50', 'text-indigo-600');
        }
        
        // Reset style button states
        const styleButtons = document.querySelectorAll('.qr-style-btn');
        styleButtons.forEach(b => {
            b.classList.remove('border-2', 'border-indigo-500', 'bg-indigo-50');
            b.classList.add('border', 'border-zinc-200');
        });
        const squareBtn = document.querySelector('.qr-style-btn[data-style="square"]');
        if (squareBtn) {
            squareBtn.classList.remove('border', 'border-zinc-200');
            squareBtn.classList.add('border-2', 'border-indigo-500', 'bg-indigo-50');
        }
        
        modal.classList.remove('hidden');
        modal.classList.add('flex');
        
        // Initialize and show preview after a small delay
        setTimeout(() => updateQRPreview(), 20);
    }
});
if(closeQRModal) closeQRModal.addEventListener('click', () => {
    const modal = document.getElementById('qrModal');
    if(modal) {
        modal.classList.add('hidden');
        modal.classList.remove('flex');
    }
});
if(cancelQRBtn) cancelQRBtn.addEventListener('click', () => {
    const modal = document.getElementById('qrModal');
    if(modal) {
        modal.classList.add('hidden');
        modal.classList.remove('flex');
    }
});

// Initialize QR Code Modal
initQRCodeModal();

// Shape Color
if(shapeColor) shapeColor.addEventListener('input', (e) => {
     if (activeObject) {
        if (activeObject.isButton) {
            activeObject.getObjects()[0].set('fill', e.target.value);
            activeObject.dirty = true; // Mark group as dirty so it redraws with new color
        } else {
            activeObject.set('fill', e.target.value);
        }
        if(shapeColorPreview) shapeColorPreview.querySelector('div').style.backgroundColor = e.target.value;
        canvas.requestRenderAll();
        triggerSave();
    }
});

// Corner Radius
if(cornerRadiusInput) cornerRadiusInput.addEventListener('input', (e) => {
    if (activeObject) {
        const val = parseInt(e.target.value, 10);
        if (cornerRadiusValue) cornerRadiusValue.innerText = val;
        
        if (activeObject.isButton) {
            const rect = activeObject.getObjects()[0];
            rect.set('rx', val);
            rect.set('ry', val);
            activeObject.dirty = true;
            canvas.requestRenderAll();
            triggerSave();
        } else if (activeObject.type === 'rect') {
            activeObject.set('rx', val);
            activeObject.set('ry', val);
            canvas.requestRenderAll();
            triggerSave();
        }
    }
});

// Rotation
if(rotationInput) rotationInput.addEventListener('input', (e) => {
     if(activeObject) {
         const val = parseInt(e.target.value, 10);
         activeObject.set('angle', val);
         canvas.requestRenderAll();
         if(rotationValue) rotationValue.innerText = val;
         triggerSave();
     }
});

// Zoom
if(zoomInBtn) zoomInBtn.addEventListener('click', () => applyZoom(zoomLevel + 0.25));
if(zoomOutBtn) zoomOutBtn.addEventListener('click', () => applyZoom(zoomLevel - 0.25));

// Canvas Resizing
if(canvasPreset) canvasPreset.addEventListener('change', (e) => {
    const val = e.target.value;
    if(val === 'custom') return;
    
    const [w, h] = val.split('x').map(Number);
    if(canvasWidthInput) canvasWidthInput.value = w;
    if(canvasHeightInput) canvasHeightInput.value = h;
    resizeCanvas(w, h);
});

const handleCustomResize = () => {
    if(canvasPreset) canvasPreset.value = 'custom';
    const w = canvasWidthInput ? (parseInt(canvasWidthInput.value) || 800) : 800;
    const h = canvasHeightInput ? (parseInt(canvasHeightInput.value) || 600) : 600;
    resizeCanvas(w, h);
}

if(canvasWidthInput) canvasWidthInput.addEventListener('change', handleCustomResize);
if(canvasHeightInput) canvasHeightInput.addEventListener('change', handleCustomResize);

// Layer Management
if(bringFrontBtn) bringFrontBtn.onclick = () => { if(activeObject) { canvas.bringToFront(activeObject); canvas.renderAll(); triggerSave(); } };
if(bringForwardBtn) bringForwardBtn.onclick = () => { if(activeObject) { canvas.bringForward(activeObject); canvas.renderAll(); triggerSave(); } };
if(sendBackwardBtn) sendBackwardBtn.onclick = () => { if(activeObject) { canvas.sendBackwards(activeObject); canvas.renderAll(); triggerSave(); } };
if(sendBackBtn) sendBackBtn.onclick = () => { if(activeObject) { canvas.sendToBack(activeObject); canvas.renderAll(); triggerSave(); } };


// Background
if(bgColor1) bgColor1.addEventListener('input', () => { updateBackground(); triggerSave(); });
if(bgColor2) bgColor2.addEventListener('input', () => { updateBackground(); triggerSave(); });
if(bgDirection) bgDirection.addEventListener('change', () => { updateBackground(); triggerSave(); });

// Background Type Toggle
if(bgTypeSolid) bgTypeSolid.addEventListener('click', () => {
    bgType = 'solid';
    updateBgTypeUI();
    updateBackground();
    triggerSave();
});
if(bgTypeGradient) bgTypeGradient.addEventListener('click', () => {
    bgType = 'gradient';
    updateBgTypeUI();
    updateBackground();
    triggerSave();
});

// Solid Background Color
if(bgSolidColor) bgSolidColor.addEventListener('input', () => {
    if(bgSolidColorBtn) bgSolidColorBtn.style.backgroundColor = bgSolidColor.value;
    if(bgSolidColorHex) bgSolidColorHex.value = bgSolidColor.value.toUpperCase();
    updateBackground();
    triggerSave();
});
if(bgSolidColorHex) bgSolidColorHex.addEventListener('input', (e) => {
    let val = e.target.value.trim();
    if (!val.startsWith('#')) val = '#' + val;
    if (/^#[0-9A-Fa-f]{6}$/.test(val)) {
        if(bgSolidColor) bgSolidColor.value = val;
        if(bgSolidColorBtn) bgSolidColorBtn.style.backgroundColor = val;
        updateBackground();
        triggerSave();
    }
});
if(bgSolidColorHex) bgSolidColorHex.addEventListener('blur', (e) => {
    // On blur, format the value
    let val = e.target.value.trim();
    if (!val.startsWith('#')) val = '#' + val;
    if (/^#[0-9A-Fa-f]{6}$/.test(val)) {
        e.target.value = val.toUpperCase();
    } else if (bgSolidColor) {
        e.target.value = bgSolidColor.value.toUpperCase();
    }
});

// Canvas Objects
canvas.on('selection:created', (e) => updateUIForSelection(e.selected[0]));
canvas.on('selection:updated', (e) => updateUIForSelection(e.selected[0]));
canvas.on('selection:cleared', () => updateUIForSelection(null));

// Object Name - with validation to prevent spaces, dots, and special characters
if(objectName) {
    objectName.addEventListener('input', (e) => {
        // Remove any invalid characters (only allow alphanumeric and underscore)
        const sanitized = e.target.value.replace(/[^a-zA-Z0-9_]/g, '');
        if (sanitized !== e.target.value) {
            e.target.value = sanitized;
        }
        if (activeObject) {
            activeObject.set('name', sanitized || '');
            triggerSave();
        }
    });
    
    // Also prevent paste of invalid characters
    objectName.addEventListener('paste', (e) => {
        e.preventDefault();
        const pasted = (e.clipboardData || window.clipboardData).getData('text');
        const sanitized = pasted.replace(/[^a-zA-Z0-9_]/g, '');
        const start = e.target.selectionStart;
        const end = e.target.selectionEnd;
        const currentValue = e.target.value;
        e.target.value = currentValue.substring(0, start) + sanitized + currentValue.substring(end);
        e.target.setSelectionRange(start + sanitized.length, start + sanitized.length);
        if (activeObject) {
            activeObject.set('name', e.target.value || '');
            triggerSave();
        }
    });
}

if(addButtonBtn) addButtonBtn.addEventListener('click', addButton);

// Text Content
if(textContent) textContent.addEventListener('input', (e) => {
    if (activeObject) {
        if (activeObject.isButton) {
             activeObject.getObjects()[1].set('text', e.target.value);
             activeObject.addWithUpdate(); // Recalculate group bounds
             canvas.requestRenderAll();
             triggerSave();
        } else if (activeObject.type === 'i-text') {
            activeObject.set('text', e.target.value);
            canvas.requestRenderAll();
            triggerSave(); 
        }
    }
});

canvas.on('text:changed', (e) => {
     if (activeObject && activeObject === e.target && textContent) {
         textContent.value = e.target.text;
     }
});

// Color
if(textColor) textColor.addEventListener('input', (e) => {
    if (activeObject) {
        if (activeObject.isButton) {
            activeObject.getObjects()[1].set('fill', e.target.value);
            activeObject.dirty = true; // Mark group as dirty
            if(textColorPreview) textColorPreview.querySelector('div').style.backgroundColor = e.target.value;
            canvas.requestRenderAll();
            triggerSave();
        } else if (activeObject.type === 'i-text') {
            activeObject.set('fill', e.target.value);
            if(textColorPreview) textColorPreview.querySelector('div').style.backgroundColor = e.target.value;
            canvas.requestRenderAll();
            triggerSave();
        }
    }
});

// Style Toggles
if(boldBtn) boldBtn.addEventListener('click', () => {
    if (activeObject) {
        if (activeObject.isButton) {
            const textObj = activeObject.getObjects()[1];
            const isBold = textObj.fontWeight === 'bold';
            textObj.set('fontWeight', isBold ? 'normal' : 'bold');
            activeObject.addWithUpdate();
            
            // Update UI state manually since updateUIForSelection might be overkill or needed
            boldBtn.classList.toggle('bg-indigo-100', !isBold);
            boldBtn.classList.toggle('text-indigo-700', !isBold);
            
            canvas.requestRenderAll();
            triggerSave();
        } else if (activeObject.type === 'i-text') {
            // Check for selection
            if (activeObject.selectionStart !== activeObject.selectionEnd) {
                 const styles = activeObject.getSelectionStyles();
                 const isBold = styles.find(s => s.fontWeight === 'bold');
                 activeObject.setSelectionStyles({ fontWeight: isBold ? 'normal' : 'bold' });
            } else {
                const isBold = activeObject.fontWeight === 'bold';
                activeObject.set('fontWeight', isBold ? 'normal' : 'bold');
            }
            updateUIForSelection(activeObject);
            canvas.requestRenderAll();
            triggerSave();
        }
    }
});

if(italicBtn) italicBtn.addEventListener('click', () => {
    if (activeObject) {
        if (activeObject.isButton) {
             const textObj = activeObject.getObjects()[1];
             const isItalic = textObj.fontStyle === 'italic';
             textObj.set('fontStyle', isItalic ? 'normal' : 'italic');
             activeObject.addWithUpdate();

             italicBtn.classList.toggle('bg-indigo-100', !isItalic);
             italicBtn.classList.toggle('text-indigo-700', !isItalic);

             canvas.requestRenderAll();
             triggerSave();
        } else if (activeObject.type === 'i-text') {
             // Check for selection
            if (activeObject.selectionStart !== activeObject.selectionEnd) {
                 const styles = activeObject.getSelectionStyles();
                 const isItalic = styles.find(s => s.fontStyle === 'italic');
                 activeObject.setSelectionStyles({ fontStyle: isItalic ? 'normal' : 'italic' });
            } else {
                const isItalic = activeObject.fontStyle === 'italic';
                activeObject.set('fontStyle', isItalic ? 'normal' : 'italic');
            }
            updateUIForSelection(activeObject);
            canvas.requestRenderAll();
            triggerSave();
        }
    }
});

// Font Size
if(fontSizeInput) fontSizeInput.addEventListener('input', (e) => {
    if (activeObject) {
        const size = parseInt(e.target.value, 10);
        if(size > 0) {
            if (activeObject.isButton) {
                activeObject.getObjects()[1].set('fontSize', size);
                activeObject.addWithUpdate();
            } else if (activeObject.type === 'i-text') {
                activeObject.set('fontSize', size);
            }
            canvas.requestRenderAll();
            triggerSave();
        }
    }
});

// Alignment
if(alignLeftBtn) alignLeftBtn.addEventListener('click', () => {
    if (activeObject && (activeObject.type === 'i-text')) {
        activeObject.set('textAlign', 'left');
        updateUIForSelection(activeObject);
        canvas.requestRenderAll();
        triggerSave();
    }
});

if(alignCenterBtn) alignCenterBtn.addEventListener('click', () => {
    if (activeObject && (activeObject.type === 'i-text')) {
        activeObject.set('textAlign', 'center');
        updateUIForSelection(activeObject);
        canvas.requestRenderAll();
        triggerSave();
    }
});

if(alignRightBtn) alignRightBtn.addEventListener('click', () => {
    if (activeObject && (activeObject.type === 'i-text')) {
        activeObject.set('textAlign', 'right');
        updateUIForSelection(activeObject);
        canvas.requestRenderAll();
        triggerSave();
    }
});

// Stroke Logic
if(enableStroke) enableStroke.addEventListener('change', () => {
    if (activeObject) {
        const target = activeObject.isButton ? activeObject.getObjects()[0] : activeObject;

        if (enableStroke.checked) {
            const width = strokeWidth ? Math.max(parseFloat(strokeWidth.value) || 1, 0.1) : 1;
            const color = strokeColor ? strokeColor.value : '#000000';
            
            target.set('stroke', color);
            target.set('strokeWidth', width);
            
            // Improve stroke rendering quality
            target.set('strokeLineJoin', 'round');
            target.set('strokeLineCap', 'round');
            target.set('strokeMiterLimit', 10);
            
            // For text objects, render stroke first to prevent overlap with fill
            if (target.type === 'i-text' || target.type === 'text' || target.type === 'textbox') {
                target.set('paintFirst', 'stroke');
                target.set('objectCaching', false);
            }
            
            // Update UI to reflect actual value
            if(strokeWidth) strokeWidth.value = width;
            if(strokeColorDisplay) strokeColorDisplay.style.backgroundColor = color;
            if(strokeControls) strokeControls.classList.remove('opacity-50', 'pointer-events-none');
        } else {
            // Preserve stroke color when disabling
            const currentColor = target.stroke || (strokeColor ? strokeColor.value : '#000000');
            target.set('strokeWidth', 0);
            
            // Reset paintFirst and re-enable caching for text objects when stroke is disabled
            if (target.type === 'i-text' || target.type === 'text' || target.type === 'textbox') {
                target.set('paintFirst', 'fill');
                target.set('objectCaching', true);
            }
            
            // Keep color in UI for when re-enabling
            if(strokeColor) strokeColor.value = currentColor;
            if(strokeColorDisplay) strokeColorDisplay.style.backgroundColor = currentColor;
            if(strokeControls) strokeControls.classList.add('opacity-50', 'pointer-events-none');
        }

        if (activeObject.isButton) activeObject.addWithUpdate(); // Update group
        canvas.requestRenderAll();
        triggerSave();
    }
});

if(strokeColor) strokeColor.addEventListener('input', (e) => {
    if (activeObject) {
        const target = activeObject.isButton ? activeObject.getObjects()[0] : activeObject;
        const color = e.target.value;
        
        target.set('stroke', color);
        
        // Ensure rendering quality is maintained when changing color
        if (target.strokeWidth > 0) {
            target.set('strokeLineJoin', 'round');
            target.set('strokeLineCap', 'round');
            target.set('strokeMiterLimit', 10);
            // For text objects, render stroke first to prevent overlap with fill
            if (target.type === 'i-text' || target.type === 'text' || target.type === 'textbox') {
                target.set('paintFirst', 'stroke');
                target.set('objectCaching', false);
            }
        }
        
        if(strokeColorDisplay) strokeColorDisplay.style.backgroundColor = color;
        
        // If stroke is enabled, update immediately; if disabled, just update UI
        if(enableStroke && enableStroke.checked && target.strokeWidth > 0) {
            if (activeObject.isButton) activeObject.dirty = true;
            canvas.requestRenderAll();
            triggerSave();
        }
    }
});

if(strokeWidth) strokeWidth.addEventListener('input', (e) => {
    if (activeObject) {
        const target = activeObject.isButton ? activeObject.getObjects()[0] : activeObject;
        const width = parseFloat(e.target.value) || 0;
        
        if (width > 0) {
            // Enable stroke if width > 0
            target.set('strokeWidth', width);
            target.set('stroke', target.stroke || (strokeColor ? strokeColor.value : '#000000'));
            
            // Improve stroke rendering quality
            target.set('strokeLineJoin', 'round');
            target.set('strokeLineCap', 'round');
            target.set('strokeMiterLimit', 10);
            
            // For text objects, render stroke first to prevent overlap with fill
            if (target.type === 'i-text' || target.type === 'text' || target.type === 'textbox') {
                target.set('paintFirst', 'stroke');
                target.set('objectCaching', false);
            }
            
            if(enableStroke && !enableStroke.checked) {
                enableStroke.checked = true;
                if(strokeControls) strokeControls.classList.remove('opacity-50', 'pointer-events-none');
            }
            
            if (activeObject.isButton) activeObject.addWithUpdate();
            canvas.requestRenderAll();
            triggerSave();
        } else {
            // Disable stroke if width is 0
            target.set('strokeWidth', 0);
            
            // Reset paintFirst and re-enable caching for text objects when stroke is disabled
            if (target.type === 'i-text' || target.type === 'text' || target.type === 'textbox') {
                target.set('paintFirst', 'fill');
                target.set('objectCaching', true);
            }
            
            if(enableStroke && enableStroke.checked) {
                enableStroke.checked = false;
                if(strokeControls) strokeControls.classList.add('opacity-50', 'pointer-events-none');
            }
            
            if (activeObject.isButton) activeObject.addWithUpdate();
            canvas.requestRenderAll();
            triggerSave();
        }
    }
});

// Shadow Logic
if(enableShadow) enableShadow.addEventListener('change', applyShadow);
if(shadowColor) shadowColor.addEventListener('input', (e) => {
    if(shadowColorDisplay) shadowColorDisplay.style.backgroundColor = e.target.value;
    applyShadow();
});
if(shadowBlur) shadowBlur.addEventListener('input', applyShadow);
if(shadowOffsetX) shadowOffsetX.addEventListener('input', applyShadow);
if(shadowOffsetY) shadowOffsetY.addEventListener('input', applyShadow);

// Global Actions
if(addTextBtn) addTextBtn.addEventListener('click', addText);

// Page Strip Actions
if(addPageBtn) addPageBtn.addEventListener('click', () => createNewPage());

// Image Upload - Native picker helper
function nativeImagePicker() {
    if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.nativeImagePicker) {
        window.webkit.messageHandlers.nativeImagePicker.postMessage({});
        return true;
    }
    return false;
}

// Called from Swift with image data URL
window.handleNativeImageContent = function(dataURL) {
    addImageToCanvas(dataURL);
};

// Add image to canvas from data URL
function addImageToCanvas(dataURL) {
    fabric.Image.fromURL(dataURL, function (img) {
        // Smart Scaling: Fit image within 50% of LOGICAL canvas width/height
        const maxWidth = artboardBase.w * 0.5;
        const maxHeight = artboardBase.h * 0.5;

        let scale = 1;
        if (img.width > maxWidth || img.height > maxHeight) {
            const scaleX = maxWidth / img.width;
            const scaleY = maxHeight / img.height;
            scale = Math.min(scaleX, scaleY);
        }

        img.set({
            left: artboardBase.w / 2,
            top: artboardBase.h / 2,
            originX: 'center',
            originY: 'center',
            scaleX: scale,
            scaleY: scale,
            name: generateDefaultName('image')
        });

        canvas.add(img);
        canvas.setActiveObject(img);
        updateUIForSelection(img);
        triggerSave();
    });
}

if(addImageBtn) addImageBtn.addEventListener('click', () => {
    // Try native image picker first (for macOS/iOS app)
    if (!nativeImagePicker()) {
        if(imgLoader) imgLoader.click();
    }
});

if(imgLoader) imgLoader.addEventListener('change', (e) => {
    const file = e.target.files[0];
    if(!file) return;

    const reader = new FileReader();
    reader.onload = function (f) {
        addImageToCanvas(f.target.result);
        imgLoader.value = '';
    };
    reader.readAsDataURL(file);
});

// --- Drag & Drop Image Support ---
const canvasWrapper = getEl('canvasWrapper');

if (canvasWrapper) {
    // Prevent default drag behaviors
    ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
        canvasWrapper.addEventListener(eventName, preventDefaults, false);
    });

    function preventDefaults(e) {
        e.preventDefault();
        e.stopPropagation();
    }

    // Visual feedback when dragging over
    ['dragenter', 'dragover'].forEach(eventName => {
        canvasWrapper.addEventListener(eventName, () => {
            canvasWrapper.classList.add('ring-4', 'ring-indigo-500/20', 'bg-indigo-50/30');
        }, false);
    });

    ['dragleave', 'drop'].forEach(eventName => {
        canvasWrapper.addEventListener(eventName, () => {
            canvasWrapper.classList.remove('ring-4', 'ring-indigo-500/20', 'bg-indigo-50/30');
        }, false);
    });

    // Handle dropped files
    canvasWrapper.addEventListener('drop', (e) => {
        const dt = e.dataTransfer;
        const files = dt.files;

        ([...files]).forEach(file => {
            // Only process image files
            if (file.type.startsWith('image/')) {
                const reader = new FileReader();
                reader.onload = (f) => {
                    const data = f.target.result;
                    fabric.Image.fromURL(data, function (img) {
                        // Reuse Smart Scaling Logic
                        const maxWidth = artboardBase.w * 0.5;
                        const maxHeight = artboardBase.h * 0.5;
                        
                        let scale = 1;
                        if (img.width > maxWidth || img.height > maxHeight) {
                            const scaleX = maxWidth / img.width;
                            const scaleY = maxHeight / img.height;
                            scale = Math.min(scaleX, scaleY);
                        }

                        // Default to center of canvas
                        img.set({
                            left: artboardBase.w / 2,
                            top: artboardBase.h / 2,
                            originX: 'center',
                            originY: 'center',
                            scaleX: scale,
                            scaleY: scale,
                            name: generateDefaultName('image')
                        });
                        
                        canvas.add(img);
                        canvas.setActiveObject(img);
                        updateUIForSelection(img);
                        triggerSave();
                    });
                };
                reader.readAsDataURL(file);
            }
        });
    }, false);
}

if(deleteObjBtn) deleteObjBtn.addEventListener('click', () => {
    if (activeObject) {
        canvas.remove(activeObject);
        canvas.discardActiveObject();
        canvas.requestRenderAll();
        updateUIForSelection(null);
        triggerSave();
    }
});

// Reset Logic (Fix)
if(resetBtn) resetBtn.addEventListener('click', () => {
    // Show Modal
    if(clearModal) {
        clearModal.classList.remove('hidden');
        clearModal.classList.add('flex');
    }
});

if(cancelClearBtn) cancelClearBtn.addEventListener('click', () => {
    if(clearModal) {
        clearModal.classList.add('hidden');
        clearModal.classList.remove('flex');
    }
});

if(confirmClearBtn) confirmClearBtn.addEventListener('click', () => {
     canvas.clear();
     localStorage.removeItem('gradientEditorState'); // Clear save
     
     // Reset pages to single empty page
     pages = [];
     currentPageId = null;
     pageCounter = 0;
     
     updateBackground();
     initializePages();
     
     // Hide modal
     if(clearModal) {
        clearModal.classList.add('hidden');
        clearModal.classList.remove('flex');
    }
});

// ============================================
// EXPORT FUNCTIONS (PNG, JPG, PDF)
// ============================================

// Helper: Prepare canvas for export (hide guidelines, deselect)
function prepareCanvasForExport() {
    canvas.discardActiveObject();
    const guidelines = canvas.getObjects().filter(obj => obj.name?.startsWith('__guideline'));
    guidelines.forEach(guideline => guideline.set('visible', false));
    canvas.requestRenderAll();
    return guidelines;
}

// Helper: Restore canvas after export
function restoreCanvasAfterExport(guidelines) {
    guidelines.forEach(guideline => guideline.set('visible', true));
    canvas.requestRenderAll();
}

// Helper: Get canvas as data URL
function getCanvasDataURL(format = 'png', quality = 1) {
    const multiplier = 2 / zoomLevel;
    return canvas.toDataURL({
        format: format,
        quality: quality,
        multiplier: multiplier
    });
}

// Native app bridge helper - single file
function nativeDownload(filename, dataURL) {
    if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.nativeDownload) {
        window.webkit.messageHandlers.nativeDownload.postMessage({
            filename: filename,
            data: dataURL
        });
        return true;
    }
    return false;
}

// Native app bridge helper - batch files (folder picker)
function nativeBatchDownload(files) {
    if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.nativeBatchDownload) {
        window.webkit.messageHandlers.nativeBatchDownload.postMessage({ files: files });
        return true;
    }
    return false;
}

// Download canvas as PNG
function downloadAsPng() {
    if (downloadMenu) downloadMenu.classList.add('hidden');
    const guidelines = prepareCanvasForExport();

    const dataURL = getCanvasDataURL('png', 1);
    restoreCanvasAfterExport(guidelines);

    // Try native download first (for macOS/iOS app)
    if (nativeDownload('my-design.png', dataURL)) return;

    const link = document.createElement('a');
    link.download = 'my-design.png';
    link.href = dataURL;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

// Download canvas as JPG
function downloadAsJpg() {
    if (downloadMenu) downloadMenu.classList.add('hidden');
    const guidelines = prepareCanvasForExport();

    const dataURL = getCanvasDataURL('jpeg', 0.92);
    restoreCanvasAfterExport(guidelines);

    // Try native download first (for macOS/iOS app)
    if (nativeDownload('my-design.jpg', dataURL)) return;

    const link = document.createElement('a');
    link.download = 'my-design.jpg';
    link.href = dataURL;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

// Download canvas as PDF
function downloadAsPdf() {
    if (downloadMenu) downloadMenu.classList.add('hidden');

    if (typeof jspdf === 'undefined') {
        alert('PDF library not loaded. Please refresh the page.');
        return;
    }

    const guidelines = prepareCanvasForExport();
    const dataURL = getCanvasDataURL('jpeg', 0.95);
    restoreCanvasAfterExport(guidelines);

    const { jsPDF } = jspdf;
    const orientation = artboardBase.w > artboardBase.h ? 'landscape' : 'portrait';
    const pdf = new jsPDF({
        orientation: orientation,
        unit: 'px',
        format: [artboardBase.w * 2, artboardBase.h * 2],
        hotfixes: ['px_scaling']
    });

    pdf.addImage(dataURL, 'JPEG', 0, 0, artboardBase.w * 2, artboardBase.h * 2);

    // Try native download first (for macOS/iOS app)
    const pdfData = pdf.output('datauristring');
    if (nativeDownload('my-design.pdf', pdfData)) return;

    pdf.save('my-design.pdf');
}

// Download all pages as individual PNG files
async function downloadAllAsPng() {
    if (downloadMenu) downloadMenu.classList.add('hidden');

    if (pages.length === 0) {
        alert('No pages to download.');
        return;
    }

    saveCurrentPageToArray();
    const originalPageId = currentPageId;
    const originalArtboard = { ...artboardBase };

    // Collect all page images first
    const collectedFiles = [];

    for (let i = 0; i < pages.length; i++) {
        const page = pages[i];
        const pageArtboard = page.artboardBase || { w: 1200, h: 675 };
        artboardBase = { ...pageArtboard };
        canvas.setWidth(pageArtboard.w * zoomLevel);
        canvas.setHeight(pageArtboard.h * zoomLevel);

        await new Promise((resolve) => {
            canvas.loadFromJSON(page.fabric, () => {
                canvas.getObjects().forEach(obj => {
                    if ((obj.type === 'i-text' || obj.type === 'text' || obj.type === 'textbox') && !obj.styles) {
                        obj.styles = {};
                    }
                    if (obj.type === 'i-text' || obj.type === 'text' || obj.type === 'textbox') {
                        obj.set('objectCaching', false);
                        if (obj.fontFamily) obj.set('fontFamily', obj.fontFamily);
                    }
                });

                const guidelines = prepareCanvasForExport();

                const pageBg = page.background || {};
                const bgElement = document.getElementById('canvasBg');
                if (bgElement) {
                    bgElement.style.width = `${pageArtboard.w * zoomLevel}px`;
                    bgElement.style.height = `${pageArtboard.h * zoomLevel}px`;
                    bgElement.style.background = `linear-gradient(${pageBg.direction || 'to right'}, ${pageBg.color1 || '#4f46e5'}, ${pageBg.color2 || '#ec4899'})`;
                }

                canvas.requestRenderAll();

                setTimeout(() => {
                    const dataURL = getCanvasDataURL('png', 1);
                    restoreCanvasAfterExport(guidelines);

                    // Collect the file data
                    collectedFiles.push({
                        filename: `page-${i + 1}.png`,
                        data: dataURL
                    });

                    resolve();
                }, 200);
            });
        });

        if (i < pages.length - 1) {
            await new Promise(r => setTimeout(r, 100));
        }
    }

    // Restore original page
    artboardBase = originalArtboard;
    const originalPage = pages.find(p => p.id === originalPageId);
    if (originalPage) restorePageState(originalPage);

    // Try native batch download (folder picker) first
    if (nativeBatchDownload(collectedFiles)) return;

    // Fallback: download individually in browser
    for (const file of collectedFiles) {
        const link = document.createElement('a');
        link.download = file.filename;
        link.href = file.data;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        await new Promise(r => setTimeout(r, 300));
    }
}

// Download all pages as multi-page PDF
async function downloadAllAsPdf() {
    if (downloadMenu) downloadMenu.classList.add('hidden');
    
    if (typeof jspdf === 'undefined') {
        alert('PDF library not loaded. Please refresh the page.');
        return;
    }
    
    if (pages.length === 0) {
        alert('No pages to download.');
        return;
    }
    
    saveCurrentPageToArray();
    const originalPageId = currentPageId;
    const originalArtboard = { ...artboardBase };
    
    const { jsPDF } = jspdf;
    let pdf = null;
    
    for (let i = 0; i < pages.length; i++) {
        const page = pages[i];
        const pageArtboard = page.artboardBase || { w: 1200, h: 675 };
        artboardBase = { ...pageArtboard };
        canvas.setWidth(pageArtboard.w * zoomLevel);
        canvas.setHeight(pageArtboard.h * zoomLevel);
        
        await new Promise((resolve) => {
            canvas.loadFromJSON(page.fabric, () => {
                canvas.getObjects().forEach(obj => {
                    if ((obj.type === 'i-text' || obj.type === 'text' || obj.type === 'textbox') && !obj.styles) {
                        obj.styles = {};
                    }
                    if (obj.type === 'i-text' || obj.type === 'text' || obj.type === 'textbox') {
                        obj.set('objectCaching', false);
                        if (obj.fontFamily) obj.set('fontFamily', obj.fontFamily);
                    }
                });
                
                const guidelines = prepareCanvasForExport();
                
                const pageBg = page.background || {};
                const bgElement = document.getElementById('canvasBg');
                if (bgElement) {
                    bgElement.style.width = `${pageArtboard.w * zoomLevel}px`;
                    bgElement.style.height = `${pageArtboard.h * zoomLevel}px`;
                    bgElement.style.background = `linear-gradient(${pageBg.direction || 'to right'}, ${pageBg.color1 || '#4f46e5'}, ${pageBg.color2 || '#ec4899'})`;
                }
                
                canvas.requestRenderAll();
                
                setTimeout(() => {
                    const dataURL = getCanvasDataURL('jpeg', 0.95);
                    restoreCanvasAfterExport(guidelines);
                    
                    const pdfWidth = pageArtboard.w * 2;
                    const pdfHeight = pageArtboard.h * 2;
                    const orientation = pdfWidth > pdfHeight ? 'landscape' : 'portrait';
                    
                    if (i === 0) {
                        // Create PDF with first page dimensions
                        pdf = new jsPDF({
                            orientation: orientation,
                            unit: 'px',
                            format: [pdfWidth, pdfHeight],
                            hotfixes: ['px_scaling']
                        });
                    } else {
                        // Add new page with appropriate dimensions
                        pdf.addPage([pdfWidth, pdfHeight], orientation);
                    }
                    
                    pdf.addImage(dataURL, 'JPEG', 0, 0, pdfWidth, pdfHeight);
                    resolve();
                }, 200);
            });
        });
        
        if (i < pages.length - 1) {
            await new Promise(r => setTimeout(r, 100));
        }
    }
    
    // Save the PDF
    if (pdf) {
        // Try native download first (for macOS/iOS app)
        const pdfData = pdf.output('datauristring');
        if (!nativeDownload('my-design-multipage.pdf', pdfData)) {
            pdf.save('my-design.pdf');
        }
    }

    // Restore original page
    artboardBase = originalArtboard;
    const originalPage = pages.find(p => p.id === originalPageId);
    if (originalPage) restorePageState(originalPage);
}

// Main download button - direct PNG download
if (downloadBtn) downloadBtn.addEventListener('click', downloadAsPng);

// Format-specific download buttons
if (downloadPngBtn) downloadPngBtn.addEventListener('click', downloadAsPng);
if (downloadJpgBtn) downloadJpgBtn.addEventListener('click', downloadAsJpg);
if (downloadPdfBtn) downloadPdfBtn.addEventListener('click', downloadAsPdf);
if (downloadAllPngBtn) downloadAllPngBtn.addEventListener('click', downloadAllAsPng);
if (downloadAllPdfBtn) downloadAllPdfBtn.addEventListener('click', downloadAllAsPdf);

// Download Menu Toggle
if (downloadMenuBtn && downloadMenu) {
    downloadMenuBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        downloadMenu.classList.toggle('hidden');
    });
    
    if (downloadBtn) {
        downloadBtn.addEventListener('contextmenu', (e) => {
            e.preventDefault();
            downloadMenu.classList.toggle('hidden');
        });
    }
    
    document.addEventListener('click', (e) => {
        if (!downloadMenu.contains(e.target) && e.target !== downloadMenuBtn && e.target !== downloadBtn) {
            downloadMenu.classList.add('hidden');
        }
    });
}

// Export JSON Logic (Save Project)
if(exportJsonBtn) exportJsonBtn.addEventListener('click', () => {
    // Save current page state first
    saveCurrentPageToArray();

    // Build full multi-page state object
    const fullState = {
        pages: pages,
        currentPageId: currentPageId,
        pageCounter: pageCounter
    };

    const json = JSON.stringify(fullState, null, 2);

    // Try native download first (for macOS/iOS app)
    const dataURL = 'data:application/json;base64,' + btoa(unescape(encodeURIComponent(json)));
    if (!nativeDownload('canvas-project.json', dataURL)) {
        const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(json);
        const link = document.createElement('a');
        link.setAttribute("href", dataStr);
        link.setAttribute("download", "canvas-project.json");
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }
});

// --- Snapping System ---
const SNAP_THRESHOLD = 8; // pixels
let activeGuidelines = {
    vertical: null,
    horizontal: null
};

// Create guideline line
function createGuideline(orientation, position) {
    const color = '#4f46e5';
    const strokeWidth = 1;
    const dashArray = [4, 4];
    
    if (orientation === 'vertical') {
        return new fabric.Line([position, 0, position, artboardBase.h], {
            stroke: color,
            strokeWidth: strokeWidth,
            strokeDashArray: dashArray,
            selectable: false,
            evented: false,
            excludeFromExport: true,
            name: '__guideline_vertical__'
        });
    } else {
        return new fabric.Line([0, position, artboardBase.w, position], {
            stroke: color,
            strokeWidth: strokeWidth,
            strokeDashArray: dashArray,
            selectable: false,
            evented: false,
            excludeFromExport: true,
            name: '__guideline_horizontal__'
        });
    }
}

// Remove guidelines
function removeGuidelines() {
    // Clear tracked guidelines
    if (activeGuidelines.vertical) {
        canvas.remove(activeGuidelines.vertical);
        activeGuidelines.vertical = null;
    }
    if (activeGuidelines.horizontal) {
        canvas.remove(activeGuidelines.horizontal);
        activeGuidelines.horizontal = null;
    }

    // Safety cleanup: Find and remove any guideline objects that might have lost their reference
    const guidelines = canvas.getObjects().filter(obj => obj.name && obj.name.startsWith('__guideline'));
    guidelines.forEach(g => canvas.remove(g));
}

// Get bounding box of object (accounting for rotation)
function getObjectBounds(obj) {
    const bounds = obj.getBoundingRect();
    return {
        left: bounds.left,
        right: bounds.left + bounds.width,
        top: bounds.top,
        bottom: bounds.top + bounds.height,
        centerX: bounds.left + bounds.width / 2,
        centerY: bounds.top + bounds.height / 2,
        width: bounds.width,
        height: bounds.height
    };
}

// Calculate snap positions from canvas edges
function getCanvasSnapPositions() {
    return {
        vertical: [0, artboardBase.w / 2, artboardBase.w], // left, center, right
        horizontal: [0, artboardBase.h / 2, artboardBase.h] // top, center, bottom
    };
}

// Calculate snap positions from other objects
function getObjectSnapPositions(movingObj) {
    const snapPositions = {
        vertical: [],
        horizontal: []
    };
    
    canvas.getObjects().forEach(obj => {
        if (obj === movingObj || obj.name?.startsWith('__guideline')) return;
        
        const bounds = getObjectBounds(obj);
        
        // Vertical snap points: left edge, center, right edge
        snapPositions.vertical.push(bounds.left, bounds.centerX, bounds.right);
        
        // Horizontal snap points: top edge, center, bottom edge
        snapPositions.horizontal.push(bounds.top, bounds.centerY, bounds.bottom);
    });
    
    return snapPositions;
}

// Find closest snap position
function findClosestSnap(value, snapPositions, threshold) {
    let closest = null;
    let minDistance = threshold;
    
    snapPositions.forEach(snapPos => {
        const distance = Math.abs(value - snapPos);
        if (distance < minDistance) {
            minDistance = distance;
            closest = snapPos;
        }
    });
    
    return closest;
}

// Apply snapping during object movement
canvas.on('object:moving', (e) => {
    const obj = e.target;
    if (!obj) return;
    
    const bounds = getObjectBounds(obj);
    const canvasSnaps = getCanvasSnapPositions();
    const objectSnaps = getObjectSnapPositions(obj);
    
    // Combine all snap positions
    const allVerticalSnaps = [...canvasSnaps.vertical, ...objectSnaps.vertical];
    const allHorizontalSnaps = [...canvasSnaps.horizontal, ...objectSnaps.horizontal];
    
    let snappedX = null;
    let snappedY = null;
    let snapOffsetX = 0;
    let snapOffsetY = 0;
    
    // Check vertical snapping (left, center, right edges) - prioritize closest
    const snapCandidatesX = [
        { value: bounds.left, snap: findClosestSnap(bounds.left, allVerticalSnaps, SNAP_THRESHOLD) },
        { value: bounds.centerX, snap: findClosestSnap(bounds.centerX, allVerticalSnaps, SNAP_THRESHOLD) },
        { value: bounds.right, snap: findClosestSnap(bounds.right, allVerticalSnaps, SNAP_THRESHOLD) }
    ].filter(c => c.snap !== null);
    
    if (snapCandidatesX.length > 0) {
        // Find the closest snap among all candidates
        let bestSnapX = null;
        let minDistX = Infinity;
        snapCandidatesX.forEach(candidate => {
            const dist = Math.abs(candidate.value - candidate.snap);
            if (dist < minDistX) {
                minDistX = dist;
                bestSnapX = candidate;
            }
        });
        
        if (bestSnapX) {
            snapOffsetX = bestSnapX.snap - bestSnapX.value;
            snappedX = bestSnapX.snap;
        }
    }
    
    // Check horizontal snapping (top, center, bottom edges) - prioritize closest
    const snapCandidatesY = [
        { value: bounds.top, snap: findClosestSnap(bounds.top, allHorizontalSnaps, SNAP_THRESHOLD) },
        { value: bounds.centerY, snap: findClosestSnap(bounds.centerY, allHorizontalSnaps, SNAP_THRESHOLD) },
        { value: bounds.bottom, snap: findClosestSnap(bounds.bottom, allHorizontalSnaps, SNAP_THRESHOLD) }
    ].filter(c => c.snap !== null);
    
    if (snapCandidatesY.length > 0) {
        // Find the closest snap among all candidates
        let bestSnapY = null;
        let minDistY = Infinity;
        snapCandidatesY.forEach(candidate => {
            const dist = Math.abs(candidate.value - candidate.snap);
            if (dist < minDistY) {
                minDistY = dist;
                bestSnapY = candidate;
            }
        });
        
        if (bestSnapY) {
            snapOffsetY = bestSnapY.snap - bestSnapY.value;
            snappedY = bestSnapY.snap;
        }
    }
    
    // Apply snap offsets
    if (snapOffsetX !== 0 || snapOffsetY !== 0) {
        obj.set({
            left: obj.left + snapOffsetX,
            top: obj.top + snapOffsetY
        });
    }
    
    // Show/hide guidelines
    removeGuidelines();
    
    if (snappedX !== null) {
        activeGuidelines.vertical = createGuideline('vertical', snappedX);
        canvas.add(activeGuidelines.vertical);
        // Ensure guideline is always at the back
        const objects = canvas.getObjects();
        const guidelineIndex = objects.indexOf(activeGuidelines.vertical);
        if (guidelineIndex > 0) {
            canvas.moveTo(activeGuidelines.vertical, 0);
        }
    }
    
    if (snappedY !== null) {
        activeGuidelines.horizontal = createGuideline('horizontal', snappedY);
        canvas.add(activeGuidelines.horizontal);
        // Ensure guideline is always at the back
        const objects = canvas.getObjects();
        const guidelineIndex = objects.indexOf(activeGuidelines.horizontal);
        if (guidelineIndex > 0) {
            canvas.moveTo(activeGuidelines.horizontal, 0);
        }
    }
    
    canvas.renderAll();
});

// Remove guidelines when object stops moving or is modified
canvas.on('object:modified', () => {
    removeGuidelines();
    canvas.renderAll();
});

// Remove guidelines when object is deselected
canvas.on('selection:cleared', () => {
    removeGuidelines();
    canvas.renderAll();
});

// Remove guidelines when object is removed
canvas.on('object:removed', () => {
    removeGuidelines();
    canvas.renderAll();
});

// Remove guidelines when mouse is released (always, as movement has stopped)
canvas.on('mouse:up', () => {
    removeGuidelines();
    canvas.renderAll();
});

// --- Undo / Redo Listeners ---
if(undoBtn) undoBtn.addEventListener('click', undo);
if(redoBtn) redoBtn.addEventListener('click', redo);

// --- Keyboard Shortcuts: Delete, Undo/Redo, Copy/Cut/Paste/Duplicate ---
window.addEventListener('keydown', (e) => {
    // Check if user is typing in an input field
    const isTyping = document.activeElement.tagName === 'INPUT' || 
                     document.activeElement.tagName === 'TEXTAREA';
    
    // Undo (Cmd/Ctrl+Z)
    if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {
        e.preventDefault();
        undo();
        return;
    }
    
    // Redo (Cmd/Ctrl+Shift+Z or Cmd/Ctrl+Y)
    if ((e.ctrlKey || e.metaKey) && e.key === 'z' && e.shiftKey) {
        e.preventDefault();
        redo();
        return;
    }
    if ((e.ctrlKey || e.metaKey) && e.key === 'y') {
        e.preventDefault();
        redo();
        return;
    }
    
    // Copy (Cmd/Ctrl+C) - only when not typing
    if ((e.ctrlKey || e.metaKey) && e.key === 'c' && !isTyping) {
        e.preventDefault();
        copySelection();
        return;
    }
    
    // Cut (Cmd/Ctrl+X) - only when not typing
    if ((e.ctrlKey || e.metaKey) && e.key === 'x' && !isTyping) {
        e.preventDefault();
        cutSelection();
        return;
    }
    
    // Paste (Cmd/Ctrl+V) - only when not typing
    if ((e.ctrlKey || e.metaKey) && e.key === 'v' && !isTyping) {
        e.preventDefault();
        pasteFromClipboard();
        return;
    }
    
    // Duplicate (Cmd/Ctrl+D) - only when not typing
    if ((e.ctrlKey || e.metaKey) && e.key === 'd' && !isTyping) {
        e.preventDefault();
        copySelection();
        // Small delay to ensure copy completes
        setTimeout(() => pasteFromClipboard(), 50);
        return;
    }

    // Delete / Backspace - only when not typing
    if ((e.key === 'Delete' || e.key === 'Backspace') && !isTyping) {
        if (activeObject) {
            canvas.remove(activeObject);
            canvas.discardActiveObject();
            canvas.requestRenderAll();
            triggerSave();
        }
    }
});

// --- Setup Color Pickers for WKWebView ---
// Background gradient colors
setupColorPicker(bgColor1, bgColor1Preview);
setupColorPicker(bgColor2, bgColor2Preview);

// Background solid color
setupColorPicker(bgSolidColor, bgSolidColorBtn, (color) => {
    if (bgSolidColorHex) bgSolidColorHex.value = color.toUpperCase();
    updateBackground();
    triggerSave();
});

// Text color
setupColorPicker(textColor, textColorPreview);

// Shape color
setupColorPicker(shapeColor, shapeColorPreview);

// Stroke color
setupColorPicker(strokeColor, document.getElementById('strokeColorDisplay'));

// Shadow color
setupColorPicker(shadowColor, document.getElementById('shadowColorDisplay'));

// QR Code colors
setupColorPicker(qrColor, qrColorDisplay, (color) => {
    if (qrColorText) qrColorText.value = color.toUpperCase();
    updateQRPreview();
});
setupColorPicker(qrBgColor, qrBgColorDisplay, (color) => {
    if (qrBgColorText) qrBgColorText.value = color.toUpperCase();
    updateQRPreview();
});

// Wait for fonts to load before initializing
function initializeApp() {
    if (document.fonts && document.fonts.ready) {
        document.fonts.ready.then(() => {
            loadFromLocalStorage();
        });
    } else {
        // Fallback for browsers without Font Loading API
        window.addEventListener('load', () => {
            setTimeout(() => {
                loadFromLocalStorage();
            }, 500);
        });
    }
}

// Initial Setup: Wait for fonts, then load from storage
initializeApp();

