let compCounter = 0, pinCounter = 0, wireCounter = 0;
let connectSourcePinId = null, currentUploadCompId = null;
let activeCompId = null, activeWireId = null;

const components = new Map(), wires = new Map();
let dragType = null, dragItem = null;
let startX, startY, origX, origY, origW, dragHandleData = null;
let isPanning = false, panStartX, panStartY, initialPanX, initialPanY;

// FIX (Performance): Die Workspace-Position auf dem Bildschirm ändert sich während eines
// laufenden Drags/Pans nicht. Wir cachen getBoundingClientRect() deshalb einmal beim
// mousedown statt sie bei jedem einzelnen mousemove neu (und damit Layout-erzwingend) abzufragen.
let cachedWorkspaceRect = null;
function getWorkspaceRect() { return cachedWorkspaceRect || document.getElementById('workspace').getBoundingClientRect(); }
function getInternalCoords(e) { const rect = getWorkspaceRect(); return { x: (e.clientX - rect.left) / workspaceScale, y: (e.clientY - rect.top) / workspaceScale }; }

// createComponent gibt jetzt die neu erzeugte ID zurück (Fix: siehe loadProjectFile in
// storage.js, das früher selbst compCounter++ gemacht und die ID dadurch verdoppelt/erraten hat).
// Optional können left/top direkt über templateData gesetzt werden (fürs Laden gespeicherter Projekte).
function createComponent(type, templateData = null) {
  compCounter++; const id = `comp_${compCounter}`;
  const compEl = document.createElement('div'); compEl.className = 'component'; compEl.id = id;

  // FIX/Anpassung: einheitliches Pin-Maximum von 15 für alle Bauteilgrößen (vorher je nach
  // Größe unterschiedlich: S=6, M=10, L=20). Die Größe (S/M/L) beeinflusst weiterhin nur noch
  // die Bauteil-Abmessungen (multiplier), nicht mehr die maximale Pin-Zahl.
  const MAX_PINS_DEFAULT = 15;
  let maxPins = MAX_PINS_DEFAULT, multiplier = 1;
  if (templateData && templateData.maxPins) { maxPins = templateData.maxPins; } 
  else { if (currentCompSize === 'S') { multiplier = 0.7; } else if (currentCompSize === 'L') { multiplier = 1.5; } }

  let width = (type === 'rect-v' ? 120 : (type === 'square' || type === 'circle' ? 140 : 180)) * multiplier;
  let height = (type === 'rect-h' ? 120 : (type === 'square' || type === 'circle' ? 140 : 180)) * multiplier;
  if (type === 'resistor') { width = 160 * multiplier; height = 60 * multiplier; maxPins = 2; }
  
  if (templateData && templateData.width) width = templateData.width;
  if (templateData && templateData.height) height = templateData.height;

  if (type === 'circle') compEl.classList.add('circle');
  compEl.style.width = width + 'px'; compEl.style.height = height + 'px';
  if (templateData && templateData.left !== undefined && templateData.top !== undefined) {
    compEl.style.left = templateData.left; compEl.style.top = templateData.top;
  } else {
    const spawnOffset = (compCounter * 25) % 250;
    compEl.style.left = ((-workspacePanX / workspaceScale) + 100 + spawnOffset) + 'px';
    compEl.style.top = ((-workspacePanY / workspaceScale) + 100 + spawnOffset) + 'px';
  }

  let initialBg = templateData?.bgColor || compColor;
  let initialText = templateData?.text || (type === 'resistor' ? '10k' : 'Text...');
  const initialShowText = templateData?.showText !== undefined ? templateData.showText : true;

  if (type === 'resistor') initialBg = 'transparent';
  compEl.style.backgroundColor = initialBg;

  // Der Container hat keinen Header mehr, nur den Inhaltsbereich!
  // FIX (Sicherheit): initialText kann aus einer Bibliotheks-/Projektdatei stammen (also von
  // außen kommen). Vorher wurde der Wert direkt in innerHTML interpoliert -> Stored-XSS, wenn
  // eine importierte .json/.logikkiste HTML wie "<img src=x onerror=...>" als Text enthält.
  // Jetzt bauen wir das Element per DOM-API und setzen den Text ausschließlich über textContent.
  const viewportEl = document.createElement('div'); viewportEl.className = 'comp-viewport';
  const textEl = document.createElement('div'); textEl.className = 'comp-text';
  textEl.contentEditable = 'true'; textEl.spellcheck = false;
  textEl.style.display = initialShowText ? 'flex' : 'none';
  textEl.textContent = initialText;
  viewportEl.appendChild(textEl); compEl.appendChild(viewportEl);

  document.getElementById('workspace').appendChild(compEl);
  components.set(id, { element: compEl, type, width, height, maxPins, pins: [], imageData: null, bgColor: initialBg, text: initialText, showText: initialShowText });

  // Live-Update, wenn der Text getippt wird (besonders für Widerstand wichtig)
  // FIX: innerHTML durch textContent ersetzt, damit auch bei Copy&Paste kein HTML in
  // components.text landen und später beim Neuanlegen ausgeführt werden kann.
  textEl.addEventListener('input', (e) => {
    components.get(id).text = e.target.textContent;
    if (type === 'resistor') renderResistorSVG(id, e.target.textContent);
  });

  if (type === 'resistor') renderResistorSVG(id, initialText);

  if (templateData) {
    if (templateData.imageData) { components.get(id).imageData = { ...templateData.imageData }; renderCompImage(id); }
    for (let i = 0; i < templateData.pinCount; i++) addPinToComp(id);
  } else { addPinToComp(id); addPinToComp(id); }

  setActiveComp(id);
  return id;
}

