let db;
const request = indexedDB.open('DrawKisteDB', 2);
request.onupgradeneeded = (e) => {
  db = e.target.result;
  if (!db.objectStoreNames.contains('folders')) db.createObjectStore('folders', { keyPath: 'id' });
  if (!db.objectStoreNames.contains('templates')) db.createObjectStore('templates', { keyPath: 'id', autoIncrement: true });
};
// FIX: Es gab keine Fehlerbehandlung. Wenn indexedDB.open() fehlschlägt (privater Modus,
// Speicherplatz voll, blockierte Datenbank-Version...), blieb "db" für immer undefined und
// die Bibliothek lud einfach nie, ohne dass der Nutzer eine Erklärung bekam.
request.onerror = () => { console.error('DrawKiste: IndexedDB konnte nicht geöffnet werden.', request.error); alert('Die Bauteil-Bibliothek konnte nicht geladen werden (IndexedDB-Fehler). Speichern/Laden von Vorlagen ist in dieser Sitzung nicht verfügbar.'); };
request.onsuccess = (e) => { 
  db = e.target.result; 
  const tx = db.transaction('folders', 'readwrite'), store = tx.objectStore('folders'), countReq = store.count();
  countReq.onsuccess = () => {
    if (countReq.result === 0) {
      store.put({ id: 'Arduino', name: 'Arduino' }); store.put({ id: 'Elektronik', name: 'Elektronik' });
      store.put({ id: 'Energie', name: 'Energie' }); store.put({ id: 'Sonstige', name: 'Sonstige' }); store.put({ id: 'Eigene', name: 'Eigene' });
    }
  };
  tx.oncomplete = () => loadLibraryUI();
};

// FIX (weiterer schwerwiegender Bug): saveProjectFile schrieb zwar Leitungen ("ws") in die
// Datei, loadProjectFile hat "data.ws" aber nie ausgewertet -> alle Leitungen gingen beim
// Neuladen eines gespeicherten Projekts verloren. Außerdem wurde nur "maxPins" (das Maximum),
// nicht die tatsächlich vorhandene Pin-Anzahl gespeichert. Da Pin-IDs bei jedem Laden neu von 1
// weg vergeben werden, reichen die rohen alten IDs zur Wiederherstellung ohnehin nicht aus -
// wir speichern Leitungen deshalb über (Bauteil-Index, Pin-Index innerhalb des Bauteils).
function saveProjectFile() {
  const compEntries = Array.from(components.entries());
  const compIndexById = new Map(compEntries.map(([id], idx) => [id, idx]));
  const comps = compEntries.map(([, c]) => ({
    type: c.type, width: c.width, height: c.height, maxPins: c.maxPins, pinCount: c.pins.length,
    left: c.element.style.left, top: c.element.style.top,
    bgColor: c.bgColor, text: c.text, showText: c.showText, imageData: c.imageData
  }));
  const ws = Array.from(wires.values()).map(w => {
    const fromCompId = document.getElementById(w.fromPin)?.dataset.compId;
    const toCompId = document.getElementById(w.toPin)?.dataset.compId;
    const fromComp = components.get(fromCompId), toComp = components.get(toCompId);
    return {
      fromCompIndex: compIndexById.get(fromCompId), fromPinIndex: fromComp ? fromComp.pins.indexOf(w.fromPin) : -1,
      toCompIndex: compIndexById.get(toCompId), toPinIndex: toComp ? toComp.pins.indexOf(w.toPin) : -1,
      style: w.style, color: w.color, labelText: w.labelText
    };
  });
  const blob = new Blob([JSON.stringify({ comps, ws, panX: workspacePanX, panY: workspacePanY, scale: workspaceScale })], { type: 'application/json' });
  const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'mein_schaltplan.logikkiste'; a.click();
}

