/**
 * Cast Conductor Proprietary License v5
 * SPDX-License-Identifier: LicenseRef-CastConductor-Proprietary-v5
 * Layer Manager Module (Phase 2.7 Extraction)
 * Responsibilities:
 *  - Build layers panel UI (visibility, lock, order)
 *  - Persist order & locks (localStorage)
 *  - Apply z-indices based on current ordering
 *  - Layer rename (double-click to edit name)
 *  - Layer duplicate (copy layer with new ID)
 * 
 * Phase 1 Step 5 Enhancements:
 *  - Display all 8 unified layer kinds with icons
 *  - Support slideshow-image layers from migration
 *  - Consistent UI for all layer types (text, image, special)
 *  - Rich layer names with icons and descriptions
 */
import { buildUnifiedLayerRows } from './legacy-layer-hydration.js';
import { getLayerIcon, getLayerLabel, getQRIconSVG } from './layer-icons.js';

/**
 * Generate a unique layer ID
 */
function generateLayerId(prefix = 'layer') {
  return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
}

export function buildLayersPanel(editor){
  const wrapper = document.getElementById('ccve-layers-panel-wrapper');
  const panel = document.getElementById('ccve-layers-panel');
  const list = document.getElementById('ccve-layers-list');
  if (!panel || !list) return;
  // Build from unified content-block layers (token + hydrated + unified)
  const rows = buildUnifiedLayerRows(editor);
  // Hide only pseudo/legacy static layers (hydrated from old config)
  // Show all real unified layers (including static-text/static-image created via Add Layer)
  const rowsVisible = rows.filter(r => {
    if (!r) return false;
    // Hide pseudo static layers (legacy fallback)
    if (r.isPseudo && (r.kind === 'static-text' || r.kind === 'static-image')) return false;
    // Show all other layers (including real static-text/static-image from unified system)
    return true;
  });
  if (!rowsVisible.length) { if(wrapper) wrapper.style.display='none'; panel.style.display = 'none'; list.innerHTML=''; return; }
  // Ensure wrapper visible when we have rows to show
  if (wrapper) wrapper.style.display='block';
  // Ensure visibility map exists
  editor.containerVisibility = editor.containerVisibility || {};
  editor._layerLockMap = editor._layerLockMap || loadLocks() || {}; // id:boolean
  // Order: use persisted order when available, else natural order from rows
  const persistedOrder = loadOrder();
  const idPos = new Map(); persistedOrder.forEach((id,i)=>idPos.set(id,i));
  const ordered = rowsVisible.slice().sort((a,b)=>{
    const ap=idPos.has(a.id)?idPos.get(a.id):99999; const bp=idPos.has(b.id)?idPos.get(b.id):99999; return ap===bp?0:(ap<bp?-1:1);
  });
  
  // Collect layer groups for group header rendering
  const layerGroups = editor.currentConfig?.layerGroups || {};
  const layers = editor.currentConfig?.layers || [];
  const collapsedGroups = editor._collapsedGroups || new Set();
  
  // Build HTML with group headers inserted before first member of each group
  let listHTML = '';
  let renderedGroups = new Set();
  
  ordered.forEach(r=>{
    const id = r.id;
    const layer = layers.find(l => l.id === id);
    const groupId = layer?.groupId;
    
    // If this layer is in a group, render group header before first member
    if (groupId && layerGroups[groupId] && !renderedGroups.has(groupId)) {
      renderedGroups.add(groupId);
      const group = layerGroups[groupId];
      const isCollapsed = collapsedGroups.has(groupId);
      listHTML += `<div class="ccve-layer-group-header ${isCollapsed ? 'collapsed' : ''}" data-group-id="${groupId}">
        <span class="group-icon">📦</span>
        <span class="group-label">${editor.escapeHtml(group.label || 'Group')}</span>
        <span class="group-count">(${group.memberIds?.length || 0})</span>
        <span class="group-toggle">${isCollapsed ? '▶' : '▼'}</span>
      </div>`;
    }
    
    // Get layer icon and label from centralized mapping
    const layerIcon = getLayerIcon(r.kind);
    const layerLabel = getLayerLabel(r.kind);
    
    // Use custom label if provided, otherwise use kind-based label
    const rawDisplayName = r.label || layerLabel;
    const displayName = editor.escapeHtml(rawDisplayName);
    
    // Build full name with icon (special handling for QR codes)
    let name;
    if (r.kind === 'qr-image') {
      name = `${getQRIconSVG({ size: '14px', color: 'currentColor' })} ${displayName}`;
    } else {
      name = `${layerIcon} ${displayName}`;
    }
    
  if (!(id in editor.containerVisibility)) editor.containerVisibility[id]=true;
    const visible=!!editor.containerVisibility[id];
    const locked=!!editor._layerLockMap[id];
    // Sync existing DOM node visibility/lock if present
  const domSel = `#block-stage [data-layer-id="${CSS.escape(id)}"]`;
  const el=document.querySelector(domSel);
    if(el){ el.classList.toggle('hidden', !visible); el.classList.toggle('ccve-locked', locked); }
    
    // Unified layer type detection (all 8 kinds + legacy)
    const isBackgroundLayer = (r.kind==='overlay' || r.kind==='image' || r.kind==='gradient' || r.kind==='background' || r.kind==='background-image');
    const isPseudo = !!r.isPseudo;
    const isLegacy = (r.kind==='static-text'||r.kind==='static-image');
    const isToken = (r.kind==='token-text' || r.kind==='token-image');
    const isStaticText = (r.kind==='static-text');
    const isStaticImage = (r.kind==='static-image');
    const isSlideshow = (r.kind==='slideshow-image');
    const isQrImage = (r.kind==='qr-image');
    const isWpPost = (r.kind==='wordpress-post');
    const isVideo = (r.kind==='video');
    const isFeed = (r.kind==='feed-layer');
    
    // All real layers (non-pseudo) are editable, lockable, reorderable
    const disableReorder = isPseudo;
    const disableLock = isPseudo; // Only true pseudo layers (legacy fallback) are non-lockable
    
    // All unified layer types support delete and duplicate
    const isDeletable = isToken || isLegacy || isBackgroundLayer || isQrImage || isSlideshow || isStaticText || isStaticImage || isWpPost || isVideo || isFeed;
    // Only unified layers (in config.layers) can be duplicated - not background/overlay pseudo layers
    const isDuplicatable = isToken || isStaticText || isStaticImage || isSlideshow || isQrImage || isWpPost || isVideo || isFeed;
    // Only unified layers can be renamed (not background pseudo layers)
    const isRenamable = isDuplicatable;
    
    // In-group styling and collapse handling
    const inGroup = groupId && layerGroups[groupId];
    const groupCollapsed = inGroup && collapsedGroups.has(groupId);
    const inGroupClass = inGroup ? 'in-group' : '';
    const collapsedClass = groupCollapsed ? 'group-collapsed' : '';
    const groupBadge = inGroup ? `<span class="ccve-group-badge" title="In ${editor.escapeHtml(layerGroups[groupId]?.label || 'Group')} - Press G to ungroup">⛓</span>` : '';
    
  listHTML += `<li data-layer-id="${editor.escapeHtml(id)}" data-layer-kind="${r.kind}" ${groupId ? `data-group-id="${groupId}"` : ''} class="${editor.selectedContainerId===id?'active':''} ${inGroupClass} ${collapsedClass}" role="listitem" tabindex="0" aria-label="Layer ${editor.escapeHtml(displayName)}">
      <span class="ccve-layer-drag" data-drag-id="${editor.escapeHtml(id)}" title="Drag to reorder" aria-label="Reorder handle" role="button" tabindex="0" ${disableReorder?'aria-disabled="true" style="opacity:0.4;cursor:not-allowed;"':''}>⋮⋮</span>
      <button class="ccve-layer-visibility" data-eye-id="${editor.escapeHtml(id)}" title="Toggle visibility" aria-label="Toggle visibility" aria-pressed="${visible}">${visible?'👁️':'🚫'}</button>
      <button class="ccve-layer-lock" data-lock-id="${editor.escapeHtml(id)}" title="${locked?'Unlock':'Lock'}" aria-label="${locked?'Unlock layer':'Lock layer'}" aria-pressed="${locked}" ${disableLock?'disabled':''}>${locked?'🔒':'🔓'}</button>
      <span class="ccve-layer-name ${isRenamable ? 'ccve-layer-renamable' : ''}" data-name-id="${editor.escapeHtml(id)}" data-raw-name="${editor.escapeHtml(rawDisplayName)}" title="${isRenamable ? 'Double-click to rename' : ''}">${name}${groupBadge}</span>
      <div class="ccve-layer-order" role="group" aria-label="Layer order controls">
        <button class="ccve-layer-up" data-up-id="${editor.escapeHtml(id)}" title="Bring Forward" aria-label="Bring Forward" ${disableReorder?'disabled':''}>▲</button>
        <button class="ccve-layer-down" data-down-id="${editor.escapeHtml(id)}" title="Send Back" aria-label="Send Back" ${disableReorder?'disabled':''}>▼</button>
        ${isDuplicatable ? `<button class="ccve-layer-copy" data-copy-id="${editor.escapeHtml(id)}" title="Duplicate Layer" aria-label="Duplicate Layer">📋</button>` : ''}
        ${isDeletable ? `<button class="ccve-layer-delete" data-del-id="${editor.escapeHtml(id)}" data-kind="${r.kind}" data-bg-index="${r._backgroundLayerIndex ?? ''}" title="Delete Layer" aria-label="Delete Layer">✕</button>` : ''}
      </div>
    </li>`;
  });
  
  list.innerHTML = listHTML;
  panel.style.display='block';
  applyZ(editor, list);
  
  // GROUP ACTION BAR - shows when 2+ layers selected
  _updateGroupActionBar(editor, list);
  
  // GROUP HEADER COLLAPSE/EXPAND HANDLERS
  list.querySelectorAll('.ccve-layer-group-header').forEach(header => {
    header.addEventListener('click', e => {
      e.stopPropagation();
      const groupId = header.getAttribute('data-group-id');
      if (!groupId) return;
      
      // Initialize collapsed groups set
      if (!editor._collapsedGroups) editor._collapsedGroups = new Set();
      
      // Toggle collapsed state
      if (editor._collapsedGroups.has(groupId)) {
        editor._collapsedGroups.delete(groupId);
      } else {
        editor._collapsedGroups.add(groupId);
      }
      
      // Rebuild panel to reflect change
      buildLayersPanel(editor);
    });
    
    // Right-click on group header to ungroup
    header.addEventListener('contextmenu', e => {
      e.preventDefault();
      e.stopPropagation();
      const groupId = header.getAttribute('data-group-id');
      if (!groupId) return;
      
      if (editor._layerGrouping) {
        editor._layerGrouping.ungroupLayers(groupId);
      }
    });
  });
  
  // Visibility handlers
  list.querySelectorAll('.ccve-layer-visibility').forEach(btn=>btn.addEventListener('click',e=>{
    e.stopPropagation(); const cid=btn.getAttribute('data-eye-id');
    const cur=(cid in editor.containerVisibility)?editor.containerVisibility[cid]:true; const next=!cur; editor.containerVisibility[cid]=next;
    // Update DOM if present
  const target=document.querySelector(`#block-stage [data-layer-id="${CSS.escape(cid)}"]`);
    if (target) target.classList.toggle('hidden', !next);
    btn.textContent=next?'👁️':'🚫';
  }));
  // Lock handlers (skip pseudo)
  list.querySelectorAll('.ccve-layer-lock').forEach(btn=>btn.addEventListener('click',e=>{
    e.stopPropagation(); if(btn.disabled) return; const cid=btn.getAttribute('data-lock-id');
    editor._layerLockMap[cid]=!editor._layerLockMap[cid];
  const target=document.querySelector(`#block-stage [data-layer-id="${CSS.escape(cid)}"]`);
    if (target) target.classList.toggle('ccve-locked', !!editor._layerLockMap[cid]);
    btn.textContent=editor._layerLockMap[cid]?'🔒':'🔓'; btn.title=editor._layerLockMap[cid]?'Unlock':'Lock';
    persistLocks(editor._layerLockMap);
  }));
  // Reorder (buttons) — updates both visual z-index and config.layers order
  const reorder=(cid,dir)=>{
    const li = list.querySelector(`li[data-layer-id="${CSS.escape(cid)}"]`);
    if(!li) return; if(li.querySelector('.ccve-layer-up[disabled], .ccve-layer-down[disabled]')) return; // disabled reorder
    const items=Array.from(list.querySelectorAll('li'));
    const idx=items.indexOf(li); if(idx<0) return; const nidx=idx+dir; if(nidx<0||nidx>=items.length) return;
    if(dir<0) list.insertBefore(items[idx], items[nidx]); else list.insertBefore(items[nidx], items[idx]);
    applyZ(editor,list); persistOrder(list);
    syncLayerOrderToConfig(editor, list);
    editor.unsavedChanges = true;
    try { editor.updateSaveButton && editor.updateSaveButton(); } catch(_) {}
  };
  list.querySelectorAll('.ccve-layer-up').forEach(btn=>btn.addEventListener('click',e=>{ e.stopPropagation(); if(btn.disabled) return; reorder(btn.getAttribute('data-up-id'),+1); }));
  list.querySelectorAll('.ccve-layer-down').forEach(btn=>btn.addEventListener('click',e=>{ e.stopPropagation(); if(btn.disabled) return; reorder(btn.getAttribute('data-down-id'),-1); }));
  // Delete layer (unified: all 8 layer kinds + legacy + background)
  list.querySelectorAll('.ccve-layer-delete').forEach(btn=>btn.addEventListener('click', e=>{
    e.stopPropagation(); const id = btn.getAttribute('data-del-id'); const kind = btn.getAttribute('data-kind')||''; const bgIndex = btn.getAttribute('data-bg-index'); if(!id) return;
    
    // Check if this is a unified layer (in config.layers[]) or legacy hydrated layer
    const layers = (editor.currentConfig?.layers)||[];
    const isUnifiedLayer = layers.some(l => l && l.id === id);
    
    // Unified layer system: Delete from config.layers[] array
    if (isUnifiedLayer) {
      const idx = layers.findIndex(l=>l && l.id===id);
      if(idx!==-1){ layers.splice(idx,1); }
      const node = document.querySelector(`#block-stage [data-layer-id="${CSS.escape(id)}"]`);
      if(node) node.remove();
      try { editor._pushTokenUndoState && editor._pushTokenUndoState('delete'); } catch(_){ }
      editor.unsavedChanges = true;
      try { editor.updateSaveButton && editor.updateSaveButton(); } catch(_) {}
      // Trigger preview refresh to remove ghost images from server preview
      try { editor.triggerPreview && editor.triggerPreview(true); } catch(_) {}
    } else if (kind==='static-text' || kind==='static-image') {
      // Legacy hydrated layer: Mark as deleted via override
      const ov = editor.currentConfig.legacy_overrides = editor.currentConfig.legacy_overrides || {};
      ov[id] = { ...(ov[id]||{}), deleted: true };
      const node = document.querySelector(`#block-stage [data-layer-id="${CSS.escape(id)}"]`);
      if(node) node.remove();
      editor.unsavedChanges = true;
      try { editor.updateSaveButton && editor.updateSaveButton(); } catch(_) {}
    } else if (kind==='overlay' || kind==='image' || kind==='gradient') {
      // Delete specific background layer by index
      if (editor.currentConfig && editor.currentConfig.background && Array.isArray(editor.currentConfig.background.layers) && bgIndex !== null && bgIndex !== '') {
        const idx = parseInt(bgIndex, 10);
        if (!isNaN(idx) && idx >= 0 && idx < editor.currentConfig.background.layers.length) {
          editor.currentConfig.background.layers.splice(idx, 1);
          // If this was an overlay, also clear the overlay config
          if (kind === 'overlay') {
            editor.currentConfig.overlay = { color: '#000000', opacity: 0 };
          }
          try { editor.refreshBackgroundLayersUI && editor.refreshBackgroundLayersUI(); } catch(_) {}
          editor.unsavedChanges = true;
          try { editor.updateSaveButton && editor.updateSaveButton(); } catch(_) {}
        }
      }
    } else if (kind==='background') {
      // Clear background config entirely (legacy fallback)
      if (editor.currentConfig) {
        editor.currentConfig.background = {};
        try { editor.refreshBackgroundLayersUI && editor.refreshBackgroundLayersUI(); } catch(_) {}
      }
      editor.unsavedChanges = true;
      try { editor.updateSaveButton && editor.updateSaveButton(); } catch(_) {}
    }
    buildLayersPanel(editor);
  }));
  
  // ========================================
  // LAYER RENAME (double-click on name)
  // ========================================
  list.querySelectorAll('.ccve-layer-name.ccve-layer-renamable').forEach(nameSpan => {
    nameSpan.addEventListener('dblclick', e => {
      e.stopPropagation();
      const layerId = nameSpan.getAttribute('data-name-id');
      if (!layerId) return;
      
      // Get current raw name (without icon)
      const currentRawName = nameSpan.getAttribute('data-raw-name') || '';
      
      // Find the layer in config
      const layers = (editor.currentConfig?.layers) || [];
      const layer = layers.find(l => l && l.id === layerId);
      if (!layer) return;
      
      // Get the layer kind for the icon
      const li = nameSpan.closest('li');
      const kind = li?.getAttribute('data-layer-kind') || layer.kind || 'unknown';
      const layerIcon = kind === 'qr-image' ? getQRIconSVG({ size: '14px', color: 'currentColor' }) : getLayerIcon(kind);
      
      // Create inline input for editing
      const input = document.createElement('input');
      input.type = 'text';
      input.className = 'ccve-layer-rename-input';
      input.value = currentRawName;
      input.style.cssText = 'width: calc(100% - 24px); font-size: 12px; padding: 2px 4px; border: 1px solid #3498db; border-radius: 3px; background: #2c3e50; color: #fff; outline: none;';
      
      // Replace span content with input
      const originalHTML = nameSpan.innerHTML;
      nameSpan.innerHTML = '';
      nameSpan.appendChild(input);
      input.focus();
      input.select();
      
      // Handle save on Enter or blur
      const saveRename = () => {
        const newName = input.value.trim();
        if (newName && newName !== currentRawName) {
          // Update layer in config
          layer.label = newName;
          editor.unsavedChanges = true;
          try { editor._pushTokenUndoState && editor._pushTokenUndoState('rename'); } catch(_) {}
          // Update save button to reflect unsaved changes
          try { editor.updateSaveButton && editor.updateSaveButton(); } catch(_) {}
        }
        // Rebuild panel to show new name
        buildLayersPanel(editor);
      };
      
      const cancelRename = () => {
        // Restore original display
        nameSpan.innerHTML = originalHTML;
      };
      
      input.addEventListener('keydown', e => {
        if (e.key === 'Enter') {
          e.preventDefault();
          saveRename();
        } else if (e.key === 'Escape') {
          e.preventDefault();
          cancelRename();
        }
      });
      
      input.addEventListener('blur', () => {
        // Small delay to allow Enter key to process first
        setTimeout(() => {
          if (document.body.contains(input)) {
            saveRename();
          }
        }, 50);
      });
    });
  });
  
  // ========================================
  // LAYER DUPLICATE (copy button)
  // ========================================
  list.querySelectorAll('.ccve-layer-copy').forEach(btn => btn.addEventListener('click', e => {
    e.stopPropagation();
    const layerId = btn.getAttribute('data-copy-id');
    if (!layerId) return;
    
    const layers = (editor.currentConfig?.layers) || [];
    const sourceLayer = layers.find(l => l && l.id === layerId);
    if (!sourceLayer) return;
    
    // Deep clone the layer
    const clonedLayer = JSON.parse(JSON.stringify(sourceLayer));
    
    // Generate new unique ID
    clonedLayer.id = generateLayerId(clonedLayer.kind || 'layer');
    
    // Update label to indicate it's a copy
    const originalLabel = clonedLayer.label || getLayerLabel(clonedLayer.kind) || 'Layer';
    clonedLayer.label = `${originalLabel} (Copy)`;
    
    // Offset position slightly so it's visible
    if (typeof clonedLayer.x === 'number') clonedLayer.x += 20;
    if (typeof clonedLayer.y === 'number') clonedLayer.y += 20;
    
    // Assign z-index (on top)
    clonedLayer.zIndex = 100 + layers.length;
    
    // Add to layers array
    layers.push(clonedLayer);
    
    editor.unsavedChanges = true;
    try { editor.updateSaveButton && editor.updateSaveButton(); } catch(_) {}
    try { editor._pushTokenUndoState && editor._pushTokenUndoState('duplicate'); } catch(_) {}
    
    // Rebuild the canvas and layer panel
    try {
      if (editor.renderTokenLayers) {
        editor.renderTokenLayers();
      }
    } catch(_) {}
    
    buildLayersPanel(editor);
    
    // Flash feedback on the new layer row
    setTimeout(() => {
      const newLi = list.querySelector(`li[data-layer-id="${CSS.escape(clonedLayer.id)}"]`);
      if (newLi) {
        newLi.style.transition = 'background-color 0.3s';
        newLi.style.backgroundColor = '#27ae60';
        setTimeout(() => {
          newLi.style.backgroundColor = '';
        }, 500);
      }
    }, 100);
  }));
  
  // Legacy conversion removed: no UI wiring
  // Keyboard accessibility (skip shortcuts when typing in inputs)
  list.querySelectorAll('li').forEach(li => li.addEventListener('keydown', e => {
    const id = li.getAttribute('data-layer-id');
    if (!id) return;
    // Skip shortcuts when typing in input/textarea (e.g., layer rename)
    if (e.target && (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable)) return;
    if (e.key === 'ArrowUp' && (e.metaKey || e.ctrlKey)) { e.preventDefault(); reorder(id, +1); li.focus(); }
    else if (e.key === 'ArrowDown' && (e.metaKey || e.ctrlKey)) { e.preventDefault(); reorder(id, -1); li.focus(); }
    else if (e.key.toLowerCase() === 'l') { e.preventDefault(); li.querySelector('.ccve-layer-lock')?.click(); }
    else if (e.key.toLowerCase() === 'v') { e.preventDefault(); li.querySelector('.ccve-layer-visibility')?.click(); }
  }));
  // Drag reorder (lightweight) — skip pseudo/background
  let dragInfo=null;
  const onDragMove=(e)=>{ if(!dragInfo) return; e.preventDefault(); const {ghost,startY}=dragInfo; const dy=e.clientY-startY; ghost.style.transform=`translateY(${dy}px)`; const items=Array.from(list.querySelectorAll('li:not(.ccve-dragging-ghost)')); for(const item of items){ if(item.classList.contains('ccve-dragging')) continue; const r=item.getBoundingClientRect(); if(e.clientY<r.top+r.height/2){ if(ghost.nextSibling!==item) list.insertBefore(ghost,item); break;} if(e.clientY>r.bottom-r.height/2){ if(item.nextSibling){ if(ghost!==item.nextSibling) list.insertBefore(ghost,item.nextSibling);} else { list.appendChild(ghost);} } } };
  const onDragEnd=()=>{ if(!dragInfo) return; document.removeEventListener('mousemove',onDragMove); document.removeEventListener('mouseup',onDragEnd); const {li,ghost}=dragInfo; list.insertBefore(li,ghost); ghost.remove(); li.classList.remove('ccve-dragging'); dragInfo=null; applyZ(editor,list); persistOrder(list); syncLayerOrderToConfig(editor, list); editor.unsavedChanges = true; try { editor.updateSaveButton && editor.updateSaveButton(); } catch(_) {} };
  list.querySelectorAll('.ccve-layer-drag').forEach(handle=>handle.addEventListener('mousedown',e=>{ e.preventDefault(); const li=handle.closest('li'); if(!li) return; if(handle.getAttribute('aria-disabled')==='true') return; const ghost=li.cloneNode(true); ghost.classList.add('ccve-dragging-ghost'); ghost.style.opacity='0.4'; ghost.style.pointerEvents='none'; li.classList.add('ccve-dragging'); list.insertBefore(ghost, li.nextSibling); dragInfo={ li, ghost, startY:e.clientY }; document.addEventListener('mousemove',onDragMove); document.addEventListener('mouseup',onDragEnd); }));
  
  // ========================================
  // RIGHT-CLICK CONTEXT MENU
  // ========================================
  list.querySelectorAll('li').forEach(li => {
    li.addEventListener('contextmenu', e => {
      e.preventDefault();
      e.stopPropagation();
      
      const layerId = li.getAttribute('data-layer-id');
      const layerKind = li.getAttribute('data-layer-kind');
      if (!layerId) return;
      
      // Remove any existing context menu
      const existingMenu = document.querySelector('.ccve-layer-context-menu');
      if (existingMenu) existingMenu.remove();
      
      // Check what actions are available for this layer
      const layers = (editor.currentConfig?.layers) || [];
      const isUnifiedLayer = layers.some(l => l && l.id === layerId);
      const isDuplicatable = ['token-text', 'token-image', 'static-text', 'static-image', 'slideshow-image', 'qr-image', 'wordpress-post'].includes(layerKind);
      const isRenamable = isDuplicatable;
      const isDeletable = isUnifiedLayer || ['overlay', 'image', 'gradient', 'background'].includes(layerKind);
      
      // Build menu items
      let menuHTML = `
        <div class="ccve-layer-context-menu" style="position:fixed; left:${e.clientX}px; top:${e.clientY}px; z-index:10000; background:#1e2328; border:1px solid #3d4450; border-radius:6px; padding:4px 0; min-width:150px; box-shadow:0 4px 12px rgba(0,0,0,0.4); font-size:12px; color:#e5e7eb;">
      `;
      
      if (isRenamable) {
        menuHTML += `<div class="ccve-ctx-item" data-action="rename" style="padding:8px 12px; cursor:pointer; display:flex; align-items:center; gap:8px;">
          <span>✏️</span> Rename Layer
        </div>`;
      }
      
      if (isDuplicatable) {
        menuHTML += `<div class="ccve-ctx-item" data-action="duplicate" style="padding:8px 12px; cursor:pointer; display:flex; align-items:center; gap:8px;">
          <span>📋</span> Duplicate Layer
        </div>`;
      }
      
      menuHTML += `<div class="ccve-ctx-item" data-action="visibility" style="padding:8px 12px; cursor:pointer; display:flex; align-items:center; gap:8px;">
        <span>${editor.containerVisibility[layerId] !== false ? '🚫' : '👁️'}</span> ${editor.containerVisibility[layerId] !== false ? 'Hide' : 'Show'} Layer
      </div>`;
      
      menuHTML += `<div class="ccve-ctx-item" data-action="lock" style="padding:8px 12px; cursor:pointer; display:flex; align-items:center; gap:8px;">
        <span>${editor._layerLockMap[layerId] ? '🔓' : '🔒'}</span> ${editor._layerLockMap[layerId] ? 'Unlock' : 'Lock'} Layer
      </div>`;
      
      // LAYER GROUPING SECTION
      // Check if layer grouping manager is available
      const groupingMgr = editor._layerGrouping;
      if (groupingMgr) {
        const selectedLayers = groupingMgr.getSelectedLayers();
        const thisLayer = layers.find(l => l && l.id === layerId);
        const isInGroup = thisLayer && thisLayer.groupId;
        const hasMultiSelection = selectedLayers.length > 1;
        
        menuHTML += `<div style="border-top:1px solid #3d4450; margin:4px 0;"></div>`;
        
        // If multiple layers selected, show "Group Selection"
        if (hasMultiSelection) {
          menuHTML += `<div class="ccve-ctx-item" data-action="group" style="padding:8px 12px; cursor:pointer; display:flex; align-items:center; gap:8px;">
            <span>📦</span> Group Selection <span style="color:#6b7280; margin-left:auto; font-size:10px;">G</span>
          </div>`;
        }
        
        // If this layer is in a group, show "Ungroup"
        if (isInGroup) {
          const groupLabel = groupingMgr.getGroupLabel(thisLayer.groupId);
          menuHTML += `<div class="ccve-ctx-item" data-action="ungroup" style="padding:8px 12px; cursor:pointer; display:flex; align-items:center; gap:8px;">
            <span>📂</span> Ungroup "${groupLabel || 'Group'}" <span style="color:#6b7280; margin-left:auto; font-size:10px;">G</span>
          </div>`;
        }
        
        // Always show "Add to Selection" when right-clicking a non-selected layer
        if (!selectedLayers.some(l => l.id === layerId)) {
          menuHTML += `<div class="ccve-ctx-item" data-action="add-to-selection" style="padding:8px 12px; cursor:pointer; display:flex; align-items:center; gap:8px;">
            <span>➕</span> Add to Selection <span style="color:#6b7280; margin-left:auto; font-size:10px;">Shift+Click</span>
          </div>`;
        }
        
        // Show "Select Group" if layer is in a group but whole group isn't selected
        if (isInGroup) {
          menuHTML += `<div class="ccve-ctx-item" data-action="select-group" style="padding:8px 12px; cursor:pointer; display:flex; align-items:center; gap:8px;">
            <span>🎯</span> Select Entire Group
          </div>`;
        }
      }
      
      if (isDeletable) {
        menuHTML += `<div style="border-top:1px solid #3d4450; margin:4px 0;"></div>`;
        menuHTML += `<div class="ccve-ctx-item" data-action="delete" style="padding:8px 12px; cursor:pointer; display:flex; align-items:center; gap:8px; color:#ef4444;">
          <span>🗑️</span> Delete Layer
        </div>`;
      }
      
      menuHTML += `</div>`;
      
      // Insert menu into DOM
      document.body.insertAdjacentHTML('beforeend', menuHTML);
      const menu = document.querySelector('.ccve-layer-context-menu');
      
      // Add hover effects
      menu.querySelectorAll('.ccve-ctx-item').forEach(item => {
        item.addEventListener('mouseenter', () => {
          if (!item.style.color.includes('ef4444')) {
            item.style.backgroundColor = '#2a313a';
          } else {
            item.style.backgroundColor = 'rgba(239, 68, 68, 0.1)';
          }
        });
        item.addEventListener('mouseleave', () => {
          item.style.backgroundColor = '';
        });
      });
      
      // Handle menu item clicks
      menu.addEventListener('click', menuE => {
        const item = menuE.target.closest('.ccve-ctx-item');
        if (!item) return;
        
        const action = item.getAttribute('data-action');
        
        switch (action) {
          case 'rename':
            // Trigger double-click on the name span
            const nameSpan = li.querySelector('.ccve-layer-name.ccve-layer-renamable');
            if (nameSpan) {
              nameSpan.dispatchEvent(new MouseEvent('dblclick', { bubbles: true }));
            }
            break;
            
          case 'duplicate':
            // Click the copy button
            const copyBtn = li.querySelector('.ccve-layer-copy');
            if (copyBtn) copyBtn.click();
            break;
            
          case 'visibility':
            const visBtn = li.querySelector('.ccve-layer-visibility');
            if (visBtn) visBtn.click();
            break;
            
          case 'lock':
            const lockBtn = li.querySelector('.ccve-layer-lock');
            if (lockBtn) lockBtn.click();
            break;
            
          case 'delete':
            const delBtn = li.querySelector('.ccve-layer-delete');
            if (delBtn) delBtn.click();
            break;
          
          case 'group':
            // Group currently selected layers
            if (editor._layerGrouping) {
              editor._layerGrouping.groupSelectedLayers();
            }
            break;
          
          case 'ungroup':
            // Ungroup the layer's group
            const layer = (editor.currentConfig?.layers || []).find(l => l && l.id === layerId);
            if (layer && layer.groupId && editor._layerGrouping) {
              editor._layerGrouping.ungroupLayers(layer.groupId);
            }
            break;
          
          case 'add-to-selection':
            // Add this layer to the current multi-selection
            if (editor._layerGrouping) {
              const targetLayer = (editor.currentConfig?.layers || []).find(l => l && l.id === layerId);
              if (targetLayer) {
                editor._layerGrouping.selectLayer(targetLayer, true); // true = add to selection
              }
            }
            break;
          
          case 'select-group':
            // Select all layers in this layer's group
            const groupLayer = (editor.currentConfig?.layers || []).find(l => l && l.id === layerId);
            if (groupLayer && groupLayer.groupId && editor._layerGrouping) {
              editor._layerGrouping.selectGroup(groupLayer.groupId);
            }
            break;
        }
        
        menu.remove();
      });
      
      // Close menu on click outside
      const closeMenu = (closeE) => {
        if (!menu.contains(closeE.target)) {
          menu.remove();
          document.removeEventListener('click', closeMenu);
        }
      };
      setTimeout(() => document.addEventListener('click', closeMenu), 0);
      
      // Close menu on Escape
      const escHandler = (escE) => {
        if (escE.key === 'Escape') {
          menu.remove();
          document.removeEventListener('keydown', escHandler);
        }
      };
      document.addEventListener('keydown', escHandler);
    });
  });
}

