/**
 * Unified Layer Renderer
 * 
 * Handles rendering ALL layer kinds to the canvas with consistent behavior.
 * Works with smart guide system, drag/drop, resize, and all existing interactions.
 * 
 * COORDINATE SYSTEM (as of v5.2.1):
 * - Layers are stored with CONTAINER-RELATIVE coordinates (y=0 is top of container)
 * - When rendering, we ADD the container offset to get CANVAS-ABSOLUTE positions
 * - This enables responsive reuse of blocks across different container types
 * 
 * @module unified-layer-renderer
 * @since 5.2.1 - Unified Layer System
 */

import {
    LAYER_KIND_TOKEN_TEXT,
    LAYER_KIND_STATIC_TEXT,
    LAYER_KIND_TOKEN_IMAGE,
    LAYER_KIND_STATIC_IMAGE,
    LAYER_KIND_SLIDESHOW_IMAGE,
    LAYER_KIND_QR_IMAGE,
    LAYER_KIND_BACKGROUND_IMAGE,
    LAYER_KIND_WP_POST,
    LAYER_KIND_VIDEO,
    LAYER_KIND_FEED,
    CSS_CLASS,
    DATA_ATTR,
    isTextLayer,
    isImageLayer,
    isVideoLayer,
    isFeedLayer,
    getLayerTypeName
} from './layer-constants.js';

/**
 * Get the container offset from the editor's current config.
 * Container offset is where the container starts on the 1280x720 canvas.
 * 
 * For lower_third: { x: 0, y: 480 }
 * For upper_third: { x: 0, y: 0 }
 * For right_half:  { x: 640, y: 0 }
 * 
 * @param {Object} editor - Canvas editor instance
 * @returns {{x: number, y: number}} Container offset in canvas coordinates
 */
function getContainerOffset(editor) {
    const layout = editor?.currentConfig?.layout;
    if (!layout) return { x: 0, y: 0 };
    
    // Use layout.position first (updated by preset changes)
    // This ensures layers render correctly when Intended Container changes
    if (layout.position) {
        return {
            x: layout.position.x || 0,
            y: layout.position.y || 0
        };
    }
    
    // Fall back to _originalPosition (set during migration)
    if (layout._originalPosition) {
        return {
            x: layout._originalPosition.x || 0,
            y: layout._originalPosition.y || 0
        };
    }
    
    // Legacy fallback to x_position/y_position
    return {
        x: layout.x_position || 0,
        y: layout.y_position || 0
    };
}

/**
 * Render a layer to the canvas
 * 
 * Creates DOM element with proper structure for interactions.
 * Maintains compatibility with smart guides, drag/drop, resize.
 * 
 * @param {Object} editor - Canvas editor instance
 * @param {Object} layer - Layer object with kind, position, size, etc.
 * @param {HTMLElement} [stage] - Optional stage element to append to. If provided, appends the layer.
 * @returns {HTMLElement} Rendered layer element
 */
export function renderLayer(editor, layer, stage = null) {
    // Validate layer
    if (!layer || !layer.id || !layer.kind) {
        console.error('[UnifiedRenderer] Invalid layer:', layer);
        return null;
    }
    
    // Get container offset - layers are stored as CONTAINER-RELATIVE coordinates
    // but must be rendered at CANVAS-ABSOLUTE positions
    const containerOffset = getContainerOffset(editor);
    
    // Check if layer already exists on stage (avoid duplicates)
    if (stage) {
        const existing = stage.querySelector(`[data-layer-id="${layer.id}"]`);
        if (existing) {
            // Update existing element instead of creating duplicate
            console.debug('[UnifiedRenderer] Layer already exists, updating:', layer.kind, layer.id);
            updateLayerElement(existing, layer, containerOffset);
            return existing;
        }
    }
    
    // Create container element (required for smart guides and interactions)
    const container = document.createElement('div');
    
    // Use unified layer class naming convention
    container.className = `canvas-container ${CSS_CLASS.LAYER} ${CSS_CLASS.layerKind(layer.kind)}`;
    
    // Use data-layer-id for interaction handlers
    container.setAttribute(DATA_ATTR.LAYER_ID, layer.id);
    container.setAttribute(DATA_ATTR.LAYER_KIND, layer.kind);
    
    // Calculate canvas-absolute position from container-relative coordinates
    const canvasX = layer.x + containerOffset.x;
    const canvasY = layer.y + containerOffset.y;
    
    // Apply universal positioning and sizing
    Object.assign(container.style, {
        position: 'absolute',
        left: `${canvasX}px`,
        top: `${canvasY}px`,
        width: `${layer.width}px`,
        height: `${layer.height}px`,
        zIndex: layer.zIndex || 10,
        display: layer.visible !== false ? 'block' : 'none',
        pointerEvents: layer.lock ? 'none' : 'auto'
    });
    
    // Add locked class if applicable
    if (layer.lock) {
        container.classList.add(CSS_CLASS.LAYER_LOCKED);
    }
    
    // Render layer content based on kind
    const content = renderLayerContent(editor, layer);
    if (content) {
        container.appendChild(content);
    }
    
    // Add resize handles if not locked
    if (!layer.lock) {
        addResizeHandles(container);
    }
    
    // Append to stage if provided
    if (stage) {
        stage.appendChild(container);
        console.debug('[UnifiedRenderer] Appended layer to stage:', layer.kind, layer.id);
    }
    
    return container;
}

/**
 * Update an existing layer element with new layer data
 * 
 * @param {HTMLElement} element - Existing layer DOM element
 * @param {Object} layer - Updated layer data
 * @param {{x: number, y: number}} containerOffset - Container offset for coordinate conversion
 */