// FIX (kritischer Bug): Vorher wurde hier VOR dem Aufruf von createComponent() manuell
// "compCounter++" gemacht, um die neue ID zu erraten ("comp_" + compCounter). createComponent()
// selbst erhöht compCounter aber ebenfalls -> der Zähler wurde pro Bauteil doppelt erhöht, die
// erratene ID stimmte nie mit der tatsächlich erzeugten überein, document.getElementById(newCompId)
// lieferte null und der gesamte Ladevorgang brach mit einer Exception ab (meist nach dem ersten
// Bauteil). Jetzt nutzen wir die von createComponent() zurückgegebene echte ID und übergeben
// left/top gleich mit, statt sie hinterher separat zu setzen.
// Zusätzlich: try/catch + Validierung, damit eine beschädigte/fremde Datei nicht mit einer
// unbehandelten Exception mitten im (bereits geleerten!) Workspace abbricht.
function loadProjectFile(e) {
  const file = e.target.files[0]; if(!file) return;
  const reader = new FileReader();
  reader.onload = (ev) => {
    try {
      const data = JSON.parse(ev.target.result);
      if (!data || !Array.isArray(data.comps)) throw new Error('Ungültiges Dateiformat: "comps" fehlt.');

      document.querySelectorAll('.component, .wire-path, .wire-label, .wire-handle').forEach(el => el.remove());
      components.clear(); wires.clear(); compCounter = 0; pinCounter = 0; wireCounter = 0; activeCompId = null; activeWireId = null;
      updateTopBarContext();

      // createComponent() gibt jetzt die tatsächlich erzeugte ID zurück und erzeugt die
      // Pins direkt selbst über templateData.pinCount (kein manueller/geratener zweiter
      // Schritt mehr nötig, siehe editor.js).
      const newComponentIds = data.comps.map(c => createComponent(c.type, {
        maxPins: c.maxPins, width: c.width, height: c.height, left: c.left, top: c.top,
        bgColor: c.bgColor, text: c.text, showText: c.showText, imageData: c.imageData,
        pinCount: c.pinCount !== undefined ? c.pinCount : c.maxPins // Fallback für ältere Dateien ohne pinCount
      }));

      // Leitungen wiederherstellen (vorher wurde "data.ws" komplett ignoriert!). Referenzierung
      // über (Bauteil-Index, Pin-Index) statt über die alten Pin-IDs, da diese beim Laden neu
      // vergeben werden.
      if (Array.isArray(data.ws)) {
        data.ws.forEach(w => {
          const fromComp = components.get(newComponentIds[w.fromCompIndex]);
          const toComp = components.get(newComponentIds[w.toCompIndex]);
          const fromPinId = fromComp?.pins[w.fromPinIndex], toPinId = toComp?.pins[w.toPinIndex];
          if (!fromPinId || !toPinId) return;
          createWire(fromPinId, toPinId);
          const wire = wires.get(`wire_${wireCounter}`);
          if (!wire) return;
          if (w.style) wire.style = w.style;
          if (w.color) { wire.color = w.color; wire.path.setAttribute('stroke', w.color); }
          if (w.labelText) { wire.labelText = w.labelText; wire.textPathEl.textContent = w.labelText; }
          updateWirePath(wire.id);
        });
      }

      if (data.scale) { workspacePanX = data.panX || 0; workspacePanY = data.panY || 0; setZoom(data.scale); }
      alert("Projekt geladen!");
    } catch (err) {
      console.error('DrawKiste: Fehler beim Laden des Projekts.', err);
      alert('Die Datei konnte nicht geladen werden. Sie ist entweder beschädigt oder kein gültiges DrawKiste-Projekt.');
    } finally {
      e.target.value = '';
    }
  };
  reader.onerror = () => { alert('Die Datei konnte nicht gelesen werden.'); e.target.value = ''; };
  reader.readAsText(file);
}

function exportLibrary() {
  if (!db) return;
  db.transaction('folders', 'readonly').objectStore('folders').getAll().onsuccess = (e) => {
    const folders = e.target.result;
    db.transaction('templates', 'readonly').objectStore('templates').getAll().onsuccess = (tEv) => {
      const blob = new Blob([JSON.stringify({ folders, templates: tEv.target.result })], { type: 'application/json' });
      const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'bibliothek_backup.json'; a.click();
    };
  };
}

function importLibrary(e) {
  const file = e.target.files[0]; if(!file) return;
  const reader = new FileReader();
  reader.onload = (ev) => {
    try {
      const data = JSON.parse(ev.target.result);
      if (data.folders && data.templates) {
        const tx = db.transaction(['folders', 'templates'], 'readwrite');
        data.folders.forEach(f => tx.objectStore('folders').put(f));
        data.templates.forEach(t => { delete t.id; tx.objectStore('templates').add(t); });
        tx.oncomplete = () => { alert('Bibliothek ergänzt!'); loadLibraryUI(); };
        tx.onerror = () => { alert('Fehler beim Speichern der importierten Bibliothek.'); };
      } else {
        alert('Fehler! Die Datei enthält keine gültige Bibliothek (folders/templates fehlen).');
      }
    } catch (err) { alert('Fehler! Die Datei ist kein gültiges JSON.'); }
    e.target.value = '';
  }; reader.readAsText(file);
}

