window.timelineEngine = {
  config: null,
  template: null,
  csvOverride: false,
  cssOverride: false,
  csvData: null,  // Store current CSV text
  cssData: null,  // Store current CSS text

  projectBasePath: '',

  showTemplatePreview() {
    if (!this.template) return;

    console.log("Showing template preview");

    // Detect template theme for appropriate colors
    const isEnhanced = this.template.includes('Enhanced');
    const isBlueTheme = this.template.includes('My Project');
    const isGreenTheme = this.template.includes('Example');

    // Color scheme selection
    let primaryColor = '#0A4D8C';  // default
    let secondaryColor = '#5C6B7A'; // default

    if (isEnhanced) {
      if (isBlueTheme) {
        primaryColor = '#3b82f6';
        secondaryColor = '#60a5fa';
      } else if (isGreenTheme) {
        primaryColor = '#2d8659';
        secondaryColor = '#4a9b6b';
      }
    }

    // Create sample month graphics matching the template style
    const sampleMonths = isEnhanced ? `
      <line x1="240" y1="75" x2="240" y2="300" stroke="${secondaryColor}" stroke-width="2" opacity="0.6" />
      <rect x="210" y="70" width="60" height="25" fill="${primaryColor}" opacity="0.1" rx="4" />
      <text x="244" y="90" fill="${primaryColor}" font-size="13" font-weight="600">Jan 25</text>

      <line x1="360" y1="75" x2="360" y2="300" stroke="${secondaryColor}" stroke-width="2" opacity="0.6" />
      <rect x="330" y="70" width="60" height="25" fill="${primaryColor}" opacity="0.1" rx="4" />
      <text x="364" y="90" fill="${primaryColor}" font-size="13" font-weight="600">Feb 25</text>

      <line x1="480" y1="75" x2="480" y2="300" stroke="${secondaryColor}" stroke-width="2" opacity="0.6" />
      <rect x="450" y="70" width="60" height="25" fill="${primaryColor}" opacity="0.1" rx="4" />
      <text x="484" y="90" fill="${primaryColor}" font-size="13" font-weight="600">Mar 25</text>

      <line x1="600" y1="75" x2="600" y2="300" stroke="${secondaryColor}" stroke-width="2" opacity="0.6" />
      <rect x="570" y="70" width="60" height="25" fill="${primaryColor}" opacity="0.1" rx="4" />
      <text x="604" y="90" fill="${primaryColor}" font-size="13" font-weight="600">Apr 25</text>
    ` : `
      <line x1="240" y1="75" x2="240" y2="300" stroke="#E3E8EF" />
      <text x="244" y="90" fill="#5C6B7A" font-size="12">Jan 25</text>
      <line x1="360" y1="75" x2="360" y2="300" stroke="#E3E8EF" />
      <text x="364" y="90" fill="#5C6B7A" font-size="12">Feb 25</text>
      <line x1="480" y1="75" x2="480" y2="300" stroke="#E3E8EF" />
      <text x="484" y="90" fill="#5C6B7A" font-size="12">Mar 25</text>
      <line x1="600" y1="75" x2="600" y2="300" stroke="#E3E8EF" />
      <text x="604" y="90" fill="#5C6B7A" font-size="12">Apr 25</text>
    `;

    // Create sample lane content matching the template style
    const sampleLanes = isEnhanced ? `
      <rect x="40" y="116" width="640" height="80" fill="rgba(255,255,255,0.7)" stroke="${secondaryColor}" stroke-width="1" opacity="0.5" rx="8" />
      <text x="56" y="136" fill="${primaryColor}" font-size="14" font-weight="700">Example Epic</text>
      <circle cx="270" cy="156" r="6" fill="${primaryColor}" stroke="${secondaryColor}" stroke-width="2" />
      <text x="282" y="160" font-size="12" fill="${primaryColor}" font-weight="500">
        <tspan class="item-id">EX-1: </tspan>
        <tspan class="item-title" fill="${primaryColor === '#3b82f6' ? '#1e40af' : '#1e5a3d'}">Sample Task Preview</tspan>
      </text>

      <rect x="40" y="212" width="640" height="80" fill="rgba(255,255,255,0.7)" stroke="${secondaryColor}" stroke-width="1" opacity="0.5" rx="8" />
      <text x="56" y="232" fill="${primaryColor}" font-size="14" font-weight="700">Another Epic</text>
      <circle cx="390" cy="252" r="6" fill="${primaryColor}" stroke="${secondaryColor}" stroke-width="2" />
      <text x="402" y="256" font-size="12" fill="${primaryColor}" font-weight="500">
        <tspan class="item-id">EX-2: </tspan>
        <tspan class="item-title" fill="${primaryColor === '#3b82f6' ? '#1e40af' : '#1e5a3d'}">Template Preview</tspan>
      </text>
    ` : `
      <rect x="40" y="116" width="640" height="80" fill="#FFFFFF" stroke="#E3E8EF" rx="10" />
      <text x="56" y="136" fill="#0B1F3B" font-size="14" font-weight="600">Example Epic</text>
      <circle cx="270" cy="156" r="5" fill="#0A4D8C" />
      <text x="282" y="160" font-size="12" fill="#0B1F3B">
        <tspan class="item-id">EX-1: </tspan>
        <tspan class="item-title">Sample Task Preview</tspan>
      </text>

      <rect x="40" y="212" width="640" height="80" fill="#FFFFFF" stroke="#E3E8EF" rx="10" />
      <text x="56" y="232" fill="#0B1F3B" font-size="14" font-weight="600">Another Epic</text>
      <circle cx="390" cy="252" r="5" fill="#0A4D8C" />
      <text x="402" y="256" font-size="12" fill="#0B1F3B">
        <tspan class="item-id">EX-2: </tspan>
        <tspan class="item-title">Template Preview</tspan>
      </text>
    `;

    // Replace placeholders with sample data
    let previewSvg = this.template
      .replace("{{MONTHS}}", sampleMonths)
      .replace("{{LANES}}", sampleLanes);

    // Add dimensions for proper preview display (using reasonable default size)
    const previewWidth = 720;
    const previewHeight = 360;
    previewSvg = previewSvg.replace(
      /<svg([^>]*?)>/,
      `<svg$1 width="${previewWidth}" height="${previewHeight}" viewBox="0 0 ${previewWidth} ${previewHeight}">`
    );

    document.getElementById("viewer").innerHTML = previewSvg;

    // Initialize zoom functionality for the preview
    if (window.svgViewer) {
      window.svgViewer.resetZoom();
      window.svgViewer.updateZoomControls();
    }

    console.log("Template preview displayed with theme:", { isEnhanced, isBlueTheme, isGreenTheme });
  },

  updateFileStatus(fileType, filename, status = 'loaded') {
    const statusElement = document.getElementById(`${fileType}File`);

    if (statusElement) {
      if (filename && status === 'loaded') {
        statusElement.textContent = filename;
        statusElement.style.color = '#28a745';
        statusElement.title = `Loaded: ${filename}`;
      } else if (filename && status === 'error') {
        statusElement.textContent = `Error: ${filename}`;
        statusElement.style.color = '#dc3545';
        statusElement.title = `Failed to load: ${filename}`;
      } else {
        statusElement.textContent = 'Not loaded';
        statusElement.style.color = '#6c757d';
        statusElement.title = 'No file loaded';
      }
    }

    // Add visual feedback with brief highlight animation
    if (statusElement && filename) {
      statusElement.style.transform = 'scale(1.05)';
      setTimeout(() => {
        statusElement.style.transform = 'scale(1)';
      }, 200);
    }
  },

  resolveProjectPath(relativePath) {
    if (!relativePath) return relativePath;
    // If path is already absolute (starts with http/https) or has no base path, return as-is
    if (relativePath.startsWith('http') || !this.projectBasePath) {
      return relativePath;
    }
    const resolvedPath = this.projectBasePath + relativePath;
    console.log("Resolved path:", relativePath, "->", resolvedPath);
    return resolvedPath;
  },

  async autoLoadDefaultProject() {
    console.log("Starting autoLoadDefaultProject");
    // Try projects in order: binect, my-project, example
    const candidates = [
      { path: "binect/project.json", basePath: "binect/" },
      { path: "my-project/project.json", basePath: "my-project/" },
      { path: "example/project.json", basePath: "example/" }
    ];
    for (const candidate of candidates) {
      try {
        const res = await fetch(candidate.path);
        if (!res.ok) continue;
        const cfg = await res.json();
        this.projectBasePath = candidate.basePath;
        await this.loadProjectConfigObject(cfg);
        console.log("Project loaded successfully from:", candidate.path);
        return;
      } catch (e) {
        continue;
      }
    }
    console.log("No project could be auto-loaded");
  },

  async loadProjectConfigObject(cfg) {
    this.config = cfg;
    const name = cfg.name || "Timeline";
    document.getElementById("projectName").textContent = name;
    document.getElementById("projectSubtitle").textContent =
      cfg.description || "Projektkonfiguration geladen.";

    // Update project status
    this.updateFileStatus('project', name, 'loaded');

    // Enable project edit button
    if (window.fileEditor) {
      window.fileEditor.enableEditButton('project');
    }

    // Show field mappings in debug panel
    this.showFieldMappings();

    // Track loading errors for user feedback
    const loadingErrors = [];

    // Stylesheet
    if (cfg.stylesheet && !this.cssOverride) {
      const stylesheetPath = this.resolveProjectPath(cfg.stylesheet);

      // Load CSS via fetch to store content for editing
      try {
        const cssResponse = await fetch(stylesheetPath);
        if (cssResponse.ok) {
          const cssText = await cssResponse.text();
          this.cssData = cssText;  // Store for editing

          // Apply CSS
          const blob = new Blob([cssText], { type: "text/css" });
          const linkElement = document.getElementById("dynamicCss");
          linkElement.href = URL.createObjectURL(blob);

          this.updateFileStatus('css', cfg.stylesheet + ' ✨', 'loaded');

          // Enable CSS edit button
          if (window.fileEditor) {
            window.fileEditor.enableEditButton('css');
          }

          console.log("Stylesheet loaded successfully:", stylesheetPath);
        } else {
          throw new Error(`HTTP ${cssResponse.status}`);
        }
      } catch (e) {
        console.error("Stylesheet could not be loaded:", e);
        this.updateFileStatus('css', cfg.stylesheet, 'error');
        loadingErrors.push(`Stylesheet: ${cfg.stylesheet}`);
      }
    }

    // SVG template
    if (cfg.svgTemplate) {
      try {
        const templatePath = this.resolveProjectPath(cfg.svgTemplate);
        console.log("Attempting to fetch SVG template from:", templatePath);
        const svgResponse = await fetch(templatePath);
        console.log("SVG template fetch response:", svgResponse.status, svgResponse.statusText);

        if (!svgResponse.ok) {
          throw new Error(`HTTP ${svgResponse.status}: ${svgResponse.statusText}`);
        }

        this.template = await svgResponse.text();
        console.log("SVG template loaded, length:", this.template.length);
        this.updateFileStatus('svg', cfg.svgTemplate, 'loaded');

        // Enable SVG edit button
        if (window.fileEditor) {
          window.fileEditor.enableEditButton('svg');
        }

        // Show template fields in debug panel
        this.showTemplateFields();

        // Show template preview if no CSV data is loaded yet
        if (!this.csvOverride && document.querySelector("#viewer").innerHTML.includes("Keine Timeline verfügbar")) {
          this.showTemplatePreview();
        }
      } catch (e) {
        console.error("SVG template could not be loaded:", e);
        console.error("Failed SVG template path was:", this.resolveProjectPath(cfg.svgTemplate));
        this.updateFileStatus('svg', cfg.svgTemplate, 'error');
        loadingErrors.push(`SVG template: ${cfg.svgTemplate}`);
      }
    }

    // CSV data
    if (cfg.dataSource && !this.csvOverride) {
      try {
        const csvPath = this.resolveProjectPath(cfg.dataSource);
        console.log("Attempting to fetch CSV from:", csvPath);
        const csvResponse = await fetch(csvPath);
        console.log("CSV fetch response:", csvResponse.status, csvResponse.statusText);

        if (!csvResponse.ok) {
          throw new Error(`HTTP ${csvResponse.status}: ${csvResponse.statusText}`);
        }

        const csvText = await csvResponse.text();
        console.log("CSV text loaded, length:", csvText.length);
        console.log("CSV preview:", csvText.substring(0, 200));

        this.updateFileStatus('csv', cfg.dataSource, 'loaded');

        // Enable CSV edit button
        if (window.fileEditor) {
          window.fileEditor.enableEditButton('csv');
        }

        this.processCsv(csvText);
      } catch (e) {
        console.error("CSV could not be loaded:", e);
        console.error("Failed CSV path was:", this.resolveProjectPath(cfg.dataSource));
        this.updateFileStatus('csv', cfg.dataSource, 'error');
        loadingErrors.push(`CSV data: ${cfg.dataSource}`);
      }
    }

    // Show user feedback if there were loading errors
    if (loadingErrors.length > 0) {
      setTimeout(() => {
        const viewer = document.getElementById("viewer");
        if (viewer && !viewer.innerHTML.includes('<svg')) {
          viewer.innerHTML = `
            <div style="text-align:center; padding:40px 20px; color:#6c757d;">
              <div style="font-size:48px; margin-bottom:16px;">⚠️</div>
              <h4 style="margin:0 0 8px 0; color:#dc3545;">Projektdateien konnten nicht geladen werden</h4>
              <p style="margin:0 0 12px 0; font-size:14px;">
                <strong>Fehlgeschlagene Dateien:</strong><br>
                ${loadingErrors.map(err => `• ${err}`).join('<br>')}
              </p>
              <p style="margin:0; font-size:12px; color:#6c757d;">
                💡 <strong>Tipp:</strong> Lade die Dateien manuell mit den Load-Buttons oben oder
                verwende einen lokalen Server (<code>make serve</code>).
              </p>
            </div>
          `;
        }
      }, 500); // Small delay to let other operations complete
    }
  },

  processCsv(text) {
    console.log("processCsv called with text length:", text?.length);

    // Store CSV data for editing
    this.csvData = text;

    if (!this.config || !this.config.fieldMapping) {
      console.error("No config or fieldMapping found.");
      return;
    }

    if (typeof Papa === 'undefined') {
      console.error("Papa Parse library not available");
      document.getElementById("viewer").innerHTML =
        "<em style='color:#dc3545;'>Fehler: CSV Parser nicht verfügbar.</em>";
      return;
    }

    const m = this.config.fieldMapping;

    const self = this; // Capture 'this' context
    Papa.parse(text, {
      header: true,
      skipEmptyLines: true,
      complete: (res) => {
        console.log("Papa.parse complete, found", res.data.length, "rows");
        const rows = res.data;

        // Show CSV preview in debug panel
        self.showCSVPreview(text, rows);

        const items = rows.map((r) => {
          const dueField = (m.due || []).find(f => r[f]);
          const item = {
            id: m.id ? r[m.id] : (r["ID"] || ""),
            title: m.title ? r[m.title] : (r["Title"] || ""),
            lane: m.lane ? (r[m.lane] || "Ohne Epic") : (r["Lane"] || "Default"),
            due: self.parseDate(dueField ? r[dueField] : null)
          };
          return item;
        }).filter(i => i.title && i.due);

        console.log("Filtered to", items.length, "valid items");

        if (!items.length) {
          document.getElementById("viewer").innerHTML =
            "<em style='color:#999;'>Keine gültigen Items gefunden.</em>";
          return;
        }

        // Ensure generator is available
        if (!window.timelineGenerator) {
          console.error("Timeline generator not available");
          document.getElementById("viewer").innerHTML =
            "<em style='color:#dc3545;'>Fehler: Timeline Generator nicht verfügbar.</em>";
          return;
        }

        try {
          console.log("Generating timeline with:", items, self.config, self.template ? "template loaded" : "no template");
          const svg = window.timelineGenerator.generate(items, self.config, self.template);
          document.getElementById("viewer").innerHTML = svg;
          const dlBtn = document.getElementById("downloadSvg");
          dlBtn.disabled = false;
          dlBtn.style.opacity = 1;

          // Initialize zoom functionality for the new SVG
          if (window.svgViewer) {
            window.svgViewer.resetZoom();
            window.svgViewer.updateZoomControls();
          }

          console.log("Timeline generated successfully");
        } catch (error) {
          console.error("Error generating timeline:", error);
          document.getElementById("viewer").innerHTML =
            "<em style='color:#dc3545;'>Fehler beim Generieren der Timeline.</em>";
        }
      }
    });
  },

  parseDate(str) {
    if (!str) return null;
    str = String(str).trim();
    let d = null;

    // YYYY/MM/DD oder YYYY-MM-DD
    let m = str.match(/^(\d{4})[\/-](\d{1,2})[\/-](\d{1,2})$/);
    if (m) {
      const [_, yy, mm, dd] = m;
      d = new Date(Number(yy), Number(mm) - 1, Number(dd));
      return isNaN(d.getTime()) ? null : d;
    }

    // DD.MM.YYYY
    m = str.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})$/);
    if (m) {
      const [_, dd, mm, yy] = m;
      d = new Date(Number(yy), Number(mm) - 1, Number(dd));
      return isNaN(d.getTime()) ? null : d;
    }

    // Fallback
    d = new Date(str);
    return isNaN(d.getTime()) ? null : d;
  },

  // --------- Debug Display Functions ---------

  showFieldMappings() {
    if (!this.config || !this.config.fieldMapping) return;

    const debugInfo = document.getElementById("debugInfo");
    const fieldMappingInfo = document.getElementById("fieldMappingInfo");
    const fieldMappingDisplay = document.getElementById("fieldMappingDisplay");

    if (debugInfo && fieldMappingInfo && fieldMappingDisplay) {
      debugInfo.style.display = "block";
      fieldMappingInfo.style.display = "block";

      const mapping = this.config.fieldMapping;
      let display = "CSV Column → Timeline Field\n";
      display += "━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
      display += `ID:    ${JSON.stringify(mapping.id)}\n`;
      display += `Title: ${JSON.stringify(mapping.title)}\n`;
      display += `Lane:  ${JSON.stringify(mapping.lane)}\n`;
      display += `Due:   ${JSON.stringify(mapping.due)}\n`;
      if (mapping.epic) display += `Epic:  ${JSON.stringify(mapping.epic)}\n`;
      if (mapping.type) display += `Type:  ${JSON.stringify(mapping.type)}\n`;
      if (mapping.color) display += `Color: ${JSON.stringify(mapping.color)}\n`;

      fieldMappingDisplay.textContent = display;
    }
  },

  showTemplateFields() {
    if (!this.template) return;

    const debugInfo = document.getElementById("debugInfo");
    const templateFieldsInfo = document.getElementById("templateFieldsInfo");
    const templateFieldsDisplay = document.getElementById("templateFieldsDisplay");

    if (debugInfo && templateFieldsInfo && templateFieldsDisplay) {
      debugInfo.style.display = "block";
      templateFieldsInfo.style.display = "block";

      // Extract placeholders from template
      const placeholders = new Set();
      const placeholderRegex = /\{\{([A-Z_]+)\}\}/g;
      let match;
      while ((match = placeholderRegex.exec(this.template)) !== null) {
        placeholders.add(match[1]);
      }

      let display = "Required Template Placeholders:\n";
      display += "━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";

      // Group by category
      const monthFields = Array.from(placeholders).filter(p => p.includes('MONTH'));
      const laneFields = Array.from(placeholders).filter(p => p.includes('LANE'));
      const taskFields = Array.from(placeholders).filter(p => p.includes('TASK') || p.includes('TEXT'));
      const otherFields = Array.from(placeholders).filter(p =>
        !monthFields.includes(p) && !laneFields.includes(p) && !taskFields.includes(p)
      );

      if (monthFields.length > 0) {
        display += "\nMonth Fields:\n";
        monthFields.forEach(f => display += `  • ${f}\n`);
      }
      if (laneFields.length > 0) {
        display += "\nLane Fields:\n";
        laneFields.forEach(f => display += `  • ${f}\n`);
      }
      if (taskFields.length > 0) {
        display += "\nTask Fields:\n";
        taskFields.forEach(f => display += `  • ${f}\n`);
      }
      if (otherFields.length > 0) {
        display += "\nOther Fields:\n";
        otherFields.forEach(f => display += `  • ${f}\n`);
      }

      templateFieldsDisplay.textContent = display;
    }
  },

  showCSVPreview(csvText, parsedData) {
    const debugInfo = document.getElementById("debugInfo");
    const csvDataInfo = document.getElementById("csvDataInfo");
    const csvDataDisplay = document.getElementById("csvDataDisplay");

    if (debugInfo && csvDataInfo && csvDataDisplay) {
      debugInfo.style.display = "block";
      csvDataInfo.style.display = "block";

      const lines = csvText.trim().split('\n');
      const headers = lines[0] ? lines[0].split(',') : [];
      const firstDataLine = lines[1] ? lines[1].split(',') : [];

      let display = "CSV Structure Preview:\n";
      display += "━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
      display += `Headers: ${headers.join(', ')}\n\n`;

      if (firstDataLine.length > 0) {
        display += "First Data Row:\n";
        headers.forEach((header, i) => {
          display += `  ${header}: "${firstDataLine[i] || ''}"\n`;
        });
      }

      if (parsedData) {
        display += `\nParsed Rows: ${parsedData.length}\n`;
        const validCount = parsedData.filter(r => {
          const mapping = this.config?.fieldMapping || {};
          const titleField = mapping.title;
          const dueField = Array.isArray(mapping.due) ? mapping.due.find(f => r[f]) : mapping.due;
          return r[titleField] && r[dueField];
        }).length;
        display += `Valid Items: ${validCount}\n`;

        if (validCount === 0 && parsedData.length > 0) {
          display += "\n⚠️  WARNING: No valid items found!\n";
          display += "Check that:\n";
          display += "  • CSV headers match field mappings\n";
          display += "  • Title and Due fields have values\n";
          display += "  • Date format is parseable (e.g., YYYY-MM-DD)\n";
        }
      }

      csvDataDisplay.textContent = display;
    }
  }
};