function updateLayerElement(element, layer, containerOffset = { x: 0, y: 0 }) {
    // Ensure unified layer class is present (for interaction handlers)
    if (!element.classList.contains(CSS_CLASS.LAYER)) {
        element.classList.add(CSS_CLASS.LAYER);
    }
    
    // Calculate canvas-absolute position from container-relative coordinates
    const canvasX = layer.x + containerOffset.x;
    const canvasY = layer.y + containerOffset.y;
    
    // Update positioning and sizing
    Object.assign(element.style, {
        left: `${canvasX}px`,
        top: `${canvasY}px`,
        width: `${layer.width}px`,
        height: `${layer.height}px`,
        zIndex: layer.zIndex || 10,
        display: layer.visible !== false ? 'block' : 'none',
        pointerEvents: layer.lock ? 'none' : 'auto'
    });
    
    // Update locked state
    if (layer.lock) {
        element.classList.add(CSS_CLASS.LAYER_LOCKED);
    } else {
        element.classList.remove(CSS_CLASS.LAYER_LOCKED);
    }
    
    // Update text styling for text layers
    if (layer.kind === LAYER_KIND_TOKEN_TEXT || layer.kind === LAYER_KIND_STATIC_TEXT) {
        const textEl = element.querySelector(`.${CSS_CLASS.LAYER_TEXT_CONTENT}`);
        if (textEl) {
            applyTextStyling(textEl, layer);
            
            // Update text content based on layer kind
            if (layer.kind === LAYER_KIND_STATIC_TEXT) {
                // Static text uses layer.text directly
                if (layer.text !== undefined) {
                    textEl.textContent = layer.text;
                }
            } else if (layer.kind === LAYER_KIND_TOKEN_TEXT) {
                // Token text uses renderedText (resolved template) or templateText
                if (layer.renderedText) {
                    textEl.textContent = layer.renderedText;
                } else if (layer.templateText) {
                    textEl.textContent = layer.templateText;
                }
            }
        }
    }
    
    // Update image for image layers
    if (layer.kind === LAYER_KIND_TOKEN_IMAGE) {
        const img = element.querySelector(`img[${DATA_ATTR.TOKEN_IMAGE}]`);
        if (img && layer.renderedUrl) {
            img.src = layer.renderedUrl;
        }
    }
}

/**
 * Render layer content based on layer kind
 * 
 * @param {Object} editor - Canvas editor instance
 * @param {Object} layer - Layer object
 * @returns {HTMLElement} Layer content element
 */
function renderLayerContent(editor, layer) {
    switch (layer.kind) {
        case LAYER_KIND_TOKEN_TEXT:
            return renderTokenText(editor, layer);
        
        case LAYER_KIND_STATIC_TEXT:
            return renderStaticText(editor, layer);
        
        case LAYER_KIND_TOKEN_IMAGE:
            return renderTokenImage(editor, layer);
        
        case LAYER_KIND_STATIC_IMAGE:
            return renderStaticImage(editor, layer);
        
        case LAYER_KIND_SLIDESHOW_IMAGE:
            return renderSlideshowImage(editor, layer);
        
        case LAYER_KIND_QR_IMAGE:
            return renderQrImage(editor, layer);
        
        case LAYER_KIND_BACKGROUND_IMAGE:
            return renderBackgroundImage(editor, layer);
        
        case LAYER_KIND_WP_POST:
            return renderWordPressPost(editor, layer);
        
        case LAYER_KIND_VIDEO:
            return renderVideoLayer(editor, layer);
        
        case LAYER_KIND_FEED:
            return renderFeedLayer(editor, layer);
        
        default:
            console.warn('[UnifiedRenderer] Unknown layer kind:', layer.kind);
            return renderFallback(layer);
    }
}

/**
 * Render token text layer
 */
function renderTokenText(editor, layer) {
    const wrapper = document.createElement('div');
    wrapper.className = `${CSS_CLASS.TEXT_LAYER} token-text-layer`;
    wrapper.style.cssText = 'width: 100%; height: 100%; display: flex; align-items: center; overflow: hidden;';
    
    const textEl = document.createElement('div');
    textEl.className = CSS_CLASS.LAYER_TEXT_CONTENT;
    textEl.setAttribute(DATA_ATTR.TOKEN_TEXT, '1');
    textEl.contentEditable = false; // Tokens are not directly editable
    
    // Use templateText (like {{track.title}}) or token field
    const templateText = layer.templateText || layer.token || '';
    
    // Try to resolve and render the template
    let displayText = templateText;
    if (editor._liveTokenData && templateText) {
        // Use existing token render if available
        try {
            // Simple token replacement for common patterns
            displayText = templateText.replace(/\{\{([^}]+)\}\}/g, (match, tokenPath) => {
                const resolved = editor.resolveToken(tokenPath);
                // Hardcoded fallbacks for critical tokens if not resolved
                if (resolved == null) {
                    const fallbacks = {
                        'weather.unit': '°F',
                        'weather.temperature': '72',
                        'weather.condition': 'Sunny',
                        'location.time': '3:14 PM',
                        'location.city': 'Los Angeles'
                    };
                    return fallbacks[tokenPath] ?? '';
                }
                return resolved;
            });
        } catch(_) {}
    }
    
    // Use renderedText if already resolved by token system
    if (layer.renderedText) {
        displayText = layer.renderedText;
    }
    
    textEl.textContent = displayText || templateText || '{{token}}';
    
    // Apply text styling AFTER setting content
    // This ensures style.color is not overridden
    applyTextStyling(textEl, layer);
    
    // Only show placeholder styling if token is completely unresolved
    // (no renderedText and still contains {{ markers)
    const isUnresolved = !layer.renderedText && displayText && displayText.includes('{{');
    if (isUnresolved) {
        textEl.style.color = '#999';
        textEl.style.fontStyle = 'italic';
    }
    
    wrapper.appendChild(textEl);
    return wrapper;
}

/**
 * Render static text layer
 */