// FIX (Performance): Vorher rief jede exportierte Seite ihren eigenen html2canvas()-Aufruf auf
// (inkl. print-mode toggeln + 200ms Warten). Bei mehreren Seiten wurde der komplette, teils sehr
// große Workspace mehrfach komplett neu gerendert. Jetzt wird der Workspace nur EINMAL in voller
// Auflösung gerendert; einzelne Seiten werden danach günstig per Canvas-2D aus diesem einen
// "Master-Canvas" ausgeschnitten.
const CANVAS_EXPORT_SCALE = 2;
async function prepareFullCanvas() {
  document.body.classList.add('print-mode'); setActiveComp(null); setActiveWire(null);
  const ws = document.getElementById('workspace');
  const oldTransform = ws.style.transform; ws.style.transform = 'none';
  // FIX: fester setTimeout(200) durch doppeltes requestAnimationFrame ersetzt - wartet zuverlässig
  // genau einen gerenderten Frame nach dem Entfernen des Transforms ab, statt eine feste (auf
  // langsamer Hardware ggf. zu kurze, sonst unnötig lange) Wartezeit zu erzwingen.
  await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r)));
  const canvas = await html2canvas(ws, { backgroundColor: '#ffffff', scale: CANVAS_EXPORT_SCALE });
  ws.style.transform = oldTransform; document.body.classList.remove('print-mode');
  return canvas;
}

function cropCanvas(masterCanvas, x, y, w, h) {
  const c = document.createElement('canvas');
  c.width = w * CANVAS_EXPORT_SCALE; c.height = h * CANVAS_EXPORT_SCALE;
  c.getContext('2d').drawImage(
    masterCanvas,
    x * CANVAS_EXPORT_SCALE, y * CANVAS_EXPORT_SCALE, w * CANVAS_EXPORT_SCALE, h * CANVAS_EXPORT_SCALE,
    0, 0, w * CANVAS_EXPORT_SCALE, h * CANVAS_EXPORT_SCALE
  );
  return c;
}

async function exportFullPNG() { const canvas = await prepareFullCanvas(); const a = document.createElement('a'); a.href = canvas.toDataURL('image/png'); a.download = 'Schaltplan_Gesamt.png'; a.click(); }

let activePagesList = [];
function openExportModal() {
  if (gridMode === 'off') { alert("Wähle erst ein A4 Raster aus!"); return; }
  const w = gridMode === 'land' ? A4_LAND.w : A4_PORT.w, h = gridMode === 'land' ? A4_LAND.h : A4_PORT.h;
  let activeTiles = new Set();
  components.forEach(c => { const el = c.element, left = el.offsetLeft, top = el.offsetTop, right = left + c.width, bottom = top + c.height; for(let col = Math.floor(left/w); col <= Math.floor(right/w); col++) { for(let row = Math.floor(top/h); row <= Math.floor(bottom/h); row++) { if(col>=0 && row>=0) activeTiles.add(`${col},${row}`); } } });
  activePagesList = Array.from(activeTiles).map(str => { const [c, r] = str.split(',').map(Number); return { col: c, row: r, label: `Seite (Spalte ${c+1}, Zeile ${r+1})` }; }).sort((a,b) => a.row - b.row || a.col - b.col);
  const listEl = document.getElementById('export-pages-list');
  if (activePagesList.length === 0) { listEl.innerHTML = '<p style="color:#ff5555">Keine Bauteile gefunden!</p>'; } else { listEl.innerHTML = activePagesList.map((p, i) => `<label><input type="checkbox" class="export-page-cb" value="${i}" checked> ${p.label}</label>`).join(''); }
  document.getElementById('export-modal').style.display = 'flex';
}

function closeExportModal() { document.getElementById('export-modal').style.display = 'none'; }