// --------- SVG Viewer with Zoom functionality ---------

window.svgViewer = {
  currentZoom: 1,
  minZoom: 0.25,
  maxZoom: 3,
  zoomStep: 0.25,

  initializeZoom() {
    const viewer = document.getElementById("viewer");
    const zoomControls = document.getElementById("zoomControls");
    const zoomIn = document.getElementById("zoomIn");
    const zoomOut = document.getElementById("zoomOut");
    const zoomReset = document.getElementById("zoomReset");

    if (!viewer || !zoomControls || !zoomIn || !zoomOut || !zoomReset) {
      console.warn("Zoom controls not found in DOM");
      return;
    }

    // Show zoom controls when SVG is present
    this.updateZoomControls();

    // Zoom in
    zoomIn.addEventListener("click", () => {
      this.zoomIn();
    });

    // Zoom out
    zoomOut.addEventListener("click", () => {
      this.zoomOut();
    });

    // Reset zoom
    zoomReset.addEventListener("click", () => {
      this.resetZoom();
    });

    // Mouse wheel zoom (with Ctrl key)
    viewer.addEventListener("wheel", (e) => {
      if (e.ctrlKey || e.metaKey) {
        e.preventDefault();
        if (e.deltaY < 0) {
          this.zoomIn();
        } else {
          this.zoomOut();
        }
      }
    });

    console.log("SVG zoom functionality initialized");
  },

  showZoomControls() {
    const zoomControls = document.getElementById("zoomControls");
    if (zoomControls) {
      zoomControls.style.display = "block";
    }
  },

  hideZoomControls() {
    const zoomControls = document.getElementById("zoomControls");
    if (zoomControls) {
      zoomControls.style.display = "none";
    }
  },

  zoomIn() {
    if (this.currentZoom < this.maxZoom) {
      this.currentZoom = Math.min(this.maxZoom, this.currentZoom + this.zoomStep);
      this.applyZoom();
    }
  },

  zoomOut() {
    if (this.currentZoom > this.minZoom) {
      this.currentZoom = Math.max(this.minZoom, this.currentZoom - this.zoomStep);
      this.applyZoom();
    }
  },

  resetZoom() {
    this.currentZoom = 1;
    this.applyZoom();
  },

  applyZoom() {
    const viewer = document.getElementById("viewer");
    const container = document.getElementById("viewerContainer");
    if (viewer && container) {
      viewer.style.transform = `scale(${this.currentZoom})`;

      // Adjust container overflow behavior based on zoom level
      if (this.currentZoom !== 1) {
        viewer.classList.add("zoomed");
        container.style.overflow = "auto";
      } else {
        viewer.classList.remove("zoomed");
        container.style.overflow = "hidden";
      }

      this.updateZoomControls();
    }
  },

  updateZoomControls() {
    const zoomIn = document.getElementById("zoomIn");
    const zoomOut = document.getElementById("zoomOut");
    const zoomReset = document.getElementById("zoomReset");

    if (zoomIn && zoomOut && zoomReset) {
      // Update button states
      zoomIn.disabled = this.currentZoom >= this.maxZoom;
      zoomOut.disabled = this.currentZoom <= this.minZoom;

      // Update zoom percentage display
      const percentage = Math.round(this.currentZoom * 100);
      zoomReset.textContent = `${percentage}%`;

      // Show/hide controls based on whether SVG is present
      const hasSvg = document.querySelector("#viewer svg") !== null;
      if (hasSvg) {
        this.showZoomControls();
      } else {
        this.hideZoomControls();
      }
    }
  }
};