function renderStaticText(editor, layer) {
    const wrapper = document.createElement('div');
    wrapper.className = `${CSS_CLASS.TEXT_LAYER} static-text-layer`;
    wrapper.style.cssText = 'width: 100%; height: 100%; display: flex; align-items: center; justify-content: flex-start; overflow: hidden;';
    
    const textEl = document.createElement('div');
    textEl.className = CSS_CLASS.LAYER_TEXT_CONTENT;
    textEl.contentEditable = true; // Static text is editable
    textEl.style.cssText = 'cursor: text; min-width: 10px; outline: none; padding: 4px;';
    
    // Apply text styling
    applyTextStyling(textEl, layer);
    
    textEl.textContent = layer.text || 'Edit text...';
    
    // Handle text editing
    textEl.addEventListener('blur', () => {
        layer.text = textEl.textContent;
        editor.markUnsavedChanges();
    });
    
    // Prevent drag when clicking to edit text
    textEl.addEventListener('mousedown', (e) => {
        e.stopPropagation();
    });
    
    // Select all on first focus for easier editing
    textEl.addEventListener('focus', () => {
        if (textEl.textContent === 'Edit text...') {
            const range = document.createRange();
            range.selectNodeContents(textEl);
            const sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        }
    });
    
    wrapper.appendChild(textEl);
    return wrapper;
}

/**
 * Render token image layer
 */
function renderTokenImage(editor, layer) {
    const wrapper = document.createElement('div');
    wrapper.className = `${CSS_CLASS.IMAGE_LAYER} token-image-layer`;
    wrapper.style.cssText = 'width: 100%; height: 100%; position: relative;';
    
    const img = document.createElement('img');
    img.className = CSS_CLASS.LAYER_IMAGE_CONTENT;
    img.setAttribute(DATA_ATTR.TOKEN_IMAGE, '1'); // For token refresh system
    
    // Check for already-resolved URL first (from token refresh system)
    // Then try to resolve token, then fallback
    let imageUrl = layer.renderedUrl || resolveToken(editor, layer.token) || layer.fallback_url;
    
    if (imageUrl) {
        img.src = imageUrl;
    } else {
        // Show placeholder for unresolved token
        img.src = 'data:image/svg+xml,' + encodeURIComponent(`
            <svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
                <rect width="200" height="200" fill="#e5e7eb"/>
                <text x="50%" y="50%" text-anchor="middle" dy=".3em" fill="#6b7280" font-size="14">
                    ${layer.token || 'Image Token'}
                </text>
            </svg>
        `);
    }
    
    // Apply image styling
    applyImageStyling(img, layer);
    
    wrapper.appendChild(img);
    return wrapper;
}

/**
 * Render static image layer
 */
function renderStaticImage(editor, layer) {
    // DEBUG: Log static-image layer data
    console.log('[CC][RENDER DEBUG] renderStaticImage:', layer.id, 'url:', layer.url);
    
    const wrapper = document.createElement('div');
    wrapper.className = 'layer-content image-layer static-image-layer';
    wrapper.style.cssText = 'width: 100%; height: 100%; position: relative;';
    
    const img = document.createElement('img');
    img.className = 'layer-image';
    img.src = layer.url || '';
    
    // Apply image styling
    applyImageStyling(img, layer);
    
    // Handle image URL change (double-click to open media library)
    img.addEventListener('dblclick', (e) => {
        e.stopPropagation();
        openMediaLibrary(editor, (newUrl) => {
            layer.url = newUrl;
            img.src = newUrl;
            editor.markUnsavedChanges();
        });
    });
    
    wrapper.appendChild(img);
    return wrapper;
}

/**
 * Render slideshow image layer
 */
function renderSlideshowImage(editor, layer) {
    const wrapper = document.createElement('div');
    wrapper.className = 'layer-content image-layer slideshow-image-layer';
    wrapper.style.cssText = 'width: 100%; height: 100%; position: relative; overflow: hidden;';
    
    // Slideshow container
    const slideshowContainer = document.createElement('div');
    slideshowContainer.className = 'slideshow-container';
    slideshowContainer.style.cssText = 'width: 100%; height: 100%; position: relative;';
    
    // Render current image
    if (layer.images && layer.images.length > 0) {
        const currentIndex = layer.current_index || 0;
        const currentImage = layer.images[currentIndex];
        
        const img = document.createElement('img');
        img.className = 'layer-image slideshow-image';
        img.src = currentImage.url || currentImage;
        applyImageStyling(img, layer);
        
        slideshowContainer.appendChild(img);
        
        // Add slideshow indicator
        const indicator = document.createElement('div');
        indicator.className = 'slideshow-indicator';
        indicator.style.cssText = 'position: absolute; bottom: 5px; right: 5px; background: rgba(0,0,0,0.6); color: white; padding: 2px 6px; border-radius: 3px; font-size: 10px;';
        indicator.textContent = `${currentIndex + 1}/${layer.images.length}`;
        slideshowContainer.appendChild(indicator);
        
        // Initialize slideshow if autoplay enabled
        if (layer.autoplay && editor._activeSlideshows) {
            initializeSlideshow(editor, layer, slideshowContainer);
        }
    } else {
        // Placeholder for empty slideshow
        const placeholder = document.createElement('div');
        placeholder.className = 'slideshow-placeholder';
        placeholder.style.cssText = 'width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: #e5e7eb; color: #6b7280;';
        placeholder.innerHTML = '<div>Click to add images</div>';
        
        placeholder.addEventListener('click', (e) => {
            e.stopPropagation();
            openMediaLibrary(editor, (urls) => {
                layer.images = Array.isArray(urls) ? urls.map(url => ({ url, duration: 5000 })) : [{ url: urls, duration: 5000 }];
                editor.refreshLayer(layer.id);
                editor.markUnsavedChanges();
            }, true); // Allow multiple selection
        });
        
        slideshowContainer.appendChild(placeholder);
    }
    
    wrapper.appendChild(slideshowContainer);
    return wrapper;
}