/**
 * Sync layer order from UI list to config.layers array
 * This ensures the database saves the correct layer order
 * Also updates zIndex on each layer for consistent rendering
 */
function syncLayerOrderToConfig(editor, list) {
  if (!editor.currentConfig || !Array.isArray(editor.currentConfig.layers)) return;
  
  const uiOrder = Array.from(list.querySelectorAll('li')).map(li => li.getAttribute('data-layer-id'));
  const layers = editor.currentConfig.layers;
  
  // Create a map of layer id to layer object
  const layerMap = new Map();
  layers.forEach(l => { if (l && l.id) layerMap.set(l.id, l); });
  
  // Rebuild layers array in UI order and assign zIndex
  const reordered = [];
  uiOrder.forEach((id, index) => {
    if (layerMap.has(id)) {
      const layer = layerMap.get(id);
      layer.zIndex = 100 + index; // Match applyZ z-index calculation
      reordered.push(layer);
      layerMap.delete(id); // Remove from map to track what's been added
    }
  });
  
  // Append any remaining layers that weren't in the UI (shouldn't happen, but safety)
  let extraIndex = reordered.length;
  layerMap.forEach(l => {
    l.zIndex = 100 + extraIndex++;
    reordered.push(l);
  });
  
  // Replace layers array contents
  editor.currentConfig.layers.length = 0;
  reordered.forEach(l => editor.currentConfig.layers.push(l));
}