// --------- UI event handlers ---------

window.setupEventHandlers = function() {
  // Handler for loading entire project folder
  const folderInput = document.getElementById("folderInput");
  if (folderInput) {
    folderInput.addEventListener("change", async (ev) => {
      const files = Array.from(ev.target.files);
      if (!files.length) return;

      console.log("Folder selected with", files.length, "files");

      try {
        // Find project.json in the uploaded files
        const projectFile = files.find(f => f.name === 'project.json');
        if (!projectFile) {
          alert('No project.json found in selected folder. Please select a folder containing a project.json file.');
          return;
        }

        // Parse project.json
        const projectText = await projectFile.text();
        const cfg = JSON.parse(projectText);
        console.log("Loaded project configuration:", cfg);

        // Clear projectBasePath since we're loading from uploaded files
        window.timelineEngine.projectBasePath = '';

        // Update project status
        window.timelineEngine.updateFileStatus('project', projectFile.name, 'loaded');

        // Enable project edit button
        if (window.fileEditor) {
          window.fileEditor.enableEditButton('project');
        }

        // Load referenced files from the folder
        const errors = [];

        // Load stylesheet
        if (cfg.stylesheet) {
          const cssFile = files.find(f => f.name === cfg.stylesheet || f.webkitRelativePath.endsWith(cfg.stylesheet));
          if (cssFile) {
            const cssText = await cssFile.text();
            window.timelineEngine.cssData = cssText;  // Store for editing
            window.timelineEngine.cssOverride = true;
            const blob = new Blob([cssText], { type: "text/css" });
            document.getElementById("dynamicCss").href = URL.createObjectURL(blob);
            window.timelineEngine.updateFileStatus('css', cssFile.name, 'loaded');

            // Enable CSS edit button
            if (window.fileEditor) {
              window.fileEditor.enableEditButton('css');
            }

            console.log("Loaded stylesheet:", cssFile.name);
          } else {
            errors.push(`Stylesheet: ${cfg.stylesheet}`);
            window.timelineEngine.updateFileStatus('css', cfg.stylesheet, 'error');
          }
        }

        // Load SVG template
        if (cfg.svgTemplate) {
          const svgFile = files.find(f => f.name === cfg.svgTemplate || f.webkitRelativePath.endsWith(cfg.svgTemplate));
          if (svgFile) {
            window.timelineEngine.template = await svgFile.text();
            window.timelineEngine.updateFileStatus('svg', svgFile.name, 'loaded');
            window.timelineEngine.showTemplateFields();

            // Enable SVG edit button
            if (window.fileEditor) {
              window.fileEditor.enableEditButton('svg');
            }

            console.log("Loaded SVG template:", svgFile.name);
          } else {
            errors.push(`SVG template: ${cfg.svgTemplate}`);
            window.timelineEngine.updateFileStatus('svg', cfg.svgTemplate, 'error');
          }
        }

        // Load CSV data
        if (cfg.dataSource) {
          const csvFile = files.find(f => f.name === cfg.dataSource || f.webkitRelativePath.endsWith(cfg.dataSource));
          if (csvFile) {
            const csvText = await csvFile.text();
            window.timelineEngine.csvOverride = true;
            window.timelineEngine.updateFileStatus('csv', csvFile.name, 'loaded');

            // Enable CSV edit button
            if (window.fileEditor) {
              window.fileEditor.enableEditButton('csv');
            }

            console.log("Loaded CSV data:", csvFile.name);

            // Set config and process CSV
            window.timelineEngine.config = cfg;
            window.timelineEngine.processCsv(csvText);
          } else {
            errors.push(`CSV data: ${cfg.dataSource}`);
            window.timelineEngine.updateFileStatus('csv', cfg.dataSource, 'error');
          }
        }

        // Update project name and description
        const name = cfg.name || "Timeline";
        document.getElementById("projectName").textContent = name;
        document.getElementById("projectSubtitle").textContent = cfg.description || "Project loaded from folder.";

        // Show field mappings
        window.timelineEngine.showFieldMappings();

        // Show any errors
        if (errors.length > 0) {
          setTimeout(() => {
            alert(`⚠️  Some files could not be loaded:\n\n${errors.join('\n')}\n\nMake sure all referenced files are in the selected folder.`);
          }, 500);
        } else {
          console.log("✅ All project files loaded successfully from folder");
        }

      } catch (error) {
        console.error("Error loading project folder:", error);
        alert(`Error loading project: ${error.message}`);
      }
    });
  }

  const projectInput = document.getElementById("projectInput");
  if (projectInput) {
    projectInput.addEventListener("change", async (ev) => {
      const file = ev.target.files[0];
      if (!file) return;
      try {
        const text = await file.text();
        const cfg = JSON.parse(text);

        // For manually loaded projects, try to infer base path from filename
        // If it's example/project.json or binect/project.json, set appropriate base path
        const filename = file.name;
        if (filename === 'project.json') {
          // Try to detect if this is a known project by checking the config
          if (cfg.name && cfg.name.includes('Example')) {
            window.timelineEngine.projectBasePath = 'example/';
            console.log("Detected example project, setting base path to example/");
          } else if (cfg.name && (cfg.name.includes('My Project') || cfg.name.includes('Roadmap'))) {
            window.timelineEngine.projectBasePath = 'my-project/';
            console.log("Detected my-project, setting base path to my-project/");
          } else {
            window.timelineEngine.projectBasePath = '';
            console.log("Unknown project, clearing base path");
          }
        } else {
          window.timelineEngine.projectBasePath = '';
        }

        window.timelineEngine.updateFileStatus('project', file.name, 'loaded');

        // Enable project edit button
        if (window.fileEditor) {
          window.fileEditor.enableEditButton('project');
        }

        await window.timelineEngine.loadProjectConfigObject(cfg);

        // Show message about relative paths if project has data sources
        if (cfg.dataSource || cfg.stylesheet || cfg.svgTemplate) {
          const viewer = document.getElementById("viewer");
          if (viewer && (viewer.innerHTML.includes("could not be loaded") || viewer.innerHTML.includes("Keine gültigen Items"))) {
            viewer.innerHTML += "<br><br><em style='color:#6c757d; font-size:12px;'>💡 Hinweis: Stelle sicher, dass sich die referenzierten Dateien (CSV, CSS, SVG) im gleichen Verzeichnis wie die HTML-Datei befinden.</em>";
          }
        }
      } catch (error) {
        console.error("Error loading project:", error);
        window.timelineEngine.updateFileStatus('project', file.name, 'error');
      }
    });
  }

  const csvInput = document.getElementById("csvInput");
  if (csvInput) {
    csvInput.addEventListener("change", async (ev) => {
      const file = ev.target.files[0];
      if (!file) return;
      const text = await file.text();
      window.timelineEngine.csvOverride = true;
      window.timelineEngine.updateFileStatus('csv', file.name, 'loaded');

      // Enable CSV edit button
      if (window.fileEditor) {
        window.fileEditor.enableEditButton('csv');
      }

      window.timelineEngine.processCsv(text);
    });
  }

  const cssInput = document.getElementById("cssInput");
  if (cssInput) {
    cssInput.addEventListener("change", async (ev) => {
      const file = ev.target.files[0];
      if (!file) return;
      const cssText = await file.text();
      window.timelineEngine.cssData = cssText;  // Store for editing
      window.timelineEngine.cssOverride = true;
      const blob = new Blob([cssText], { type: "text/css" });
      document.getElementById("dynamicCss").href = URL.createObjectURL(blob);
      window.timelineEngine.updateFileStatus('css', file.name, 'loaded');

      // Enable CSS edit button
      if (window.fileEditor) {
        window.fileEditor.enableEditButton('css');
      }
    });
  }

  const svgInput = document.getElementById("svgInput");
  if (svgInput) {
    svgInput.addEventListener("change", async (ev) => {
      const file = ev.target.files[0];
      if (!file) return;
      window.timelineEngine.template = await file.text();
      window.timelineEngine.updateFileStatus('svg', file.name, 'loaded');

      // Enable SVG edit button
      if (window.fileEditor) {
        window.fileEditor.enableEditButton('svg');
      }

      // Show template fields in debug panel
      window.timelineEngine.showTemplateFields();

      // Show template preview immediately when manually loaded
      window.timelineEngine.showTemplatePreview();
    });
  }

  const downloadSvg = document.getElementById("downloadSvg");
  if (downloadSvg) {
    downloadSvg.addEventListener("click", () => {
      const svg = document.querySelector("#viewer svg");
      if (!svg) return;

      // Always external view for export: IDs ausblenden
      svg.querySelectorAll(".item-id").forEach(el => el.style.display = "none");

      const now = new Date();
      const ts = String(now.getFullYear()).slice(2)
                + String(now.getMonth() + 1).padStart(2, "0")
                + String(now.getDate()).padStart(2, "0")
                + "T"
                + String(now.getHours()).padStart(2, "0")
                + String(now.getMinutes()).padStart(2, "0");

      const blob = new Blob([svg.outerHTML], { type: "image/svg+xml" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = `${ts}-timeline.svg`;
      a.click();
      URL.revokeObjectURL(url);
    });
  }

  const toggleView = document.getElementById("toggleView");
  if (toggleView) {
    toggleView.addEventListener("click", () => {
      const body = document.body;
      const isInternal = body.classList.contains("internal-mode");

      if (isInternal) {
        body.classList.remove("internal-mode");
        body.classList.add("external-mode");
        toggleView.textContent = "Switch to Internal View";
        // Hide IDs in external mode
        document.querySelectorAll(".item-id").forEach(el => el.style.display = "none");
      } else {
        body.classList.remove("external-mode");
        body.classList.add("internal-mode");
        toggleView.textContent = "Switch to External View";
        // Show IDs in internal mode
        document.querySelectorAll(".item-id").forEach(el => el.style.display = "inline");
      }
    });
  }
}