/**
 * Render QR code layer
 */
function renderQrImage(editor, layer) {
    const wrapper = document.createElement('div');
    wrapper.className = 'layer-content image-layer qr-image-layer';
    wrapper.style.cssText = 'width: 100%; height: 100%; position: relative;';
    
    const qrContainer = document.createElement('div');
    qrContainer.className = 'qr-container';
    qrContainer.style.cssText = 'width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: #fff; border-radius: 8px;';
    
    // Check for pre-rendered QR data URL (from qr-code-generator.js)
    // Generator saves: url (data URL), sourceUrl (original URL to encode)
    if (layer.url && layer.url.startsWith('data:image/')) {
        // Use pre-rendered QR image directly
        const img = document.createElement('img');
        img.src = layer.url;
        img.alt = `QR Code: ${layer.sourceUrl || ''}`;
        img.style.cssText = 'width: 100%; height: 100%; object-fit: contain; display: block;';
        qrContainer.appendChild(img);
    }
    // Fallback: Generate QR code using QRCode library (legacy qr_data field)
    else if (window.QRCode && (layer.qr_data || layer.sourceUrl)) {
        const qrEl = document.createElement('div');
        qrEl.style.cssText = 'display: inline-block;';
        
        try {
            new window.QRCode(qrEl, {
                text: layer.qr_data || layer.sourceUrl,
                width: layer.qr_size || layer.width || 256,
                height: layer.qr_size || layer.height || 256,
                colorDark: layer.qr_color || '#000000',
                colorLight: layer.qr_background || '#ffffff',
                correctLevel: window.QRCode.CorrectLevel[layer.error_correction || 'M']
            });
            qrContainer.appendChild(qrEl);
        } catch (error) {
            console.error('[UnifiedRenderer] QR generation failed:', error);
            qrContainer.innerHTML = '<div style="color: red;">QR Error</div>';
        }
    } else {
        qrContainer.innerHTML = '<div style="color: #999;">QR: ' + (layer.qr_data || layer.sourceUrl || 'No data') + '</div>';
    }
    
    wrapper.appendChild(qrContainer);
    return wrapper;
}

/**
 * Render background image layer
 */
function renderBackgroundImage(editor, layer) {
    const wrapper = document.createElement('div');
    wrapper.className = 'layer-content image-layer background-image-layer';
    wrapper.style.cssText = 'width: 100%; height: 100%; position: relative;';
    
    // Background images typically fill the entire canvas
    const img = document.createElement('img');
    img.className = 'layer-image background-image';
    img.src = layer.url || '';
    
    Object.assign(img.style, {
        width: '100%',
        height: '100%',
        objectFit: layer.object_fit || 'cover',
        opacity: layer.opacity || 1,
        filter: layer.filter || 'none'
    });
    
    wrapper.appendChild(img);
    return wrapper;
}

/**
 * Render WordPress post layer (composite)
 */
/**
 * Render WordPress Post layer
 * 
 * Composite layer that renders multiple fields from a WordPress post:
 * - Title (text)
 * - Content/Excerpt (text)  
 * - Featured Image (image)
 * 
 * Each field can be positioned independently on the canvas.
 */
