// Profile Invoice Generator - Initializes canvas on the edit-profile page
// Global state to persist between tab switches
window.profileInvoiceState = window.profileInvoiceState || {
  elements: [],
  selectedElement: null,
  elementCounter: 0,
  initialized: false
};

window.initProfileInvoiceGenerator = function() {
  var containerId = 'invoice-canvas-container-profile';
  var container = document.getElementById(containerId);
  
  if (!container) {
    console.error('Canvas container not found:', containerId);
    return;
  }
  
  // Always clear and recreate canvas to ensure clean state
  container.innerHTML = '';
  window.profileInvoiceState.initialized = false;
  
  // Get container dimensions
  var rect = container.getBoundingClientRect();
  if (rect.width === 0 || rect.height === 0) {
    console.error('Container has no size');
    return;
  }
  
  // Create canvas element
  var canvas = document.createElement('canvas');
  canvas.style.display = 'block';
  canvas.width = rect.width;
  canvas.height = rect.height;
  container.appendChild(canvas);
  
  var ctx = canvas.getContext('2d');
  
  // Restore state from global or initialize
  var elements = window.profileInvoiceState.elements;
  var selectedElement = window.profileInvoiceState.selectedElement;
  var elementCounter = window.profileInvoiceState.elementCounter;

  // Undo history: snapshots of the elements array, max 10 steps back.
  // Reset on every init so a canvas never restores states of the other
  // generator page (profile vs. admin system template).
  var undoStack = [];
  var MAX_UNDO_STEPS = 10;

  function pushUndoState() {
    try {
      var snapshot = JSON.stringify(elements);
      if (undoStack.length && undoStack[undoStack.length - 1] === snapshot) return;
      undoStack.push(snapshot);
      if (undoStack.length > MAX_UNDO_STEPS) undoStack.shift();
    } catch (err) {
      console.error('Could not record undo state:', err);
    }
  }

  window.undoProfileCanvas = function() {
    if (!undoStack.length) return false;
    var snapshot = JSON.parse(undoStack.pop());
    // Keep the same array reference (shared with profileInvoiceState)
    elements.length = 0;
    snapshot.forEach(function(el) { elements.push(el); });
    selectedElement = null;
    saveState();
    notifyElementDeselected();
    draw();
    return true;
  };
  var isDragging = false;
  var dragStart = { x: 0, y: 0 };
  var elementStart = { x: 0, y: 0 };
  var gridSize = 5;
  
  // Image cache to prevent flickering during resize
  var imageCache = {};
  
  // Page dimensions
  var padding = 10;
  var pageX, pageY, pageWidth, pageHeight;
  var zoomFactor = 1;
  var basePageWidth = 595; // A4 width in pixels at 96 DPI
  var basePageHeight = 842; // A4 height in pixels at 96 DPI
  
  function updatePageDimensions() {
    var w = canvas.width;
    var h = canvas.height;
    var availableWidth = w - padding * 2;
    var availableHeight = h - padding * 2;
    
    // Calculate zoom factor based on available space
    var zoomX = availableWidth / basePageWidth;
    var zoomY = availableHeight / basePageHeight;
    zoomFactor = Math.min(zoomX, zoomY);
    
    pageWidth = basePageWidth * zoomFactor;
    pageHeight = basePageHeight * zoomFactor;
    pageX = (w - pageWidth) / 2;
    pageY = (h - pageHeight) / 2;
  }
  
  function snapToGrid(value) {
    return Math.round(value / gridSize) * gridSize;
  }
  
  // Notify Java about element selection
  function notifyElementSelected(el) {
    if (window.invoiceGeneratorViewProfile && window.invoiceGeneratorViewProfile.$server) {
      window.invoiceGeneratorViewProfile.$server.updatePropertiesPanel(
        el.id,
        el.type,
        el.text || '',
        el.x,
        el.y,
        el.fontSize || 14,
        el.color || '#333333',
        el.width || 100,
        el.height || 30,
        el.isStatic || false,
        el.variable || null
      );
    }
  }
  
  function notifyElementDeselected() {
    if (window.invoiceGeneratorViewProfile && window.invoiceGeneratorViewProfile.$server) {
      window.invoiceGeneratorViewProfile.$server.resetPropertiesPanel();
    }
  }
  
  // Draw function
  function draw() {
    console.log('draw() called, elements:', elements.length);
    var w = canvas.width;
    var h = canvas.height;
    console.log('Canvas size:', w, 'x', h);
    
    // Clear background
    ctx.fillStyle = '#e8e8e8';
    ctx.fillRect(0, 0, w, h);
    
    updatePageDimensions();
    
    // Page shadow
    ctx.fillStyle = 'rgba(0,0,0,0.2)';
    ctx.fillRect(pageX + 4, pageY + pageHeight, pageWidth, 4);
    ctx.fillRect(pageX + pageWidth, pageY + 4, 4, pageHeight);
    
    // White page
    ctx.fillStyle = '#ffffff';
    ctx.fillRect(pageX, pageY, pageWidth, pageHeight);
    ctx.strokeStyle = '#cccccc';
    ctx.lineWidth = 1;
    ctx.strokeRect(pageX, pageY, pageWidth, pageHeight);
    
    // Grid (scaled by zoom factor)
    ctx.strokeStyle = 'rgba(200, 200, 200, 0.3)';
    ctx.lineWidth = 0.5;
    var scaledGridSize = gridSize * zoomFactor;
    for (var x = pageX; x <= pageX + pageWidth; x += scaledGridSize) {
      ctx.beginPath();
      ctx.moveTo(x, pageY);
      ctx.lineTo(x, pageY + pageHeight);
      ctx.stroke();
    }
    for (var y = pageY; y <= pageY + pageHeight; y += scaledGridSize) {
      ctx.beginPath();
      ctx.moveTo(pageX, y);
      ctx.lineTo(pageX + pageWidth, y);
      ctx.stroke();
    }
    
    // Draw elements
    console.log('Drawing', elements.length, 'elements');
    elements.forEach(function(el) {
      console.log('Drawing element:', el.id, 'at', el.x, el.y, 'text:', el.text);
      drawElement(el);
    });
    
    // Draw selection
    if (selectedElement) {
      drawSelection(selectedElement);
    }
  }
  
  function drawElement(el) {
    ctx.save();
    
    // Apply zoom factor to position and size
    var x = pageX + (el.x * zoomFactor);
    var y = pageY + (el.y * zoomFactor);
    var w = (el.width || 100) * zoomFactor;
    var h = (el.height || 30) * zoomFactor;
    var fontSize = (el.fontSize || 14) * zoomFactor;
    var textAlign = el.textAlign || 'left';
    
    if (el.type === 'line') {
      ctx.strokeStyle = el.color || '#333333';
      ctx.lineWidth = Math.max(1, zoomFactor);
      ctx.beginPath();
      ctx.moveTo(x, y);
      ctx.lineTo(x + w, y);
      ctx.stroke();
    } else if (el.type === 'image') {
      if (el.imageData) {
        // Check if image is already cached
        if (imageCache[el.imageData]) {
          // Use cached image for flicker-free rendering
          var img = imageCache[el.imageData];
          // Calculate dimensions to maintain aspect ratio (object-fit: contain)
          var imgAspect = img.width / img.height;
          var boxAspect = w / h;
          var drawW, drawH, drawX, drawY;
          
          if (imgAspect > boxAspect) {
            drawW = w;
            drawH = w / imgAspect;
            drawX = x;
            drawY = y + (h - drawH) / 2;
          } else {
            drawW = h * imgAspect;
            drawH = h;
            drawX = x + (w - drawW) / 2;
            drawY = y;
          }
          
          ctx.drawImage(img, drawX, drawY, drawW, drawH);
        } else {
          // Load and cache the image
          var img = new Image();
          img.onload = function() {
            imageCache[el.imageData] = img;
            // Calculate dimensions to maintain aspect ratio
            var imgAspect = img.width / img.height;
            var boxAspect = w / h;
            var drawW, drawH, drawX, drawY;
            
            if (imgAspect > boxAspect) {
              drawW = w;
              drawH = w / imgAspect;
              drawX = x;
              drawY = y + (h - drawH) / 2;
            } else {
              drawW = h * imgAspect;
              drawH = h;
              drawX = x + (w - drawW) / 2;
              drawY = y;
            }
            
            ctx.drawImage(img, drawX, drawY, drawW, drawH);
            // Redraw selection if this element is selected
            if (selectedElement && selectedElement.id === el.id) {
              drawSelection(el);
            }
          };
          img.src = el.imageData;
        }
      } else {
        // Draw placeholder
        ctx.fillStyle = '#f0f0f0';
        ctx.fillRect(x, y, w, h);
        ctx.strokeStyle = '#999999';
        ctx.strokeRect(x, y, w, h);
        ctx.fillStyle = '#666666';
        ctx.font = Math.max(8, 12 * zoomFactor) + 'px Arial';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText('Bild', x + w / 2, y + h / 2);
      }
    } else if (el.variable === 'services.list') {
      // Draw services list as a table
      drawServicesTable(el, x, y, w, h, fontSize);
    } else {
      // Text elements
      var lines = (el.text || '').split('\n');
      var lineHeight = fontSize * 1.2;
      var totalTextHeight = lines.length * lineHeight;
      
      // Vertically center the text in the element
      var ty = y + (h - totalTextHeight) / 2;
      
      // Draw background highlight for static elements
      if (el.isStatic) {
        var textWidth = ctx.measureText(el.text || '').width + (10 * zoomFactor);
        // Different background colors: green for customer, blue for masterdata
        if (el.isCustomer) {
          ctx.fillStyle = 'rgba(46, 204, 113, 0.15)'; // Light green for customer
        } else {
          ctx.fillStyle = 'rgba(25, 118, 210, 0.1)'; // Light blue for masterdata
        }
        ctx.fillRect(x - (3 * zoomFactor), y - (2 * zoomFactor), Math.max(w, textWidth), h);
      }
      
      // Always use black text for static elements, otherwise use element color
      ctx.fillStyle = el.isStatic ? '#000000' : (el.color || '#333333');
      // Masterdata elements are never bold; other elements respect their fontStyle
      var fontWeight = (el.isStatic && !el.isCustomer) ? '' : (el.fontStyle || '');
      ctx.font = (fontWeight ? fontWeight + ' ' : '') + fontSize + 'px Arial';
      ctx.textBaseline = 'top';
      ctx.textAlign = textAlign;

      var textX = x;
      if (textAlign === 'center') {
        textX = x + (w / 2);
      } else if (textAlign === 'right') {
        textX = x + w;
      }
      
      lines.forEach(function(line) {
        ctx.fillText(line, textX, ty);
        ty += lineHeight;
      });
    }
    
    ctx.restore();
  }
  
  // Draw services list as a table with columns: Name, Steuersatz, Nettobetrag
  // Plus summary section below: Nettosumme, USt, Gesamtsumme
  function drawServicesTable(el, x, y, w, h, fontSize) {
    var lineHeight = fontSize * 1.4;
    var padding = 4 * zoomFactor;
    var rowHeight = lineHeight + padding * 2;
    var summaryRowHeight = fontSize * 1.6;
    var summaryGap = fontSize * 0.5;
    
    // Column widths (percentages of total width)
    var colNameWidth = w * 0.55;      // 55% for Name (left-aligned)
    var colVatWidth = w * 0.20;       // 20% for Steuersatz (right-aligned)
    var colNetWidth = w * 0.25;       // 25% for Nettobetrag (right-aligned)
    
    var colNameX = x;
    var colVatX = x + colNameWidth;
    var colNetX = colVatX + colVatWidth;
    
    var vatRate = (window.profileInvoiceVatRate != null) ? window.profileInvoiceVatRate : 0.19;
    var vatPctLabel = (Math.round(vatRate * 10000) / 100).toString().replace('.', ',') + '%';

    // Rows come from window.profileInvoiceServiceData when provided (system
    // invoice template: the three admin price table positions); otherwise
    // fall back to sample data (per-user profile invoice generator)
    var serviceData = window.profileInvoiceServiceData;
    var rows = (serviceData && serviceData.rows && serviceData.rows.length)
      ? serviceData.rows
      : [
          { name: 'Umzugsleistung inkl. Verpackung', vat: vatPctLabel, net: '450,00 €' },
          { name: 'Entsorgung Möbel', vat: vatPctLabel, net: '85,00 €' },
          { name: 'Montage/De-Montage', vat: vatPctLabel, net: '120,00 €' }
        ];

    // Calculate actual content height based on table + summary
    var tableOnlyHeight = rowHeight * (rows.length + 1); // Header + data rows
    var summaryOnlyHeight = summaryGap + (summaryRowHeight * 3) + summaryGap + summaryRowHeight + summaryGap;
    var calculatedContentHeight = tableOnlyHeight + summaryOnlyHeight;
    // Ensure background covers at least the element height or the calculated content
    var bgHeight = Math.max(h, calculatedContentHeight * zoomFactor);
    
    // Draw orange background highlight for entire service variable element
    var bgPadding = 3 * zoomFactor;
    ctx.fillStyle = 'rgba(255, 152, 0, 0.15)';
    ctx.fillRect(x - bgPadding, y - (2 * zoomFactor), w + (2 * bgPadding), bgHeight + (4 * zoomFactor));
    
    // Draw table header (overlays the background)
    ctx.fillStyle = '#f5f5f5';
    ctx.fillRect(x, y, w, rowHeight);
    
    // Header border
    ctx.strokeStyle = '#cccccc';
    ctx.lineWidth = Math.max(0.5, zoomFactor);
    ctx.beginPath();
    ctx.moveTo(x, y + rowHeight);
    ctx.lineTo(x + w, y + rowHeight);
    ctx.stroke();
    
    // Header text
    ctx.fillStyle = '#333333';
    ctx.font = 'bold ' + fontSize + 'px Arial';
    ctx.textBaseline = 'middle';
    
    // Name column header (left-aligned)
    ctx.textAlign = 'left';
    ctx.fillText('Name', colNameX + padding, y + rowHeight / 2);
    
    // Steuersatz column header (right-aligned)
    ctx.textAlign = 'right';
    ctx.fillText('Steuersatz', colVatX + colVatWidth - padding, y + rowHeight / 2);
    
    // Nettobetrag column header (right-aligned)
    ctx.fillText('Nettobetrag', colNetX + colNetWidth - padding, y + rowHeight / 2);
    
    var currentY = y + rowHeight;

    // Draw data rows
    ctx.font = fontSize + 'px Arial';
    rows.forEach(function(row, index) {
      // Draw row background (alternating)
      if (index % 2 === 1) {
        ctx.fillStyle = 'rgba(0,0,0,0.02)';
        ctx.fillRect(x, currentY, w, rowHeight);
      }
      
      // Row bottom border
      ctx.strokeStyle = '#eeeeee';
      ctx.lineWidth = Math.max(0.5, zoomFactor * 0.5);
      ctx.beginPath();
      ctx.moveTo(x, currentY + rowHeight);
      ctx.lineTo(x + w, currentY + rowHeight);
      ctx.stroke();
      
      // Draw cell text
      ctx.fillStyle = '#333333';
      
      // Name (left-aligned)
      ctx.textAlign = 'left';
      ctx.fillText(row.name, colNameX + padding, currentY + rowHeight / 2);
      
      // Steuersatz (right-aligned)
      ctx.textAlign = 'right';
      ctx.fillText(row.vat, colVatX + colVatWidth - padding, currentY + rowHeight / 2);
      
      // Nettobetrag (right-aligned)
      ctx.fillText(row.net, colNetX + colNetWidth - padding, currentY + rowHeight / 2);
      
      currentY += rowHeight;
    });
    
    // Draw column separator lines
    ctx.strokeStyle = '#e0e0e0';
    ctx.lineWidth = Math.max(0.5, zoomFactor * 0.5);
    ctx.beginPath();
    // Line between Name and Steuersatz
    ctx.moveTo(colVatX, y);
    ctx.lineTo(colVatX, currentY);
    // Line between Steuersatz and Nettobetrag
    ctx.moveTo(colNetX, y);
    ctx.lineTo(colNetX, currentY);
    ctx.stroke();
    
    // Draw outer border around table
    ctx.strokeStyle = '#cccccc';
    ctx.lineWidth = Math.max(0.5, zoomFactor);
    ctx.strokeRect(x, y, w, currentY - y);
    
    // Draw summary section below the table
    var summaryY = currentY + summaryGap;
    
    // Column positions for summary section
    var labelX = x + colNameWidth + colVatWidth * 0.3; // Label column (left-aligned)
    var valueX = x + w - padding; // Value column (right-aligned)
    
    // Totals: provided with the service data or calculated from sample data
    var netTotalLabel, vatTotalLabel, grossTotalLabel;
    if (serviceData && serviceData.netTotal) {
      netTotalLabel = serviceData.netTotal;
      vatTotalLabel = serviceData.vatTotal;
      grossTotalLabel = serviceData.grossTotal;
    } else {
      var netTotal = 655.00; // 450 + 85 + 120
      var vatTotal = netTotal * vatRate;
      netTotalLabel = netTotal.toFixed(2).replace('.', ',') + ' €';
      vatTotalLabel = vatTotal.toFixed(2).replace('.', ',') + ' €';
      grossTotalLabel = (netTotal + vatTotal).toFixed(2).replace('.', ',') + ' €';
    }

    // Draw summary lines
    ctx.textBaseline = 'middle';
    
    // Nettosumme - label left, value right
    ctx.fillStyle = '#333333';
    ctx.font = fontSize + 'px Arial';
    ctx.textAlign = 'left';
    ctx.fillText('Nettosumme:', labelX, summaryY + summaryRowHeight / 2);
    ctx.font = 'bold ' + fontSize + 'px Arial';
    ctx.textAlign = 'right';
    ctx.fillText(netTotalLabel, valueX, summaryY + summaryRowHeight / 2);
    summaryY += summaryRowHeight;

    // Umsatzsteuer - label left, value right
    ctx.font = fontSize + 'px Arial';
    ctx.textAlign = 'left';
    ctx.fillText('zzgl. ' + vatPctLabel + ' USt:', labelX, summaryY + summaryRowHeight / 2);
    ctx.font = 'bold ' + fontSize + 'px Arial';
    ctx.textAlign = 'right';
    ctx.fillText(vatTotalLabel, valueX, summaryY + summaryRowHeight / 2);
    summaryY += summaryRowHeight;

    // Gesamtsumme - label left, value right
    summaryY += summaryGap; // Extra gap before total
    ctx.fillStyle = '#000000';
    ctx.font = 'bold ' + (fontSize * 1.1) + 'px Arial';
    ctx.textAlign = 'left';
    ctx.fillText('Gesamtsumme:', labelX, summaryY + summaryRowHeight / 2);
    ctx.textAlign = 'right';
    ctx.fillText(grossTotalLabel, valueX, summaryY + summaryRowHeight / 2);
  }
  
  function drawSelection(el) {
    var x = pageX + (el.x * zoomFactor);
    var y = pageY + (el.y * zoomFactor);
    var w = (el.width || 100) * zoomFactor;
    var h = (el.height || 30) * zoomFactor;
    
    // For text elements, calculate actual text dimensions
    if (el.type !== 'line' && el.type !== 'image') {
      var fontSize = (el.fontSize || 14) * zoomFactor;
      ctx.font = (el.fontStyle || '') + ' ' + fontSize + 'px Arial';
      
      // For services.list, calculate table height including summary section
      if (el.variable === 'services.list') {
        var lineHeight = fontSize * 1.4;
        var padding = 4 * zoomFactor;
        var rowHeight = lineHeight + padding * 2;
        var tableHeight = rowHeight + 3 * rowHeight; // Header + 3 rows
        var summaryRowHeight = fontSize * 1.6;
        var summaryGap = fontSize * 0.5;
        var summaryHeight = summaryGap + (summaryRowHeight * 3) + summaryGap + summaryRowHeight + summaryGap;
        var totalHeight = tableHeight + summaryHeight;
        h = Math.max(h, totalHeight);
      } else {
        var lines = (el.text || '').split('\n');
        var maxLineWidth = 0;
        lines.forEach(function(line) {
          var lineWidth = ctx.measureText(line).width;
          maxLineWidth = Math.max(maxLineWidth, lineWidth);
        });
        
        // Use the larger of defined width or actual text width
        w = Math.max(w, maxLineWidth + (10 * zoomFactor));
        
        // Calculate actual height based on number of lines
        var lineHeight = fontSize * 1.2;
        var textHeight = lines.length * lineHeight;
        h = Math.max(h, textHeight + (6 * zoomFactor));
      }
    }
    
    ctx.strokeStyle = '#1976d2';
    ctx.lineWidth = Math.max(1, 2 * zoomFactor);
    ctx.setLineDash([5, 3]);
    ctx.strokeRect(x, y, w, h);
    ctx.setLineDash([]);
    
    // Don't show resize handles for static elements (except services.list)
    if (el.isStatic && el.variable !== 'services.list') {
      return;
    }
    
    // Handles
    var hs = Math.max(6, 8 * zoomFactor); // handle size scaled
    ctx.fillStyle = '#ffffff';
    ctx.strokeStyle = '#1976d2';
    ctx.lineWidth = Math.max(1, 2 * zoomFactor);
    
    var positions = [
      [x - hs/2, y - hs/2],
      [x + w/2 - hs/2, y - hs/2],
      [x + w - hs/2, y - hs/2],
      [x - hs/2, y + h/2 - hs/2],
      [x + w - hs/2, y + h/2 - hs/2],
      [x - hs/2, y + h - hs/2],
      [x + w/2 - hs/2, y + h - hs/2],
      [x + w - hs/2, y + h - hs/2]
    ];
    
    positions.forEach(function(pos) {
      ctx.fillRect(pos[0], pos[1], hs, hs);
      ctx.strokeRect(pos[0], pos[1], hs, hs);
    });
  }
  
  function hitTest(x, y, el) {
    var ex = pageX + (el.x * zoomFactor);
    var ey = pageY + (el.y * zoomFactor);
    var ew = (el.width || 100) * zoomFactor;
    var eh = (el.height || 30) * zoomFactor;
    
    // For text elements, calculate actual text dimensions for hit testing
    if (el.type !== 'line' && el.type !== 'image') {
      var fontSize = (el.fontSize || 14) * zoomFactor;
      ctx.font = (el.fontStyle || '') + ' ' + fontSize + 'px Arial';
      
      // For services.list, calculate table height
      if (el.variable === 'services.list') {
        var lineHeight = fontSize * 1.4;
        var padding = 4 * zoomFactor;
        var rowHeight = lineHeight + padding * 2;
        var tableHeight = rowHeight + 3 * rowHeight; // Header + 3 rows
        var summaryRowHeight = fontSize * 1.6;
        var summaryGap = fontSize * 0.5;
        var summaryHeight = summaryGap + (summaryRowHeight * 3) + summaryGap + summaryRowHeight + summaryGap;
        eh = Math.max(eh, tableHeight + summaryHeight);
      } else {
        var lines = (el.text || '').split('\n');
        var maxLineWidth = 0;
        lines.forEach(function(line) {
          var lineWidth = ctx.measureText(line).width;
          maxLineWidth = Math.max(maxLineWidth, lineWidth);
        });
        
        ew = Math.max(ew, maxLineWidth + (10 * zoomFactor));
        
        var lineHeight = fontSize * 1.2;
        var textHeight = lines.length * lineHeight;
        eh = Math.max(eh, textHeight + (6 * zoomFactor));
      }
    }
    
    return x >= ex && x <= ex + ew && y >= ey && y <= ey + eh;
  }
  
  // Resizing state
  var isResizing = false;
  var resizeHandle = -1;
  var resizeStart = { x: 0, y: 0, width: 0, height: 0 };
  
  // Helper function to check if a point is on a resize handle
  function getResizeHandle(x, y, el) {
    if (!el) return -1;
    // Allow resizing for services.list even though it's static
    if (el.isStatic && el.variable !== 'services.list') return -1;
    
    var ex = pageX + (el.x * zoomFactor);
    var ey = pageY + (el.y * zoomFactor);
    var ew = (el.width || 100) * zoomFactor;
    var eh = (el.height || 30) * zoomFactor;
    
    // For services.list, calculate table height including summary
    if (el.variable === 'services.list') {
      var fontSize = (el.fontSize || 14) * zoomFactor;
      var lineHeight = fontSize * 1.4;
      var padding = 4 * zoomFactor;
      var rowHeight = lineHeight + padding * 2;
      var tableHeight = rowHeight + 3 * rowHeight; // Header + 3 rows
      var summaryRowHeight = fontSize * 1.6;
      var summaryGap = fontSize * 0.5;
      var summaryHeight = summaryGap + (summaryRowHeight * 3) + summaryGap + summaryRowHeight + summaryGap;
      eh = Math.max(eh, tableHeight + summaryHeight);
    }
    
    var hs = Math.max(6, 8 * zoomFactor);
    var halfHs = hs / 2;
    
    // Handle positions: 0=TL, 1=TC, 2=TR, 3=ML, 4=MR, 5=BL, 6=BC, 7=BR
    var handles = [
      { x: ex - halfHs, y: ey - halfHs },
      { x: ex + ew/2 - halfHs, y: ey - halfHs },
      { x: ex + ew - halfHs, y: ey - halfHs },
      { x: ex - halfHs, y: ey + eh/2 - halfHs },
      { x: ex + ew - halfHs, y: ey + eh/2 - halfHs },
      { x: ex - halfHs, y: ey + eh - halfHs },
      { x: ex + ew/2 - halfHs, y: ey + eh - halfHs },
      { x: ex + ew - halfHs, y: ey + eh - halfHs }
    ];
    
    for (var i = 0; i < handles.length; i++) {
      if (x >= handles[i].x && x <= handles[i].x + hs &&
          y >= handles[i].y && y <= handles[i].y + hs) {
        return i;
      }
    }
    return -1;
  }
  
  // Mouse events
  canvas.addEventListener('mousedown', function(e) {
    var rect = canvas.getBoundingClientRect();
    var x = e.clientX - rect.left;
    var y = e.clientY - rect.top;
    
    // Check if clicking on a resize handle of selected element
    if (selectedElement) {
      var handle = getResizeHandle(x, y, selectedElement);
      if (handle >= 0) {
        pushUndoState();
        isResizing = true;
        resizeHandle = handle;
        resizeStart = { 
          x: x, 
          y: y, 
          width: selectedElement.width || 100, 
          height: selectedElement.height || 30,
          elemX: selectedElement.x,
          elemY: selectedElement.y
        };
        e.preventDefault();
        return;
      }
    }
    
    // Check if clicking on an element
    var clickedElement = null;
    for (var i = elements.length - 1; i >= 0; i--) {
      if (hitTest(x, y, elements[i])) {
        clickedElement = elements[i];
        break;
      }
    }
    
    if (clickedElement) {
      pushUndoState();
      selectedElement = clickedElement;
      isDragging = true;
      dragStart = { x: x, y: y };
      elementStart = { x: clickedElement.x, y: clickedElement.y };
      canvas.style.cursor = 'move';
      notifyElementSelected(selectedElement);
    } else {
      selectedElement = null;
      notifyElementDeselected();
    }
    
    draw();
  });
  
  canvas.addEventListener('mousemove', function(e) {
    var rect = canvas.getBoundingClientRect();
    var x = e.clientX - rect.left;
    var y = e.clientY - rect.top;
    
    if (isResizing && selectedElement) {
      // Calculate delta in base coordinates
      var dx = (x - resizeStart.x) / zoomFactor;
      var dy = (y - resizeStart.y) / zoomFactor;
      
      var newWidth = resizeStart.width;
      var newHeight = resizeStart.height;
      var newX = resizeStart.elemX;
      var newY = resizeStart.elemY;
      
      // Handle indices: 0=TL, 1=TC, 2=TR, 3=ML, 4=MR, 5=BL, 6=BC, 7=BR
      switch(resizeHandle) {
        case 0: // Top-left
          newWidth = Math.max(20, resizeStart.width - dx);
          newHeight = Math.max(20, resizeStart.height - dy);
          newX = resizeStart.elemX + (resizeStart.width - newWidth);
          newY = resizeStart.elemY + (resizeStart.height - newHeight);
          break;
        case 1: // Top-center
          newHeight = Math.max(20, resizeStart.height - dy);
          newY = resizeStart.elemY + (resizeStart.height - newHeight);
          break;
        case 2: // Top-right
          newWidth = Math.max(20, resizeStart.width + dx);
          newHeight = Math.max(20, resizeStart.height - dy);
          newY = resizeStart.elemY + (resizeStart.height - newHeight);
          break;
        case 3: // Middle-left
          newWidth = Math.max(20, resizeStart.width - dx);
          newX = resizeStart.elemX + (resizeStart.width - newWidth);
          break;
        case 4: // Middle-right
          newWidth = Math.max(20, resizeStart.width + dx);
          break;
        case 5: // Bottom-left
          newWidth = Math.max(20, resizeStart.width - dx);
          newHeight = Math.max(20, resizeStart.height + dy);
          newX = resizeStart.elemX + (resizeStart.width - newWidth);
          break;
        case 6: // Bottom-center
          newHeight = Math.max(20, resizeStart.height + dy);
          break;
        case 7: // Bottom-right
          newWidth = Math.max(20, resizeStart.width + dx);
          newHeight = Math.max(20, resizeStart.height + dy);
          break;
      }
      
      selectedElement.width = snapToGrid(newWidth);
      selectedElement.height = snapToGrid(newHeight);
      selectedElement.x = snapToGrid(newX);
      selectedElement.y = snapToGrid(newY);
      
      draw();
      notifyElementSelected(selectedElement);
    } else if (isDragging && selectedElement) {
      // Adjust mouse movement by zoom factor to get stored coordinates
      var dx = (x - dragStart.x) / zoomFactor;
      var dy = (y - dragStart.y) / zoomFactor;
      
      var newX = elementStart.x + dx;
      var newY = elementStart.y + dy;
      
      // Constrain to page (using base coordinates, not zoomed)
      newX = Math.max(0, Math.min(newX, basePageWidth - (selectedElement.width || 100)));
      newY = Math.max(0, Math.min(newY, basePageHeight - (selectedElement.height || 30)));
      
      // Snap to grid
      selectedElement.x = snapToGrid(newX);
      selectedElement.y = snapToGrid(newY);
      
      draw();
      notifyElementSelected(selectedElement);
    } else {
      // Update cursor based on resize handles or element hover
      if (selectedElement && !selectedElement.isStatic) {
        var handle = getResizeHandle(x, y, selectedElement);
        if (handle >= 0) {
          // Set cursor based on handle type
          var cursors = ['nwse-resize', 'ns-resize', 'nesw-resize', 'ew-resize', 'ew-resize', 'nesw-resize', 'ns-resize', 'nwse-resize'];
          canvas.style.cursor = cursors[handle];
        } else {
          var hovering = false;
          for (var i = elements.length - 1; i >= 0; i--) {
            if (hitTest(x, y, elements[i])) {
              hovering = true;
              break;
            }
          }
          canvas.style.cursor = hovering ? 'move' : 'default';
        }
      } else {
        var hovering = false;
        for (var i = elements.length - 1; i >= 0; i--) {
          if (hitTest(x, y, elements[i])) {
            hovering = true;
            break;
          }
        }
        canvas.style.cursor = hovering ? 'move' : 'default';
      }
    }
  });
  
  canvas.addEventListener('mouseup', function() {
    isDragging = false;
    isResizing = false;
    resizeHandle = -1;
    canvas.style.cursor = 'default';
  });
  
  canvas.addEventListener('mouseleave', function() {
    isDragging = false;
    isResizing = false;
    resizeHandle = -1;
    canvas.style.cursor = 'default';
  });
  
  // Keyboard navigation
  canvas.setAttribute('tabindex', '0');
  canvas.addEventListener('keydown', function(e) {
    // Undo with Ctrl+Z / Cmd+Z (works without a selected element)
    if ((e.ctrlKey || e.metaKey) && (e.key === 'z' || e.key === 'Z')) {
      window.undoProfileCanvas();
      e.preventDefault();
      return;
    }

    if (!selectedElement) return;

    if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Delete'].indexOf(e.key) > -1) {
      pushUndoState();
    }

    var moved = false;

    switch(e.key) {
      case 'ArrowUp':
        if (e.shiftKey) {
          selectedElement.y = Math.max(0, selectedElement.y - 1);
        } else {
          selectedElement.y = Math.max(0, Math.floor((selectedElement.y - 1) / gridSize) * gridSize);
        }
        moved = true;
        e.preventDefault();
        break;
      case 'ArrowDown':
        if (e.shiftKey) {
          selectedElement.y = Math.min(basePageHeight - (selectedElement.height || 30), selectedElement.y + 1);
        } else {
          selectedElement.y = Math.min(basePageHeight - (selectedElement.height || 30), Math.ceil((selectedElement.y + 1) / gridSize) * gridSize);
        }
        moved = true;
        e.preventDefault();
        break;
      case 'ArrowLeft':
        if (e.shiftKey) {
          selectedElement.x = Math.max(0, selectedElement.x - 1);
        } else {
          selectedElement.x = Math.max(0, Math.floor((selectedElement.x - 1) / gridSize) * gridSize);
        }
        moved = true;
        e.preventDefault();
        break;
      case 'ArrowRight':
        if (e.shiftKey) {
          selectedElement.x = Math.min(basePageWidth - (selectedElement.width || 100), selectedElement.x + 1);
        } else {
          selectedElement.x = Math.min(basePageWidth - (selectedElement.width || 100), Math.ceil((selectedElement.x + 1) / gridSize) * gridSize);
        }
        moved = true;
        e.preventDefault();
        break;
      case 'Delete':
        var index = elements.indexOf(selectedElement);
        if (index > -1) {
          elements.splice(index, 1);
          selectedElement = null;
          notifyElementDeselected();
          draw();
        }
        e.preventDefault();
        break;
    }

    if (moved) {
      draw();
      notifyElementSelected(selectedElement);
    }
  });
  
  // Add element function
  window.addProfileElement = function(type, label, dropX, dropY, isStatic, staticText, variable, isCustomer) {
    pushUndoState();
    elementCounter++;
    var id = 'element-' + elementCounter;
    
    // Convert to page coordinates (adjusting for zoom factor)
    var x = (dropX - pageX - 50 * zoomFactor) / zoomFactor;
    var y = (dropY - pageY - 15 * zoomFactor) / zoomFactor;
    x = Math.max(10, x);
    y = Math.max(10, y);
    x = snapToGrid(x);
    y = snapToGrid(y);
    
    var el = {
      id: id,
      type: type,
      x: x,
      y: y,
      width: 150,
      height: 30,
      fontSize: 14,
      color: '#333333',
      isStatic: isStatic || false,
      variable: variable || null,
      isCustomer: isCustomer || false
    };
    
    // Helper function to calculate height based on font size and lines
    function calculateHeight(fontSize, lineCount) {
      var lineHeight = fontSize * 1.2;
      return Math.round(lineCount * lineHeight + 6);
    }
    
    // Handle static elements (user data or customer data)
    if (isStatic && staticText) {
      el.text = staticText;
      el.color = '#000000'; // Black text for static elements
      el.fontStyle = 'bold';
      // For services.list, set larger dimensions for the table with summary section
      if (variable === 'services.list') {
        el.width = 450;
        var lineHeight = el.fontSize * 1.4;
        var padding = 4;
        var rowHeight = lineHeight + padding * 2;
        var tableHeight = rowHeight + 3 * rowHeight; // Header + 3 sample rows
        var summaryRowHeight = el.fontSize * 1.6;
        var summaryGap = el.fontSize * 0.5;
        var summaryHeight = summaryGap + (summaryRowHeight * 3) + summaryGap + summaryRowHeight + summaryGap;
        var totalHeight = tableHeight + summaryHeight;
        el.height = Math.round(totalHeight);
      } else {
        el.height = calculateHeight(el.fontSize, 1);
      }
    } else {
      switch (type) {
        case 'text':
          el.text = 'Text eingeben...';
          el.height = calculateHeight(el.fontSize, 1);
          break;
        case 'header':
          el.text = 'Überschrift';
          el.fontSize = 24;
          el.fontStyle = 'bold';
          el.color = '#000000';
          el.width = 200;
          el.height = calculateHeight(el.fontSize, 1);
          break;
        case 'date':
          el.text = 'Datum: ' + new Date().toLocaleDateString('de-DE');
          el.fontSize = 12;
          el.color = '#666666';
          el.height = calculateHeight(el.fontSize, 1);
          break;
        case 'customer':
          el.text = 'Kundenname\nStraße Nr.\nPLZ Ort';
          el.fontSize = 12;
          el.height = calculateHeight(el.fontSize, 3);
          break;
        case 'company':
          el.text = 'Ihr Unternehmen\nIhre Straße\nIhre PLZ Ort';
          el.fontSize = 12;
          el.height = calculateHeight(el.fontSize, 3);
          break;
        case 'amount':
          el.text = 'Gesamtbetrag: 0,00 €';
          el.fontStyle = 'bold';
          el.width = 180;
          el.height = calculateHeight(el.fontSize, 1);
          break;
        case 'line':
          el.text = '';
          el.width = 200;
          el.height = 2;
          break;
        case 'image':
          el.text = 'Bild';
          el.width = 100;
          el.height = 100;
          break;
        default:
          el.text = label || 'Neues Element';
          el.height = calculateHeight(el.fontSize, 1);
      }
    }
    
    elements.push(el);
    selectedElement = el;
    draw();
    notifyElementSelected(el);
    
    // Focus canvas for keyboard navigation
    canvas.focus();
  };
  
  // Update element functions
  window.updateProfileElementText = function(id, text) {
    var el = elements.find(function(e) { return e.id === id; });
    if (el) {
      pushUndoState();
      el.text = text;
      draw();
    }
  };

  window.updateProfileElementPosition = function(id, x, y) {
    var el = elements.find(function(e) { return e.id === id; });
    if (el) {
      pushUndoState();
      if (x !== null) el.x = snapToGrid(x);
      if (y !== null) el.y = snapToGrid(y);
      draw();
    }
  };

  window.updateProfileElementFontSize = function(id, size) {
    var el = elements.find(function(e) { return e.id === id; });
    if (el) {
      pushUndoState();
      el.fontSize = size;
      // Update height based on text content and new font size
      if (el.type !== 'line' && el.type !== 'image') {
        var lines = (el.text || '').split('\n');
        var lineHeight = size * 1.2;
        var textHeight = lines.length * lineHeight;
        el.height = Math.max(textHeight + 6, 20); // Minimum height of 20
      }
      draw();
    }
  };
  
  window.updateProfileElementColor = function(id, color) {
    var el = elements.find(function(e) { return e.id === id; });
    if (el) {
      pushUndoState();
      el.color = color;
      draw();
    }
  };

  window.updateProfileElementSize = function(id, width, height) {
    var el = elements.find(function(e) { return e.id === id; });
    if (el) {
      pushUndoState();
      if (width !== null) el.width = width;
      if (height !== null) el.height = height;
      draw();
    }
  };
  
  window.updateProfileElementImage = function(id, imageData) {
    var el = elements.find(function(e) { return e.id === id; });
    if (!el) return;
    
    // Load image to get dimensions
    var img = new Image();
    img.onload = function() {
      pushUndoState();
      var MAX_WIDTH = 1090;
      var width = img.width;
      var height = img.height;
      
      // Only resize if image is larger than MAX_WIDTH
      if (width > MAX_WIDTH) {
        height = Math.round(height * (MAX_WIDTH / width));
        width = MAX_WIDTH;
        
        // Create canvas to resize image
        var canvas = document.createElement('canvas');
        canvas.width = width;
        canvas.height = height;
        var ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0, width, height);
        
        // Get resized image data (maintain original format if possible)
        var resizedDataUrl = canvas.toDataURL('image/jpeg', 0.9);
        el.imageData = resizedDataUrl;
      } else {
        el.imageData = imageData;
      }
      
      el.text = 'Bild';
      draw();
    };
    img.src = imageData;
  };
  
  window.deleteProfileElement = function(id) {
    var index = elements.findIndex(function(e) { return e.id === id; });
    if (index > -1) {
      pushUndoState();
      elements.splice(index, 1);
      if (selectedElement && selectedElement.id === id) {
        selectedElement = null;
        notifyElementDeselected();
      }
      draw();
    }
  };
  
  // Save state to global before functions are defined
  function saveState() {
    window.profileInvoiceState.elements = elements;
    window.profileInvoiceState.selectedElement = selectedElement;
    window.profileInvoiceState.elementCounter = elementCounter;
  }
  
  // Clear canvas function
  window.clearProfileCanvas = function() {
    if (elements.length) {
      pushUndoState();
    }
    // Keep the same array reference (shared with profileInvoiceState and undo)
    elements.length = 0;
    selectedElement = null;
    saveState();
    notifyElementDeselected();
    draw();
  };
  
  // Get canvas data
  // Helper functions for percentage conversion
  function toPercentX(value) {
    return (value / basePageWidth * 100).toFixed(2);
  }
  function toPercentY(value) {
    return (value / basePageHeight * 100).toFixed(2);
  }
  function fromPercentX(percent) {
    return Math.round(parseFloat(percent) / 100 * basePageWidth);
  }
  function fromPercentY(percent) {
    return Math.round(parseFloat(percent) / 100 * basePageHeight);
  }
  
  window.getProfileCanvasData = function() {
    saveState();
    // Convert pixel values to percentages for storage
    var elementsWithPercent = elements.map(function(el) {
      // For static elements with variables, handle text storage differently:
      // - masterdata variables: text is resolved from user data, don't store
      // - customer variables: store the placeholder text from canvas
      var textToStore = el.text;
      if (el.isStatic && el.variable) {
        if (el.variable.startsWith('masterdata.')) {
          // Don't store the text for masterdata variables - will be resolved from user data
          textToStore = null;
        }
        // For customer variables, keep the text (placeholder) as is
      }
      
      return {
        id: el.id,
        type: el.type,
        text: textToStore,
        xPercent: toPercentX(el.x),
        yPercent: toPercentY(el.y),
        widthPercent: toPercentX(el.width),
        heightPercent: toPercentY(el.height),
        fontSize: el.fontSize,
        fontStyle: el.fontStyle,
        textAlign: el.textAlign,
        color: el.color,
        isStatic: el.isStatic,
        isCustomer: el.isCustomer,
        variable: el.variable,
        imageData: el.imageData
      };
    });
    return {
      elements: elementsWithPercent
    };
  };
  
  window.updateProfileVatRate = function(rate) {
    if (rate == null || isNaN(rate)) return;
    window.profileInvoiceVatRate = rate;
    draw();
  };

  window.updateProfileMasterdataValue = function(key, value) {
    if (!window.masterdataValues) window.masterdataValues = {};
    window.masterdataValues[key] = value;
    elements.forEach(function(el) {
      if (el.variable === key) {
        el.text = value;
      }
    });
    draw();
  };

  draw();
  window.profileInvoiceState.initialized = true;
  console.log('Profile canvas initialized with ' + elements.length + ' elements');
  
  // Handle window resize
  window.addEventListener('resize', function() {
    var newRect = container.getBoundingClientRect();
    if (newRect.width > 0 && newRect.height > 0) {
      canvas.width = newRect.width;
      canvas.height = newRect.height;
      draw();
    }
  });
  
  // Setup drop zone
  if (!container._dropSetup) {
    container._dropSetup = true;
    
    container.addEventListener('dragover', function(e) {
      e.preventDefault();
      e.dataTransfer.dropEffect = 'copy';
      container.style.borderColor = 'var(--lumo-primary-color)';
    });
    
    container.addEventListener('dragleave', function(e) {
      container.style.borderColor = 'var(--lumo-contrast-20pct)';
    });
    
    container.addEventListener('drop', function(e) {
      e.preventDefault();
      container.style.borderColor = 'var(--lumo-contrast-20pct)';
      
      var templateType = e.dataTransfer.getData('template-type');
      var templateLabel = e.dataTransfer.getData('template-label');
      var isStatic = e.dataTransfer.getData('is-static') === 'true';
      var staticText = e.dataTransfer.getData('static-text');
      var variable = e.dataTransfer.getData('variable');
      var isCustomer = e.dataTransfer.getData('is-customer') === 'true';
      
      if (templateType && window.addProfileElement) {
        var rect = container.getBoundingClientRect();
        var x = e.clientX - rect.left;
        var y = e.clientY - rect.top;
        window.addProfileElement(templateType, templateLabel, x, y, isStatic, staticText, variable, isCustomer);
      }
    });
  }
  
  // Load template function - defined INSIDE initProfileInvoiceGenerator to access closure variables
  window.loadProfileTemplate = function(templateData) {
    try {
      console.log('loadProfileTemplate called with data:', JSON.stringify(templateData).substring(0, 200));
      var data = (typeof templateData === 'string') ? JSON.parse(templateData) : templateData;
      if (data.elements && Array.isArray(data.elements)) {
        console.log('Loading ' + data.elements.length + ' elements');
        console.log('Current elements array before clear:', elements.length);
        // Clear existing elements - use length = 0 to keep the same array reference
        elements.length = 0;
        selectedElement = null;
        console.log('Elements array after clear:', elements.length);
        
        // Master data mapping - these should be filled from user data
        var masterdata = window.masterdataValues || {};
        
        // Load new elements
        data.elements.forEach(function(el) {
          console.log('Loading element:', el.id, 'type:', el.type, 'variable:', el.variable);
          // Ensure element has an ID
          if (!el.id) {
            elementCounter++;
            el.id = 'element-' + elementCounter;
          }
          
          // Convert percentages to pixels if they exist, otherwise use legacy pixel values
          if (el.xPercent !== undefined) {
            el.x = fromPercentX(el.xPercent);
          }
          if (el.yPercent !== undefined) {
            el.y = fromPercentY(el.yPercent);
          }
          if (el.widthPercent !== undefined) {
            el.width = fromPercentX(el.widthPercent);
          }
          if (el.heightPercent !== undefined) {
            el.height = fromPercentY(el.heightPercent);
          }
          
          // Handle elements with variables
          if (el.variable) {
            el.isStatic = true;
            if (el.variable.startsWith('customer.')) {
              el.isCustomer = true;
              // Customer variables - use saved text if available, otherwise use placeholder
              if (!el.text || el.text.trim() === '') {
                el.text = '[' + el.variable.replace('customer.', '') + ']';
              }
              // If text is already set (from saved template), keep it
            } else if (el.variable.startsWith('masterdata.')) {
              // Masterdata variables - use actual value from masterdata or placeholder
              var value = masterdata[el.variable];
              if (value && value.trim() !== '') {
                el.text = value;
              } else {
                el.text = '[' + el.variable.replace('masterdata.', '') + ']';
              }
            }
          }
          // Legacy: If text contains a variable placeholder {{variable}}|Display Text, extract it
          else if (el.text && el.text.startsWith('{{')) {
            var pipeIndex = el.text.indexOf('|');
            if (pipeIndex > -1) {
              // Format: {{variable}}|Display Text
              var placeholderPart = el.text.substring(0, pipeIndex);
              var displayText = el.text.substring(pipeIndex + 1);
              if (placeholderPart.startsWith('{{') && placeholderPart.endsWith('}}')) {
                var varName = placeholderPart.substring(2, placeholderPart.length - 2);
                el.variable = varName;
                if (varName.startsWith('masterdata.')) {
                  el.isStatic = true;
                  // Use masterdata value or fallback to display text
                  var value = masterdata[varName];
                  el.text = (value && value.trim() !== '') ? value : displayText;
                } else if (varName.startsWith('customer.')) {
                  el.isStatic = true;
                  el.isCustomer = true;
                  // Use saved text if available, otherwise use placeholder
                  if (!el.text || el.text.trim() === '' || el.text.startsWith('{{')) {
                    el.text = '[' + varName.replace('customer.', '') + ']';
                  }
                }
              }
            } else if (el.text.endsWith('}}')) {
              // Legacy format: {{variable}} without display text
              var varName = el.text.substring(2, el.text.length - 2);
              el.variable = varName;
              if (varName.startsWith('masterdata.')) {
                el.isStatic = true;
                var value = masterdata[varName];
                el.text = (value && value.trim() !== '') ? value : '[' + varName.replace('masterdata.', '') + ']';
              } else if (varName.startsWith('customer.')) {
                el.isStatic = true;
                el.isCustomer = true;
                el.text = '[' + varName.replace('customer.', '') + ']';
              }
            }
          }
          
          console.log('Element processed:', el.id, 'x:', el.x, 'y:', el.y, 'text:', el.text);
          elements.push(el);
          console.log('Element pushed, elements count now:', elements.length);
        });
        
        // Update counter to be higher than any loaded element
        elements.forEach(function(el) {
          if (el.id && el.id.startsWith('element-')) {
            var num = parseInt(el.id.replace('element-', ''));
            if (!isNaN(num) && num > elementCounter) {
              elementCounter = num;
            }
          }
        });
        
        // Save to global state
        saveState();
        
        console.log('Calling draw(), elements count:', elements.length);
        console.log('Canvas dimensions:', canvas.width, 'x', canvas.height);
        draw();
        console.log('draw() completed');
        notifyElementDeselected();
        console.log('Template loaded with ' + elements.length + ' elements');
      } else {
        console.log('No elements array found in template data');
      }
    } catch (e) {
      console.error('Error loading template:', e);
    }
  };
};