// --- Top-Bar Kontextmenü Steuerung ---
function updateTopBarContext() {
  const menu = document.getElementById('context-menu');
  if (!activeCompId) { menu.style.display = 'none'; return; }
  const comp = components.get(activeCompId);
  document.getElementById('context-title').innerText = comp.type === 'resistor' ? 'Widerstand' : 'Bauteil';
  document.getElementById('context-pin-counter').innerText = `${comp.pins.length}/${comp.maxPins}`;
  menu.style.display = 'flex';
}

function activeToggleText() {
  const comp = components.get(activeCompId); if (!comp) return;
  comp.showText = !comp.showText;
  const textEl = comp.element.querySelector('.comp-text');
  if (textEl) textEl.style.display = comp.showText ? 'flex' : 'none';
}

function activeDeleteComponent() {
  const compId = activeCompId; const comp = components.get(compId); if (!comp) return;
  comp.pins.forEach(pinId => {
    const wiresToDelete = []; wires.forEach((w, wId) => { if (w.fromPin === pinId || w.toPin === pinId) wiresToDelete.push(wId); });
    wiresToDelete.forEach(wId => removeWire(wId)); document.getElementById(pinId)?.remove();
  });
  comp.element.remove(); components.delete(compId); setActiveComp(null);
}

function activeAddPin() { addPinToComp(activeCompId); }
function activeRemovePin() { removePinFromComp(activeCompId); }
function activeTriggerImage() { currentUploadCompId = activeCompId; document.getElementById('image-upload').click(); }

function activeSaveComponent() {
  const compId = activeCompId; const comp = components.get(compId); if (!comp || !db) return;
  const name = prompt('Name für Vorlage:', comp.type === 'resistor' ? 'Widerstand' : 'Neues Bauteil'); if (!name) return;
  const folder = prompt('Ordner (Arduino, Elektronik, Energie, Eigene):', 'Eigene') || 'Eigene';
  db.transaction('folders', 'readwrite').objectStore('folders').put({ id: folder, name: folder }).onsuccess = () => {
    const template = { name, folder, type: comp.type, pinCount: comp.pins.length, maxPins: comp.maxPins, width: comp.width, height: comp.height, imageData: comp.imageData, bgColor: comp.bgColor, text: comp.text, showText: comp.showText };
    db.transaction('templates', 'readwrite').objectStore('templates').add(template).onsuccess = () => loadLibraryUI();
  };
}