function renderWordPressPost(editor, layer) {
    const wrapper = document.createElement('div');
    wrapper.className = 'layer-content wordpress-post-layer';
    wrapper.style.cssText = 'width: 100%; height: 100%; position: relative; pointer-events: none;';
    
    // If no post_id set, show configuration prompt
    if (!layer.post_id) {
        const placeholder = document.createElement('div');
        placeholder.style.cssText = 'width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: rgba(99, 102, 241, 0.1); border: 2px dashed #6366f1; color: #6366f1; flex-direction: column; border-radius: 8px; pointer-events: auto; cursor: pointer;';
        placeholder.innerHTML = `
            <div style="font-size: 18px; font-weight: 600; margin-bottom: 8px;">📰 WordPress Post</div>
            <div style="font-size: 14px; opacity: 0.8;">Click to select a post</div>
        `;
        placeholder.addEventListener('click', () => {
            // Trigger post selector modal
            if (editor.openPostSelector) {
                editor.openPostSelector(layer);
            }
        });
        wrapper.appendChild(placeholder);
        return wrapper;
    }
    
    // Load post data (use cache if available and fresh)
    const post = layer._cached_post;
    const cacheAge = layer._cache_timestamp ? Date.now() - layer._cache_timestamp : Infinity;
    const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
    
    // If no cache or stale, fetch post data
    if (!post || cacheAge > CACHE_TTL) {
        // Show loading state
        const loading = document.createElement('div');
        loading.style.cssText = 'width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: rgba(99, 102, 241, 0.05); color: #6366f1; flex-direction: column;';
        loading.innerHTML = `
            <div style="font-size: 14px; font-weight: 600;">Loading post...</div>
            <div style="font-size: 12px; margin-top: 5px; opacity: 0.7;">Post ID: ${layer.post_id}</div>
        `;
        wrapper.appendChild(loading);
        
        // Fetch post data asynchronously
        fetchWordPressPost(editor, layer).then(postData => {
            if (postData) {
                // Update cache
                layer._cached_post = postData;
                layer._cache_timestamp = Date.now();
                // Re-render with cached data - update the loading content in place
                const updated = renderWordPressPost(editor, layer);
                // Replace the loading div with the rendered post content
                if (wrapper.parentNode && updated) {
                    // Clear the loading content and append the new content
                    wrapper.innerHTML = '';
                    while (updated.firstChild) {
                        wrapper.appendChild(updated.firstChild);
                    }
                }
            }
        }).catch(err => {
            console.error('[UnifiedRenderer] Failed to fetch WordPress post:', err);
            loading.innerHTML = `
                <div style="font-size: 14px; font-weight: 600; color: #ef4444;">Failed to load post</div>
                <div style="font-size: 12px; margin-top: 5px; opacity: 0.7;">Post ID: ${layer.post_id}</div>
            `;
        });
        
        return wrapper;
    }
    
    // Render post fields based on configuration
    const fields = layer.fields || {};
    
    // Render title field
    if (fields.title?.enabled && post.title) {
        const titleEl = document.createElement('div');
        titleEl.className = 'wp-post-field wp-post-title';
        titleEl.style.cssText = `
            position: absolute;
            left: ${fields.title.x}px;
            top: ${fields.title.y}px;
            width: ${fields.title.width}px;
            height: ${fields.title.height}px;
            font-family: ${fields.title.font_family || 'system-ui'};
            font-size: ${fields.title.font_size || 48}px;
            font-weight: ${fields.title.font_weight || '700'};
            color: ${fields.title.color || '#ffffff'};
            text-align: ${fields.title.text_align || 'left'};
            line-height: ${fields.title.line_height || 1.2};
            overflow: hidden;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            pointer-events: auto;
        `;
        
        // Apply text shadow if configured
        if (fields.title.text_shadow) {
            const ts = fields.title.text_shadow;
            titleEl.style.textShadow = `${ts.x||0}px ${ts.y||0}px ${ts.blur||0}px ${ts.color||'rgba(0,0,0,0.5)'}`;
        }
        
        titleEl.textContent = post.title.rendered || post.title;
        wrapper.appendChild(titleEl);
    }
    
    // Render excerpt field
    if (fields.excerpt?.enabled && post.excerpt) {
        const excerptEl = document.createElement('div');
        excerptEl.className = 'wp-post-field wp-post-excerpt';
        excerptEl.style.cssText = `
            position: absolute;
            left: ${fields.excerpt.x}px;
            top: ${fields.excerpt.y}px;
            width: ${fields.excerpt.width}px;
            height: ${fields.excerpt.height}px;
            font-family: ${fields.excerpt.font_family || 'system-ui'};
            font-size: ${fields.excerpt.font_size || 28}px;
            font-weight: ${fields.excerpt.font_weight || '400'};
            color: ${fields.excerpt.color || '#e0e0e0'};
            text-align: ${fields.excerpt.text_align || 'left'};
            line-height: ${fields.excerpt.line_height || 1.4};
            overflow: hidden;
            display: -webkit-box;
            -webkit-line-clamp: 3;
            -webkit-box-orient: vertical;
            pointer-events: auto;
        `;
        
        // Apply text shadow if configured
        if (fields.excerpt.text_shadow) {
            const ts = fields.excerpt.text_shadow;
            excerptEl.style.textShadow = `${ts.x||0}px ${ts.y||0}px ${ts.blur||0}px ${ts.color||'rgba(0,0,0,0.5)'}`;
        }
        
        // Strip HTML tags from excerpt
        const excerptText = (post.excerpt.rendered || post.excerpt).replace(/<[^>]*>/g, '').trim();
        const maxLength = fields.excerpt.max_length || 200;
        excerptEl.textContent = excerptText.length > maxLength ? excerptText.substring(0, maxLength) + '...' : excerptText;
        wrapper.appendChild(excerptEl);
    }
    
    // Render content field (usually disabled by default)
    if (fields.content?.enabled && post.content) {
        const contentEl = document.createElement('div');
        contentEl.className = 'wp-post-field wp-post-content';
        contentEl.style.cssText = `
            position: absolute;
            left: ${fields.content.x}px;
            top: ${fields.content.y}px;
            width: ${fields.content.width}px;
            height: ${fields.content.height}px;
            font-family: ${fields.content.font_family || 'system-ui'};
            font-size: ${fields.content.font_size || 24}px;
            font-weight: ${fields.content.font_weight || '400'};
            color: ${fields.content.color || '#ffffff'};
            text-align: ${fields.content.text_align || 'left'};
            line-height: ${fields.content.line_height || 1.5};
            overflow: hidden;
            display: -webkit-box;
            -webkit-line-clamp: 5;
            -webkit-box-orient: vertical;
            pointer-events: auto;
        `;
        
        // Apply text shadow if configured
        if (fields.content.text_shadow) {
            const ts = fields.content.text_shadow;
            contentEl.style.textShadow = `${ts.x||0}px ${ts.y||0}px ${ts.blur||0}px ${ts.color||'rgba(0,0,0,0.5)'}`;
        }
        
        // Strip HTML tags from content
        const contentText = (post.content.rendered || post.content).replace(/<[^>]*>/g, '').trim();
        const maxLength = fields.content.max_length || 500;
        contentEl.textContent = contentText.length > maxLength ? contentText.substring(0, maxLength) + '...' : contentText;
        wrapper.appendChild(contentEl);
    }
    
    // Render featured image field
    if (fields.featured_image?.enabled && post.featured_image_url) {
        const imageEl = document.createElement('div');
        imageEl.className = 'wp-post-field wp-post-featured-image';
        imageEl.style.cssText = `
            position: absolute;
            left: ${fields.featured_image.x}px;
            top: ${fields.featured_image.y}px;
            width: ${fields.featured_image.width}px;
            height: ${fields.featured_image.height}px;
            overflow: hidden;
            border-radius: ${fields.featured_image.border_radius || 0}px;
            pointer-events: auto;
        `;
        
        const img = document.createElement('img');
        img.src = post.featured_image_url;
        img.alt = post.title?.rendered || 'Featured image';
        img.style.cssText = `
            width: 100%;
            height: 100%;
            object-fit: ${fields.featured_image.fit || 'cover'};
            display: block;
        `;
        
        imageEl.appendChild(img);
        wrapper.appendChild(imageEl);
    }
    
    return wrapper;
}

/**
 * Fetch WordPress post data via REST API
 * 
 * @param {Object} editor - Canvas editor instance
 * @param {Object} layer - WordPress post layer
 * @returns {Promise<Object>} Post data
 */