function applyZ(editor, list){
  const items=Array.from(list.querySelectorAll('li'));
  items.forEach((li,i)=>{
    const id=li.getAttribute('data-layer-id');
    const el=document.querySelector(`[data-layer-id="${CSS.escape(id)}"]`);
    if(el) el.style.zIndex = String(100 + i);
  });
}

/**
 * Update Group Action Bar - shows Group/Ungroup buttons when layers selected
 */
function _updateGroupActionBar(editor, list) {
  const panel = document.getElementById('ccve-layers-panel');
  if (!panel) return;
  
  // Remove existing action bar
  const existing = panel.querySelector('.ccve-group-action-bar');
  if (existing) existing.remove();
  
  const groupingMgr = editor._layerGrouping;
  if (!groupingMgr) return;
  
  const selectedLayers = groupingMgr.getSelectedLayers();
  const selectedCount = selectedLayers.length;
  
  // Only show if 2+ layers selected
  if (selectedCount < 2) return;
  
  // Check if all selected are in same group
  const groupIds = new Set();
  selectedLayers.forEach(l => { if (l.groupId) groupIds.add(l.groupId); });
  const allInSameGroup = groupIds.size === 1 && selectedLayers.every(l => l.groupId);
  
  // Create action bar
  const bar = document.createElement('div');
  bar.className = 'ccve-group-action-bar';
  bar.style.cssText = `
    display: flex;
    gap: 8px;
    padding: 8px;
    background: rgba(56, 189, 248, 0.1);
    border-bottom: 1px solid rgba(56, 189, 248, 0.3);
    align-items: center;
  `;
  
  const label = document.createElement('span');
  label.style.cssText = 'font-size: 11px; color: #38bdf8; flex: 1;';
  label.textContent = `${selectedCount} layers selected`;
  bar.appendChild(label);
  
  if (allInSameGroup) {
    // Show Ungroup button
    const ungroupBtn = document.createElement('button');
    ungroupBtn.className = 'ccve-group-btn';
    ungroupBtn.style.cssText = `
      background: #3d4450;
      border: 1px solid #38bdf8;
      color: #38bdf8;
      padding: 4px 10px;
      border-radius: 4px;
      font-size: 11px;
      cursor: pointer;
      display: flex;
      align-items: center;
      gap: 4px;
    `;
    ungroupBtn.innerHTML = '📂 Ungroup';
    ungroupBtn.title = 'Ungroup layers (G)';
    ungroupBtn.addEventListener('click', () => {
      const groupId = [...groupIds][0];
      groupingMgr.ungroupLayers(groupId);
    });
    bar.appendChild(ungroupBtn);
  } else {
    // Show Group button
    const groupBtn = document.createElement('button');
    groupBtn.className = 'ccve-group-btn';
    groupBtn.style.cssText = `
      background: #38bdf8;
      border: none;
      color: #1e2328;
      padding: 4px 10px;
      border-radius: 4px;
      font-size: 11px;
      font-weight: 600;
      cursor: pointer;
      display: flex;
      align-items: center;
      gap: 4px;
    `;
    groupBtn.innerHTML = '📦 Group';
    groupBtn.title = 'Group selected layers (G)';
    groupBtn.addEventListener('click', () => {
      groupingMgr.groupSelectedLayers();
    });
    bar.appendChild(groupBtn);
  }
  
  // Clear selection button
  const clearBtn = document.createElement('button');
  clearBtn.style.cssText = `
    background: transparent;
    border: none;
    color: #6b7280;
    padding: 4px;
    cursor: pointer;
    font-size: 12px;
  `;
  clearBtn.innerHTML = '✕';
  clearBtn.title = 'Clear selection (Esc)';
  clearBtn.addEventListener('click', () => {
    groupingMgr.clearSelection();
    buildLayersPanel(editor);
  });
  bar.appendChild(clearBtn);
  
  // Insert at top of panel, after heading if present
  const heading = panel.querySelector('h4, h3, .ccve-panel-heading');
  if (heading) {
    heading.after(bar);
  } else {
    panel.insertBefore(bar, panel.firstChild);
  }
}

function orderStorageKey(){ return 'ccve_layer_order'; }
function lockStorageKey(){ return 'ccve_layer_locks'; }
function persistOrder(list){ try { const ids=Array.from(list.querySelectorAll('li')).map(li=>li.getAttribute('data-layer-id')); localStorage.setItem(orderStorageKey(), JSON.stringify(ids)); } catch(_){} }
function loadOrder(){ try { const raw=localStorage.getItem(orderStorageKey()); if(!raw) return []; const arr=JSON.parse(raw); return Array.isArray(arr)?arr:[]; } catch(_){ return []; } }
function persistLocks(map){ try { localStorage.setItem(lockStorageKey(), JSON.stringify(map||{})); } catch(_){} }
function loadLocks(){ try { const raw=localStorage.getItem(lockStorageKey()); if(!raw) return null; const obj=JSON.parse(raw); return obj&&typeof obj==='object'?obj:null; } catch(_){ return null; } }

export const layerManagerApi = { buildLayersPanel, persistOrder, persistLocks, loadOrder, loadLocks };