async function handleImageUpload(e) {
  const file = e.target.files[0]; if (!file || !currentUploadCompId) return;
  const comp = components.get(currentUploadCompId); if (!comp) return;
  const optimized = await resizeImageFile(file, 450); comp.imageData = { src: optimized.dataUrl, x: 0, y: 0, w: optimized.origW, h: optimized.origH, scale: 1 }; renderCompImage(currentUploadCompId); e.target.value = '';
}

function setActiveComp(id) {
  document.querySelectorAll('.component').forEach(el => el.classList.remove('active-comp'));
  document.querySelectorAll('.wire-path').forEach(el => el.classList.remove('active-wire-path'));
  activeCompId = id; activeWireId = null;
  if (id) { document.getElementById(id).classList.add('active-comp'); document.getElementById('comp-color').value = components.get(id).bgColor; }
  updateTopBarContext();
}

function setActiveWire(id) {
  document.querySelectorAll('.component').forEach(el => el.classList.remove('active-comp'));
  document.querySelectorAll('.wire-path').forEach(el => el.classList.remove('active-wire-path'));
  activeWireId = id; activeCompId = null;
  if (id) { const wire = wires.get(id); wire.path.classList.add('active-wire-path'); document.getElementById('wire-color').value = wire.color; }
  updateTopBarContext();
}

function applyColorToActive(hex) { if (activeCompId) { const comp = components.get(activeCompId); if(comp.type!=='resistor') { comp.bgColor = hex; comp.element.style.backgroundColor = hex; } } }
function applyWireColorToActive(hex) { if (activeWireId) { const wire = wires.get(activeWireId); wire.color = hex; wire.path.setAttribute('stroke', hex); } }

function renderCompImage(compId) {
  const comp = components.get(compId); if (!comp || !comp.imageData) return;
  const viewport = comp.element.querySelector('.comp-viewport');
  let imgEl = viewport.querySelector('.comp-image'), handleEl = viewport.querySelector('.img-resize-handle');
  if (!imgEl) { imgEl = document.createElement('img'); imgEl.className = 'comp-image'; viewport.appendChild(imgEl); handleEl = document.createElement('div'); handleEl.className = 'img-resize-handle'; viewport.appendChild(handleEl); }
  imgEl.src = comp.imageData.src; imgEl.style.left = comp.imageData.x + 'px'; imgEl.style.top = comp.imageData.y + 'px';
  imgEl.style.width = (comp.imageData.w * comp.imageData.scale) + 'px'; imgEl.style.height = (comp.imageData.h * comp.imageData.scale) + 'px';
  handleEl.style.left = (comp.imageData.x + comp.imageData.w * comp.imageData.scale) + 'px'; handleEl.style.top = (comp.imageData.y + comp.imageData.h * comp.imageData.scale) + 'px';
}

function addPinToComp(compId) {
  const comp = components.get(compId); if (!comp || comp.pins.length >= comp.maxPins) return;
  pinCounter++; const pinId = `pin_${pinCounter}`; const pinEl = document.createElement('div'); pinEl.className = 'pin'; pinEl.id = pinId; pinEl.dataset.compId = compId;
  comp.element.appendChild(pinEl); comp.pins.push(pinId); redistributePins(compId); updateTopBarContext();
}
function removePinFromComp(compId) {
  const comp = components.get(compId); if (!comp || comp.pins.length === 0) return;
  const removedPinId = comp.pins.pop(), wiresToDelete = [];
  wires.forEach((wire, wireId) => { if (wire.fromPin === removedPinId || wire.toPin === removedPinId) wiresToDelete.push(wireId); });
  wiresToDelete.forEach(wId => removeWire(wId)); document.getElementById(removedPinId)?.remove(); updateTopBarContext();
}