async function fetchWordPressPost(editor, layer) {
    if (!layer.post_id) {
        throw new Error('No post_id specified');
    }
    
    try {
        // Use WordPress REST API to fetch post
        const response = await fetch(`/wp-json/wp/v2/posts/${layer.post_id}?_embed=true`, {
            headers: {
                'X-WP-Nonce': window.castconductorCanvasAjax?.nonce || ''
            }
        });
        
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
        
        const post = await response.json();
        
        // Extract featured image URL if available
        let featured_image_url = null;
        if (post._embedded && post._embedded['wp:featuredmedia']) {
            const media = post._embedded['wp:featuredmedia'][0];
            featured_image_url = media?.source_url || media?.media_details?.sizes?.full?.source_url || null;
        }
        
        return {
            id: post.id,
            title: post.title,
            content: post.content,
            excerpt: post.excerpt,
            featured_image_url,
            date: post.date,
            modified: post.modified,
            link: post.link
        };
    } catch (error) {
        console.error('[UnifiedRenderer] fetchWordPressPost failed:', error);
        throw error;
    }
}

/**
 * Render video layer
 * 
 * Video layers show a video element with poster image support.
 * In the editor, we show a poster/thumbnail with play button overlay.
 * On Roku, actual video playback happens.
 */
function renderVideoLayer(editor, layer) {
    const wrapper = document.createElement('div');
    wrapper.className = 'layer-content video-layer';
    wrapper.style.cssText = `
        width: 100%;
        height: 100%;
        position: relative;
        background: #1a1a1a;
        overflow: hidden;
        border-radius: 4px;
    `;
    
    // If no URL set, show configuration prompt
    if (!layer.url) {
        const placeholder = document.createElement('div');
        placeholder.style.cssText = `
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            background: rgba(59, 130, 246, 0.1);
            border: 2px dashed #3b82f6;
            color: #3b82f6;
            flex-direction: column;
            border-radius: 4px;
            cursor: pointer;
        `;
        placeholder.innerHTML = `
            <div style="font-size: 32px; margin-bottom: 8px;">🎬</div>
            <div style="font-size: 14px; font-weight: 600;">Video Layer</div>
            <div style="font-size: 12px; opacity: 0.8; margin-top: 4px;">Click to configure</div>
        `;
        wrapper.appendChild(placeholder);
        return wrapper;
    }
    
    // Show poster image if available, otherwise show video preview
    if (layer.poster) {
        const posterImg = document.createElement('img');
        posterImg.src = layer.poster;
        posterImg.alt = 'Video thumbnail';
        posterImg.style.cssText = `
            width: 100%;
            height: 100%;
            object-fit: ${layer.object_fit || 'contain'};
            display: block;
        `;
        wrapper.appendChild(posterImg);
    } else {
        // Show video element with poster from first frame
        // Note: Browser autoplay policies may prevent preview
        const videoEl = document.createElement('video');
        videoEl.src = layer.url;
        videoEl.muted = true;
        videoEl.preload = 'metadata';
        videoEl.style.cssText = `
            width: 100%;
            height: 100%;
            object-fit: ${layer.object_fit || 'contain'};
            display: block;
            background: #000;
        `;
        // Don't autoplay in editor - just load metadata for thumbnail
        videoEl.addEventListener('loadedmetadata', () => {
            // Seek to 1 second or 10% into the video for thumbnail
            videoEl.currentTime = Math.min(1, videoEl.duration * 0.1);
        });
        wrapper.appendChild(videoEl);
    }
    
    // Add play button overlay
    const playOverlay = document.createElement('div');
    playOverlay.style.cssText = `
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        display: flex;
        align-items: center;
        justify-content: center;
        background: rgba(0, 0, 0, 0.3);
        pointer-events: none;
    `;
    playOverlay.innerHTML = `
        <div style="
            width: 60px;
            height: 60px;
            background: rgba(255, 255, 255, 0.9);
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
        ">
            <svg width="24" height="24" viewBox="0 0 24 24" fill="#1a1a1a">
                <path d="M8 5v14l11-7z"/>
            </svg>
        </div>
    `;
    wrapper.appendChild(playOverlay);
    
    // Add video info badge
    const infoBadge = document.createElement('div');
    infoBadge.style.cssText = `
        position: absolute;
        bottom: 8px;
        left: 8px;
        background: rgba(0, 0, 0, 0.7);
        color: white;
        padding: 4px 8px;
        border-radius: 4px;
        font-size: 11px;
        font-family: system-ui, sans-serif;
    `;
    
    // Detect format from URL
    let formatLabel = 'VIDEO';
    if (layer.format && layer.format !== 'auto') {
        formatLabel = layer.format.toUpperCase();
    } else if (layer.url) {
        if (layer.url.includes('.m3u8')) formatLabel = 'HLS';
        else if (layer.url.includes('.mp4')) formatLabel = 'MP4';
        else if (layer.url.includes('.mpd')) formatLabel = 'DASH';
        else if (layer.url.startsWith('rtmp://')) formatLabel = 'RTMP';
    }
    
    const options = [];
    if (layer.autoplay) options.push('autoplay');
    if (layer.loop) options.push('loop');
    if (layer.muted) options.push('muted');
    
    infoBadge.textContent = formatLabel + (options.length ? ' • ' + options.join(', ') : '');
    wrapper.appendChild(infoBadge);
    
    return wrapper;
}

/**
 * Render feed layer
 * 
 * Feed layers display content from external feeds (RSS, MRSS, YouTube, etc.)
 * In the editor, we show a preview of the feed with sample items.
 * On Roku, the full feed browser is rendered with navigation support.
 */