async function exportSelectedAs(type) {
  const checkboxes = document.querySelectorAll('.export-page-cb:checked'); if (checkboxes.length === 0) return;
  const w = gridMode === 'land' ? A4_LAND.w : A4_PORT.w, h = gridMode === 'land' ? A4_LAND.h : A4_PORT.h; closeExportModal();

  // Nur noch EIN html2canvas()-Durchlauf für alle ausgewählten Seiten zusammen.
  const masterCanvas = await prepareFullCanvas();

  if (type === 'pdf') {
    const { jsPDF } = window.jspdf; const pdf = new jsPDF({ orientation: gridMode === 'land' ? 'l' : 'p', unit: 'px', format: [w, h] });
    for (let i = 0; i < checkboxes.length; i++) {
      const page = activePagesList[checkboxes[i].value];
      const canvas = cropCanvas(masterCanvas, page.col * w, page.row * h, w, h);
      if (i > 0) pdf.addPage();
      pdf.addImage(canvas.toDataURL('image/jpeg', 0.9), 'JPEG', 0, 0, w, h);
    }
    pdf.save('DrawKiste_Schaltplan.pdf');
  } else {
    for (let i = 0; i < checkboxes.length; i++) {
      const page = activePagesList[checkboxes[i].value];
      const canvas = cropCanvas(masterCanvas, page.col * w, page.row * h, w, h);
      const a = document.createElement('a'); a.href = canvas.toDataURL('image/png'); a.download = `DrawKiste_Spalte${page.col+1}_Zeile${page.row+1}.png`; a.click();
      // Kleine Pause nur noch, damit der Browser mehrere Auto-Downloads nicht blockiert
      // (kein Re-Rendering mehr nötig, daher deutlich kürzer als vorher).
      await new Promise(r => setTimeout(r, 150));
    }
  }
}

// FIX: reader.onerror und img.onerror fehlten komplett. Eine ungültige/beschädigte Bilddatei
// ließ das zurückgegebene Promise nie resolven -> der Upload blieb einfach lautlos hängen.
function resizeImageFile(file, maxDimension = 450) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onerror = () => reject(new Error('Datei konnte nicht gelesen werden.'));
    reader.onload = (e) => {
      const img = new Image();
      img.onerror = () => reject(new Error('Ungültige Bilddatei.'));
      img.onload = () => {
        let w = img.width, h = img.height;
        if (w > maxDimension || h > maxDimension) { if (w > h) { h = Math.round((h * maxDimension) / w); w = maxDimension; } else { w = Math.round((w * maxDimension) / h); h = maxDimension; } }
        const canvas = document.createElement('canvas'); canvas.width = w; canvas.height = h;
        canvas.getContext('2d').drawImage(img, 0, 0, w, h);
        resolve({ dataUrl: canvas.toDataURL('image/jpeg', 0.8), origW: w, origH: h });
      };
      img.src = e.target.result;
    };
    reader.readAsDataURL(file);
  });
}

function addFolder() { const input = document.getElementById('folder-input'), name = input.value.trim(); if (!name || !db) return; db.transaction('folders', 'readwrite').objectStore('folders').put({ id: name, name }).onsuccess = () => { input.value = ''; loadLibraryUI(); }; }

// FIX (Sicherheit - Stored XSS): Vorher wurde tpl.name/tpl.type/JSON.stringify(tpl) direkt in
// einen innerHTML-Template-String (inkl. eines Inline-onclick-Attributs in einfachen
// Anführungszeichen) eingesetzt. Eine importierte bibliothek_backup.json (fremde Datei!) mit
// z.B. einem Anführungszeichen oder <script>-Tag im Namen konnte dadurch das Attribut aufbrechen
// bzw. beliebiges HTML/JS einschleusen. Jetzt werden alle Elemente per DOM-API gebaut, Texte
// ausschließlich über textContent gesetzt und der Klick-Handler per addEventListener statt
// per Inline-onclick-String registriert.
function loadLibraryUI() {
  if (!db) return;
  const container = document.getElementById('library-container'); container.innerHTML = '';
  db.transaction('folders', 'readonly').objectStore('folders').getAll().onsuccess = (e) => {
    const folders = e.target.result;
    db.transaction('templates', 'readonly').objectStore('templates').getAll().onsuccess = (tEv) => {
      const templates = tEv.target.result;
      const frag = document.createDocumentFragment();
      folders.forEach(f => {
        const fEl = document.createElement('div'); fEl.className = 'folder-item'; fEl.textContent = `📁 ${f.name}`;
        frag.appendChild(fEl);
        templates.filter(t => t.folder === f.name).forEach(tpl => {
          const item = document.createElement('div'); item.className = 'lib-template-item';
          const span = document.createElement('span'); span.textContent = `➕ ${tpl.name}`;
          span.addEventListener('click', () => createComponent(tpl.type, tpl));
          const delBtn = document.createElement('button'); delBtn.textContent = '✕';
          delBtn.style.cssText = 'padding:1px 4px; font-size:9px; background:#444;';
          delBtn.addEventListener('click', () => deleteTemplate(tpl.id));
          item.appendChild(span); item.appendChild(delBtn);
          frag.appendChild(item);
        });
      });
      container.appendChild(frag);
    };
  };
}

function deleteTemplate(id) { if (!db) return; db.transaction('templates', 'readwrite').objectStore('templates').delete(id); loadLibraryUI(); }