function redistributePins(compId) {
  const comp = components.get(compId), count = comp.pins.length; if (count === 0) return;
  if (comp.type === 'resistor') {
     // Widerstand Pins immer genau links und rechts mittig
     comp.pins.forEach((pinId, idx) => {
       const el = document.getElementById(pinId); el.style.top = (comp.height / 2) + 'px'; el.style.left = (idx === 0 ? 0 : comp.width) + 'px';
     });
  } else if (comp.type === 'circle') {
    const r = comp.width / 2, step = (2 * Math.PI) / count;
    comp.pins.forEach((pinId, idx) => { const angle = idx * step, el = document.getElementById(pinId); el.dataset.angle = angle; el.style.left = (r + r * Math.cos(angle)) + 'px'; el.style.top = (r + r * Math.sin(angle)) + 'px'; });
  } else {
    const w = comp.width, h = comp.height, perimeter = 2 * (w + h), step = perimeter / count;
    comp.pins.forEach((pinId, idx) => {
      const dist = idx * step; let pos;
      if (dist <= w) pos = { x: dist, y: 0 }; else if (dist <= w + h) pos = { x: w, y: dist - w }; else if (dist <= 2 * w + h) pos = { x: w - (dist - (w + h)), y: h }; else pos = { x: 0, y: h - (dist - (2 * w + h)) };
      const el = document.getElementById(pinId); el.style.left = pos.x + 'px'; el.style.top = pos.y + 'px';
    });
  }
  updateAllWires();
}

function createWire(fromPinId, toPinId) {
  wireCounter++; const wireId = `wire_${wireCounter}`;
  const p1 = getPinCenter(fromPinId), p2 = getPinCenter(toPinId), h1 = { x: p1.x + (p2.x - p1.x) * 0.33, y: p1.y }, h2 = { x: p1.x + (p2.x - p1.x) * 0.66, y: p2.y };
  const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
  path.setAttribute('id', wireId); path.setAttribute('class', 'wire-path'); path.setAttribute('stroke', wireColor);
  path.addEventListener('mousedown', (e) => { setActiveWire(wireId); e.stopPropagation(); });
  path.addEventListener('dblclick', () => { const newText = prompt('Text für Leitung:', wires.get(wireId).labelText || ''); if (newText !== null) { wires.get(wireId).labelText = newText; wires.get(wireId).textPathEl.textContent = newText; } });
  path.addEventListener('contextmenu', (e) => { e.preventDefault(); removeWire(wireId); });
  const textEl = document.createElementNS('http://www.w3.org/2000/svg', 'text'); textEl.setAttribute('class', 'wire-label'); textEl.setAttribute('dy', '-6');
  const textPath = document.createElementNS('http://www.w3.org/2000/svg', 'textPath'); textPath.setAttribute('href', '#' + wireId); textPath.setAttribute('startOffset', '50%'); textPath.setAttribute('text-anchor', 'middle');
  textEl.appendChild(textPath);
  document.getElementById('wire-layer').appendChild(path); document.getElementById('wire-layer').appendChild(textEl);
  const h1El = document.createElement('div'); h1El.className = 'wire-handle'; h1El.id = `${wireId}_h1`; const h2El = document.createElement('div'); h2El.className = 'wire-handle'; h2El.id = `${wireId}_h2`;
  document.getElementById('workspace').appendChild(h1El); document.getElementById('workspace').appendChild(h2El);
  wires.set(wireId, { id: wireId, fromPin: fromPinId, toPin: toPinId, style: currentStyle, color: wireColor, h1, h2, h1El, h2El, path, textEl, textPathEl: textPath, labelText: '' });
  updateWirePath(wireId); setActiveWire(wireId);
}
function removeWire(wireId) { const wire = wires.get(wireId); if (!wire) return; wire.path.remove(); wire.textEl.remove(); wire.h1El.remove(); wire.h2El.remove(); wires.delete(wireId); if (activeWireId === wireId) setActiveWire(null); }