function renderFeedLayer(editor, layer) {
    const wrapper = document.createElement('div');
    wrapper.className = 'layer-content feed-layer';
    wrapper.style.cssText = `
        width: 100%;
        height: 100%;
        position: relative;
        background: #1a1a1a;
        overflow: hidden;
        border-radius: 4px;
        font-family: system-ui, sans-serif;
    `;
    
    // If no URL set, show configuration prompt
    if (!layer.feed_url) {
        const placeholder = document.createElement('div');
        placeholder.style.cssText = `
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            background: rgba(16, 185, 129, 0.1);
            border: 2px dashed #10b981;
            color: #10b981;
            flex-direction: column;
            border-radius: 4px;
            cursor: pointer;
        `;
        placeholder.innerHTML = `
            <div style="font-size: 32px; margin-bottom: 8px;">📡</div>
            <div style="font-size: 14px; font-weight: 600;">Feed Layer</div>
            <div style="font-size: 12px; opacity: 0.8; margin-top: 4px;">Click to configure</div>
        `;
        wrapper.appendChild(placeholder);
        return wrapper;
    }
    
    // Header with feed info
    const header = document.createElement('div');
    header.style.cssText = `
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        padding: 8px 12px;
        background: rgba(0, 0, 0, 0.7);
        color: white;
        font-size: 12px;
        display: flex;
        justify-content: space-between;
        align-items: center;
        z-index: 1;
    `;
    
    // Format type badge
    let typeLabel = 'FEED';
    const feedType = layer.feed_type || 'auto';
    if (feedType !== 'auto') {
        typeLabel = feedType.toUpperCase();
    } else if (layer.feed_url) {
        if (layer.feed_url.includes('youtube.com') || layer.feed_url.includes('youtu.be')) {
            typeLabel = 'YOUTUBE';
        } else if (layer.feed_url.includes('soundcloud.com')) {
            typeLabel = 'SOUNDCLOUD';
        } else if (layer.feed_url.endsWith('.json')) {
            typeLabel = 'JSON';
        }
    }
    
    header.innerHTML = `
        <span style="font-weight: 600;">📡 ${typeLabel}</span>
        <span style="opacity: 0.7;">${layer.layout || 'grid'} • ${layer.max_items || 10} items</span>
    `;
    wrapper.appendChild(header);
    
    // Create preview grid/list of sample items
    const content = document.createElement('div');
    content.style.cssText = `
        position: absolute;
        top: 36px;
        left: 0;
        right: 0;
        bottom: 0;
        padding: 8px;
        overflow: hidden;
    `;
    
    // Render based on layout type
    const layout = layer.layout || 'grid';
    const columns = layer.columns || 3;
    const showThumbnail = layer.show_thumbnail !== false;
    const showTitle = layer.show_title !== false;
    
    if (layout === 'grid') {
        content.style.display = 'grid';
        content.style.gridTemplateColumns = `repeat(${columns}, 1fr)`;
        content.style.gap = `${layer.item_spacing || 8}px`;
    } else if (layout === 'list') {
        content.style.display = 'flex';
        content.style.flexDirection = 'column';
        content.style.gap = `${layer.item_spacing || 6}px`;
    } else if (layout === 'carousel') {
        content.style.display = 'flex';
        content.style.gap = `${layer.item_spacing || 8}px`;
        content.style.overflowX = 'auto';
    }
    
    // Create sample placeholder items
    const itemCount = Math.min(layout === 'list' ? 4 : 6, layer.max_items || 10);
    for (let i = 0; i < itemCount; i++) {
        const item = document.createElement('div');
        item.style.cssText = `
            background: rgba(255, 255, 255, 0.1);
            border-radius: 4px;
            overflow: hidden;
            ${layout === 'list' ? 'display: flex; gap: 8px;' : ''}
        `;
        
        // Thumbnail placeholder
        if (showThumbnail) {
            const thumb = document.createElement('div');
            thumb.style.cssText = `
                background: linear-gradient(135deg, #374151 0%, #1f2937 100%);
                ${layout === 'list' ? `width: ${layer.thumbnail_width || 80}px; height: ${layer.thumbnail_height || 45}px; flex-shrink: 0;` : 'aspect-ratio: 16/9;'}
                display: flex;
                align-items: center;
                justify-content: center;
                color: #6b7280;
                font-size: 16px;
            `;
            thumb.textContent = '📺';
            item.appendChild(thumb);
        }
        
        // Text content
        if (showTitle) {
            const textContent = document.createElement('div');
            textContent.style.cssText = `
                padding: 6px;
                ${layout === 'list' ? 'flex: 1; display: flex; flex-direction: column; justify-content: center;' : ''}
            `;
            
            // Title placeholder
            const title = document.createElement('div');
            title.style.cssText = `
                font-size: ${layer.title_font_size || 11}px;
                color: ${layer.title_font_color || '#ffffff'};
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            `;
            title.textContent = `Feed Item ${i + 1}`;
            textContent.appendChild(title);
            
            // Duration placeholder
            if (layer.show_duration) {
                const duration = document.createElement('div');
                duration.style.cssText = 'font-size: 10px; color: #9ca3af; margin-top: 2px;';
                duration.textContent = '3:45';
                textContent.appendChild(duration);
            }
            
            item.appendChild(textContent);
        }
        
        content.appendChild(item);
    }
    
    wrapper.appendChild(content);
    
    // Add hover info tooltip
    const infoTooltip = document.createElement('div');
    infoTooltip.style.cssText = `
        position: absolute;
        bottom: 8px;
        left: 8px;
        right: 8px;
        background: rgba(0, 0, 0, 0.8);
        color: #9ca3af;
        padding: 6px 10px;
        border-radius: 4px;
        font-size: 10px;
        text-overflow: ellipsis;
        white-space: nowrap;
        overflow: hidden;
    `;
    infoTooltip.textContent = layer.feed_url;
    wrapper.appendChild(infoTooltip);
    
    return wrapper;
}

/**
 * Render fallback for unknown layer types
 */