// FIX (Performance): Vorher wurde hier pro Aufruf zweimal getBoundingClientRect() aufgerufen,
// was jedes Mal einen synchronen Layout-Reflow erzwingt. Bei jedem mousemove während eines
// Bauteil-Drags wurde diese Funktion für JEDEN Pin JEDER Leitung im Projekt aufgerufen -> bei
// größeren Schaltplänen spürbares Ruckeln. Pin- und Bauteil-Position liegen aber bereits als
// Inline-Styles (unskalierte Workspace-Koordinaten) vor, wir können die Mitte also ohne Reflow
// direkt daraus berechnen.
function getPinCenter(pinId) {
  const pinEl = document.getElementById(pinId);
  const compEl = pinEl.parentElement;
  const compLeft = parseFloat(compEl.style.left) || 0, compTop = parseFloat(compEl.style.top) || 0;
  const pinLeft = parseFloat(pinEl.style.left) || 0, pinTop = parseFloat(pinEl.style.top) || 0;
  return { x: compLeft + pinLeft, y: compTop + pinTop };
}

function updateWirePath(wireId) {
  const wire = wires.get(wireId), p1 = getPinCenter(wire.fromPin), p2 = getPinCenter(wire.toPin);
  if (wire.style === 'straight') { wire.h1El.style.display = 'none'; wire.h2El.style.display = 'none'; wire.path.setAttribute('d', `M ${p1.x} ${p1.y} L ${p2.x} ${p2.y}`); } 
  else { wire.h1El.style.display = 'block'; wire.h2El.style.display = 'block'; wire.h1El.style.left = wire.h1.x + 'px'; wire.h1El.style.top = wire.h1.y + 'px'; wire.h2El.style.left = wire.h2.x + 'px'; wire.h2El.style.top = wire.h2.y + 'px';
    if (wire.style === 'bezier') wire.path.setAttribute('d', `M ${p1.x} ${p1.y} C ${wire.h1.x} ${wire.h1.y}, ${wire.h2.x} ${wire.h2.y}, ${p2.x} ${p2.y}`);
    else if (wire.style === 'ortho') wire.path.setAttribute('d', `M ${p1.x} ${p1.y} H ${wire.h1.x} V ${wire.h1.y} H ${wire.h2.x} V ${wire.h2.y} H ${p2.x} V ${p2.y}`); }
}
function updateAllWires() { wires.forEach((_, id) => updateWirePath(id)); }

// FIX (Performance): Beim Verschieben eines Bauteils (dragType 'box') wurden vorher bei JEDEM
// mousemove ALLE Leitungen im gesamten Projekt neu berechnet, nicht nur die am gezogenen
// Bauteil hängenden. Bei vielen Leitungen war das der größte Performance-Killer beim Draggen.
function updateWiresForComponent(compId) {
  const comp = components.get(compId); if (!comp) return;
  const pinSet = new Set(comp.pins);
  wires.forEach((wire, id) => { if (pinSet.has(wire.fromPin) || pinSet.has(wire.toPin)) updateWirePath(id); });
}