function renderFallback(layer) {
    const wrapper = document.createElement('div');
    wrapper.className = 'layer-content fallback-layer';
    wrapper.style.cssText = 'width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: #fee; color: #c00; border: 2px dashed #c00;';
    wrapper.innerHTML = `<div>Unknown Layer: ${layer.kind}</div>`;
    return wrapper;
}

/**
 * Apply text styling to element
 * Style properties are stored in layer.style object (e.g., layer.style.font_size)
 * Also supports direct layer properties for WordPress post exploded layers
 */
function applyTextStyling(element, layer) {
    // Get style from layer.style object (where Typography panel stores it)
    const style = layer.style || {};
    
    // Build text shadow CSS from object or use string directly
    // Check both style.text_shadow and layer.text_shadow (for exploded WP layers)
    let textShadowCss = 'none';
    const textShadowSource = style.text_shadow || layer.text_shadow;
    if (textShadowSource) {
        if (typeof textShadowSource === 'object') {
            const { x = 0, y = 0, blur = 0, color = 'rgba(0,0,0,0.5)' } = textShadowSource;
            textShadowCss = `${x}px ${y}px ${blur}px ${color}`;
        } else if (typeof textShadowSource === 'string') {
            textShadowCss = textShadowSource;
        }
    }
    
    Object.assign(element.style, {
        fontFamily: style.font_family || layer.font_family || 'system-ui, Arial, sans-serif',
        fontSize: `${style.font_size || layer.font_size || 24}px`,
        color: style.color || layer.font_color || layer.color || '#ffffff',
        fontWeight: style.font_weight || layer.font_weight || '600',
        fontStyle: style.font_style || layer.font_style || 'normal',
        textAlign: style.text_align || layer.text_align || 'left',
        textDecoration: style.text_decoration || layer.text_decoration || 'none',
        lineHeight: style.line_height || layer.line_height || 1.2,
        letterSpacing: `${style.letter_spacing || layer.letter_spacing || 0}px`,
        textShadow: textShadowCss,
        wordWrap: 'break-word',
        whiteSpace: 'nowrap',
        overflow: 'hidden',
        textOverflow: 'ellipsis'
    });
}

/**
 * Apply image styling to element
 */
function applyImageStyling(element, layer) {
    Object.assign(element.style, {
        width: '100%',
        height: '100%',
        objectFit: layer.object_fit || layer.fit || layer.objectFit || 'cover',
        opacity: layer.opacity !== undefined ? layer.opacity : 1,
        borderRadius: `${layer.border_radius || 0}px`,
        filter: layer.filter || 'none'
    });
}

/**
 * Add resize handles to container
 */
function addResizeHandles(container) {
    const handles = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];
    handles.forEach(dir => {
        const handle = document.createElement('div');
        handle.className = `resize-handle resize-${dir}`;
        handle.setAttribute('data-direction', dir);
        container.appendChild(handle);
    });
}

/**
 * Resolve token to actual value
 */
function resolveToken(editor, token) {
    if (!token) return null;
    
    // Check editor's token resolution system
    if (editor.resolveToken) {
        return editor.resolveToken(token);
    }
    
    // Fallback: return null (will show placeholder)
    return null;
}

/**
 * Open WordPress media library
 */
function openMediaLibrary(editor, callback, multiple = false) {
    if (!window.wp || !window.wp.media) {
        alert('WordPress media library not available');
        return;
    }
    
    const frame = window.wp.media({
        title: 'Select Image',
        button: { text: 'Select' },
        multiple: multiple
    });
    
    frame.on('select', () => {
        const selection = frame.state().get('selection');
        if (multiple) {
            const urls = selection.map(attachment => attachment.toJSON().url);
            callback(urls);
        } else {
            const attachment = selection.first().toJSON();
            callback(attachment.url);
        }
    });
    
    frame.open();
}

/**
 * Initialize slideshow animation
 */
function initializeSlideshow(editor, layer, container) {
    // Store slideshow interval ID
    if (!editor._activeSlideshows) {
        editor._activeSlideshows = {};
    }
    
    // Clear existing slideshow for this layer
    if (editor._activeSlideshows[layer.id]) {
        clearInterval(editor._activeSlideshows[layer.id]);
    }
    
    // Start new slideshow
    const interval = layer.images[layer.current_index]?.duration || 5000;
    editor._activeSlideshows[layer.id] = setInterval(() => {
        if (layer.images && layer.images.length > 1) {
            layer.current_index = (layer.current_index + 1) % layer.images.length;
            editor.refreshLayer(layer.id);
        }
    }, interval);
}

/**
 * Refresh a single layer on the canvas
 */
export function refreshLayer(editor, layerId) {
    const container = document.querySelector(`[data-container-id="${layerId}"]`);
    if (!container) return;
    
    // Find layer in config
    const layer = editor.currentConfig?.layers?.find(l => l.id === layerId);
    if (!layer) return;
    
    // Re-render layer
    const newContainer = renderLayer(editor, layer);
    if (newContainer) {
        container.replaceWith(newContainer);
    }
}

/**
 * Remove layer from canvas
 */
export function removeLayer(editor, layerId) {
    const container = document.querySelector(`[data-container-id="${layerId}"]`);
    if (container) {
        container.remove();
    }
    
    // Stop slideshow if active
    if (editor._activeSlideshows && editor._activeSlideshows[layerId]) {
        clearInterval(editor._activeSlideshows[layerId]);
        delete editor._activeSlideshows[layerId];
    }
}

/**
 * Clear all layers from canvas
 */
export function clearAllLayers(editor) {
    const containers = document.querySelectorAll('.canvas-container.unified-layer');
    containers.forEach(container => container.remove());
    
    // Stop all slideshows
    if (editor._activeSlideshows) {
        Object.values(editor._activeSlideshows).forEach(intervalId => clearInterval(intervalId));
        editor._activeSlideshows = {};
    }
}

export const unifiedLayerRenderer = {
    renderLayer,
    refreshLayer,
    removeLayer,
    clearAllLayers
};