document.getElementById('workspace-wrapper').addEventListener('mousedown', (e) => {
  // FIX (Performance): Workspace-Rect einmal pro Interaktion cachen statt bei jedem mousemove neu abzufragen.
  cachedWorkspaceRect = document.getElementById('workspace').getBoundingClientRect();
  if (e.button === 1 || interactionMode === 'pan') { isPanning = true; panStartX = e.clientX; panStartY = e.clientY; initialPanX = workspacePanX; initialPanY = workspacePanY; e.preventDefault(); return; }
  if (e.target.closest('.pin-btn') || e.target.closest('.action-btn') || e.target.closest('.upload-trigger')) return;
  if (e.target.classList.contains('comp-text')) { setActiveComp(e.target.closest('.component').id); return; }
  const coords = getInternalCoords(e);
  if (e.target.classList.contains('img-resize-handle')) { dragType = 'img-scale'; dragItem = components.get(e.target.closest('.component').id); startX = coords.x; origW = dragItem.imageData.w * dragItem.imageData.scale; e.stopPropagation(); return; }
  if (interactionMode === 'img' && e.target.classList.contains('comp-image')) { dragType = 'img-pan'; dragItem = components.get(e.target.closest('.component').id); startX = coords.x; startY = coords.y; origX = dragItem.imageData.x; origY = dragItem.imageData.y; e.stopPropagation(); return; }
  if (e.target.classList.contains('wire-handle')) { dragType = 'handle'; dragItem = e.target; dragHandleData = { wireId: e.target.id.split('_')[0] + "_" + e.target.id.split('_')[1], hIdx: e.target.id.split('_')[2] }; e.stopPropagation(); return; }
  if (e.target.classList.contains('pin')) {
    if (interactionMode === 'wire') { if (!connectSourcePinId) { connectSourcePinId = e.target.id; e.target.classList.add('connecting'); } else { if (connectSourcePinId !== e.target.id) createWire(connectSourcePinId, e.target.id); document.getElementById(connectSourcePinId)?.classList.remove('connecting'); connectSourcePinId = null; } } 
    else if (interactionMode === 'edit') { dragType = 'pin'; dragItem = e.target; }
    e.stopPropagation(); return;
  }
  if (connectSourcePinId) { document.getElementById(connectSourcePinId)?.classList.remove('connecting'); connectSourcePinId = null; }
  const compEl = e.target.closest('.component');
  if (compEl) { setActiveComp(compEl.id); if (interactionMode !== 'img') { dragType = 'box'; dragItem = compEl; startX = coords.x; startY = coords.y; origX = compEl.offsetLeft; origY = compEl.offsetTop; } e.stopPropagation(); } 
  else { setActiveComp(null); setActiveWire(null); }
});

document.addEventListener('mousemove', (e) => {
  if (isPanning) { workspacePanX = initialPanX + (e.clientX - panStartX); workspacePanY = initialPanY + (e.clientY - panStartY); applyWorkspaceTransform(); return; }
  if (!dragType) return; const coords = getInternalCoords(e);
  if (dragType === 'box') { dragItem.style.left = (origX + (coords.x - startX)) + 'px'; dragItem.style.top = (origY + (coords.y - startY)) + 'px'; updateWiresForComponent(dragItem.id); }
  else if (dragType === 'img-pan') { dragItem.imageData.x = origX + (coords.x - startX); dragItem.imageData.y = origY + (coords.y - startY); renderCompImage(dragItem.element.id); }
  else if (dragType === 'img-scale') { dragItem.imageData.scale = Math.max(30, origW + (coords.x - startX)) / Math.max(1, dragItem.imageData.w); renderCompImage(dragItem.element.id); }
  else if (dragType === 'handle') { const wire = wires.get(dragHandleData.wireId); if (wire) { if (dragHandleData.hIdx === 'h1') { wire.h1.x = coords.x; wire.h1.y = coords.y; } else { wire.h2.x = coords.x; wire.h2.y = coords.y; } updateWirePath(wire.id); } } 
  else if (dragType === 'pin') {
    const pin = dragItem, compEl = pin.parentElement, comp = components.get(compEl.id), relX = coords.x - compEl.offsetLeft, relY = coords.y - compEl.offsetTop;
    if (comp.type === 'resistor') return; // Widerstand-Pins sind fix
    if (comp.type !== 'circle') { const w = comp.width, h = comp.height, minD = Math.min(Math.abs(relY), Math.abs(relY - h), Math.abs(relX), Math.abs(relX - w)); let x = Math.max(0, Math.min(w, relX)), y = Math.max(0, Math.min(h, relY)); if (minD === Math.abs(relY)) y = 0; else if (minD === Math.abs(relY - h)) y = h; else if (minD === Math.abs(relX)) x = 0; else if (minD === Math.abs(relX - w)) x = w; pin.style.left = x + 'px'; pin.style.top = y + 'px'; } 
    else { const r = comp.width / 2, angle = Math.atan2(relY - r, relX - r); pin.dataset.angle = angle; pin.style.left = (r + r * Math.cos(angle)) + 'px'; pin.style.top = (r + r * Math.sin(angle)) + 'px'; } updateAllWires();
  }
});
document.addEventListener('mouseup', () => { isPanning = false; dragType = null; dragItem = null; dragHandleData = null; cachedWorkspaceRect = null; });