/**
 * MindMap D3.js Modul
 * Visualisiert die Mindmap mit D3.js
 */

class MindMapVisualization {
  constructor(containerSelector, options = {}) {
    this.containerSelector = containerSelector;
    this.container = d3.select(containerSelector);
    this.width = options.width || this.container.node().clientWidth || 800;
    this.height = options.height || 600;
    this.nodeRadius = options.nodeRadius || 14;
    this.selectedNodeRadius = options.selectedNodeRadius || 20;
    this.linkDistance = options.linkDistance || 150;
    this.chargeStrength = options.chargeStrength || -900;
    this.centerForce = options.centerForce || 0.15;
    this.onNodeClick = options.onNodeClick || ((node) => console.log('Node clicked:', node));

    this.nodes = [];
    this.links = [];
    this.simulation = null;
    this.svg = null;
    this.linkElements = null;
    this.nodeElements = null;
    this.textElements = null;
    this.tooltipEnabled = options.tooltipEnabled !== undefined ? options.tooltipEnabled : true;
    
    this.mouseoverNode = null;
    this.selectedNode = null;
    
    this.zoomFactor = 1;
    this.tooltipDiv = null;
    this.isLoading = true;
    
    // Lade die gemerkten Knoten
    this.bookmarkedNodes = this.loadBookmarkedNodes();
    
    // Sicherstellen, dass der Container bereit ist
    if (this.container.node()) {
      this.init();
      this.setupDefaultNodes();
      
      // Sofortige Datenladung
      window.setTimeout(() => {
        this.loadData();
      }, 100);
    } else {
      console.error('Mindmap-Container nicht gefunden:', containerSelector);
    }
  }
  
  // Standardknoten als Fallback einrichten, falls die API nicht reagiert
  setupDefaultNodes() {
    // Basis-Mindmap mit Hauptthemen
    const defaultNodes = [
      { id: "root", name: "Wissen", description: "Zentrale Wissensbasis", thought_count: 0 },
      { id: "philosophy", name: "Philosophie", description: "Philosophisches Denken", thought_count: 0 },
      { id: "science", name: "Wissenschaft", description: "Wissenschaftliche Erkenntnisse", thought_count: 0 },
      { id: "technology", name: "Technologie", description: "Technologische Entwicklungen", thought_count: 0 },
      { id: "arts", name: "Künste", description: "Künstlerische Ausdrucksformen", thought_count: 0 }
    ];
    
    const defaultLinks = [
      { source: "root", target: "philosophy" },
      { source: "root", target: "science" },
      { source: "root", target: "technology" },
      { source: "root", target: "arts" }
    ];
    
    // Als Fallback verwenden, falls die API fehlschlägt
    this.defaultNodes = defaultNodes;
    this.defaultLinks = defaultLinks;
  }
  
  init() {
    // SVG erstellen, wenn noch nicht vorhanden
    if (!this.svg) {
      // Container zuerst leeren
      this.container.html('');
      
      this.svg = this.container
        .append('svg')
        .attr('width', '100%')
        .attr('height', this.height)
        .attr('viewBox', `0 0 ${this.width} ${this.height}`)
        .attr('class', 'mindmap-svg')
        .call(
          d3.zoom()
            .scaleExtent([0.1, 5])
            .on('zoom', (event) => {
              this.handleZoom(event.transform);
            })
        );
      
      // Hauptgruppe für alles, was zoom-transformierbar ist
      this.g = this.svg.append('g');
      
      // Tooltip initialisieren
      if (!d3.select('body').select('.node-tooltip').size()) {
        this.tooltipDiv = d3.select('body')
          .append('div')
          .attr('class', 'node-tooltip')
          .style('opacity', 0)
          .style('position', 'absolute')
          .style('pointer-events', 'none')
          .style('background', 'rgba(20, 20, 40, 0.9)')
          .style('color', '#ffffff')
          .style('border', '1px solid rgba(160, 80, 255, 0.2)')
          .style('border-radius', '6px')
          .style('padding', '8px 12px')
          .style('font-size', '14px')
          .style('max-width', '250px')
          .style('box-shadow', '0 10px 25px rgba(0, 0, 0, 0.5), 0 0 10px rgba(160, 80, 255, 0.2)');
      } else {
        this.tooltipDiv = d3.select('body').select('.node-tooltip');
      }
    }
    
    // Force-Simulation initialisieren
    this.simulation = d3.forceSimulation()
      .force('link', d3.forceLink().id(d => d.id).distance(this.linkDistance))
      .force('charge', d3.forceManyBody().strength(this.chargeStrength))
      .force('center', d3.forceCenter(this.width / 2, this.height / 2).strength(this.centerForce))
      .force('collision', d3.forceCollide().radius(this.nodeRadius * 2));
      
    // Globale Mindmap-Instanz für externe Zugriffe setzen
    window.mindmapInstance = this;
  }
  
  handleZoom(transform) {
    this.g.attr('transform', transform);
    this.zoomFactor = transform.k;
    
    // Knotengröße anpassen, um bei Zoom lesbar zu bleiben
    if (this.nodeElements) {
      this.nodeElements
        .attr('r', d => (d === this.selectedNode ? this.selectedNodeRadius : this.nodeRadius) / Math.sqrt(transform.k));
    }
    
    // Textgröße anpassen
    if (this.textElements) {
      this.textElements
        .style('font-size', `${12 / Math.sqrt(transform.k)}px`);
    }
  }
  
  async loadData() {
    try {
      // Ladeindikator anzeigen
      this.showLoading();
      
      // Verwende sofort die Standarddaten für eine schnelle erste Anzeige
      this.nodes = [...this.defaultNodes];
      this.links = [...this.defaultLinks];
      
      // Visualisierung sofort aktualisieren
      this.isLoading = false;
      this.updateVisualization();
      
      // Status auf bereit setzen - don't wait for API
      this.container.attr('data-status', 'ready');
      
      // API-Aufruf mit kürzerem Timeout im Hintergrund durchführen
      try {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 Sekunden Timeout
        
        const response = await fetch('/api/mindmap', { 
          signal: controller.signal,
          headers: {
            'Cache-Control': 'no-cache', 
            'Pragma': 'no-cache'
          }
        });
        clearTimeout(timeoutId);
        
        if (!response.ok) {
          console.warn(`HTTP Fehler: ${response.status}, versuche erneute Verbindung`);
          
          // Bei Verbindungsfehler versuchen, die Verbindung neu herzustellen
          const retryResponse = await fetch('/api/refresh-mindmap', {
            headers: {
              'Cache-Control': 'no-cache', 
              'Pragma': 'no-cache'
            }
          });
          
          if (!retryResponse.ok) {
            throw new Error(`Retry failed with status: ${retryResponse.status}`);
          }
          
          const retryData = await retryResponse.json();
          
          if (!retryData.success || !retryData.nodes || retryData.nodes.length === 0) {
            console.warn('Keine Mindmap-Daten nach Neuversuch, verwende weiterhin Standard-Daten.');
            return; // Keep using default data
          }
          
          // Flache Liste von Knoten und Verbindungen erstellen
          this.nodes = [];
          this.links = [];
          
          // Knoten direkt übernehmen
          retryData.nodes.forEach(node => {
            this.nodes.push({
              id: node.id,
              name: node.name,
              description: node.description || '',
              thought_count: node.thought_count || 0,
              color: this.generateColorFromString(node.name),
            });
            
            // Verbindungen hinzufügen
            if (node.connections && node.connections.length > 0) {
              node.connections.forEach(conn => {
                this.links.push({
                  source: node.id,
                  target: conn.target
                });
              });
            }
          });
          
          // Visualisierung aktualisieren mit den tatsächlichen Daten
          this.updateVisualization();
          return;
        }
        
        const data = await response.json();
        
        if (!data || !data.nodes || data.nodes.length === 0) {
          console.warn('Keine Mindmap-Daten vorhanden, verwende weiterhin Standard-Daten.');
          return; // Keep using default data
        }
        
        // Flache Liste von Knoten und Verbindungen erstellen
        this.nodes = [];
        this.links = [];
        this.processHierarchicalData(data.nodes);
        
        // Visualisierung aktualisieren mit den tatsächlichen Daten
        this.updateVisualization();
        
      } catch (error) {
        console.warn('Fehler beim Laden der Mindmap-Daten, verwende Standarddaten:', error);
        // Already using default data, no action needed
      }
      
    } catch (error) {
      console.error('Kritischer Fehler bei der Mindmap-Darstellung:', error);
      this.showError('Fehler beim Laden der Mindmap-Daten. Bitte laden Sie die Seite neu.');
      this.container.attr('data-status', 'error');
    }
  }
  
  showLoading() {
    // Element nur leeren, wenn es noch kein SVG enthält
    if (!this.container.select('svg').size()) {
      this.container.html(`
        <div class="flex justify-center items-center h-full">
          <div class="text-center">
            <div class="animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-primary-400 mx-auto mb-4"></div>
            <p class="text-lg text-white">Mindmap wird geladen...</p>
          </div>
        </div>
      `);
    }
  }
  
  processHierarchicalData(hierarchicalNodes, parentId = null) {
    hierarchicalNodes.forEach(node => {
      // Knoten hinzufügen, wenn noch nicht vorhanden
      if (!this.nodes.find(n => n.id === node.id)) {
        this.nodes.push({
          id: node.id,
          name: node.name,
          description: node.description || '',
          thought_count: node.thought_count || 0,
          color: this.generateColorFromString(node.name),
        });
      }
      
      // Verbindung zum Elternknoten hinzufügen
      if (parentId !== null) {
        this.links.push({
          source: parentId,
          target: node.id
        });
      }
      
      // Rekursiv für Kindknoten aufrufen
      if (node.children && node.children.length > 0) {
        this.processHierarchicalData(node.children, node.id);
      }
    });
  }
  
  generateColorFromString(str) {
    // Erzeugt eine deterministische Farbe basierend auf dem String
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      hash = str.charCodeAt(i) + ((hash << 5) - hash);
    }
    
    // Verwende deterministische Farbe aus unserem Farbschema
    const colors = [
      '#4080ff', // primary-400
      '#a040ff', // secondary-400
      '#205cf5', // primary-500
      '#8020f5', // secondary-500
      '#1040e0', // primary-600
      '#6010e0', // secondary-600
    ];
    
    return colors[Math.abs(hash) % colors.length];
  }
  
  updateVisualization() {
    // Starte die Visualisierung nur, wenn nicht mehr im Ladezustand
    if (this.isLoading) return;

    // Container leeren, wenn Diagramm neu erstellt wird
    if (!this.svg) {
      this.container.html('');
      this.init();
    }

    // Performance-Optimierung: Deaktiviere Transition während des Datenladens
    const useTransitions = false;

    // Links (Edges) erstellen
    this.linkElements = this.g.selectAll('.link')
      .data(this.links)
      .join(
        enter => enter.append('line')
          .attr('class', 'link')
          .attr('stroke', '#ffffff30')
          .attr('stroke-width', 2)
          .attr('stroke-dasharray', d => d.relation_type === 'contradicts' ? '5,5' : null)
          .attr('marker-end', d => d.relation_type === 'builds_upon' ? 'url(#arrowhead)' : null),
        update => update
          .attr('stroke', '#ffffff30')
          .attr('stroke-dasharray', d => d.relation_type === 'contradicts' ? '5,5' : null)
          .attr('marker-end', d => d.relation_type === 'builds_upon' ? 'url(#arrowhead)' : null),
        exit => exit.remove()
      );
    
    // Pfeilspitze für gerichtete Beziehungen hinzufügen (falls noch nicht vorhanden)
    if (!this.svg.select('defs').node()) {
      const defs = this.svg.append('defs');
      defs.append('marker')
        .attr('id', 'arrowhead')
        .attr('viewBox', '0 -5 10 10')
        .attr('refX', 20)
        .attr('refY', 0)
        .attr('orient', 'auto')
        .attr('markerWidth', 6)
        .attr('markerHeight', 6)
        .append('path')
        .attr('d', 'M0,-5L10,0L0,5')
        .attr('fill', '#ffffff50');
    }
    
    // Simplified Effekte definieren, falls noch nicht vorhanden
    if (!this.svg.select('#glow').node()) {
      const defs = this.svg.select('defs').size() ? this.svg.select('defs') : this.svg.append('defs');
      
      // Glow-Effekt für Knoten
      const filter = defs.append('filter')
        .attr('id', 'glow')
        .attr('x', '-50%')
        .attr('y', '-50%')
        .attr('width', '200%')
        .attr('height', '200%');
      
      filter.append('feGaussianBlur')
        .attr('stdDeviation', '1')
        .attr('result', 'blur');
        
      filter.append('feComposite')
        .attr('in', 'SourceGraphic')
        .attr('in2', 'blur')
        .attr('operator', 'over');
      
      // Blur-Effekt für Schatten
      const blurFilter = defs.append('filter')
        .attr('id', 'blur')
        .attr('x', '-50%')
        .attr('y', '-50%')
        .attr('width', '200%')
        .attr('height', '200%');
      
      blurFilter.append('feGaussianBlur')
        .attr('stdDeviation', '1');
    }
    
    // Knoten-Gruppe erstellen/aktualisieren
    const nodeGroups = this.g.selectAll('.node-group')
      .data(this.nodes)
      .join(
        enter => {
          const group = enter.append('g')
            .attr('class', 'node-group')
            .call(d3.drag()
              .on('start', (event, d) => this.dragStarted(event, d))
              .on('drag', (event, d) => this.dragged(event, d))
              .on('end', (event, d) => this.dragEnded(event, d)));
          
          // Hintergrundschatten für besseren Kontrast
          group.append('circle')
            .attr('class', 'node-shadow')
            .attr('r', d => this.nodeRadius * 1.2)
            .attr('fill', 'rgba(0, 0, 0, 0.3)')
            .attr('filter', 'url(#blur)');
          
          // Kreis für jeden Knoten
          group.append('circle')
            .attr('class', d => `node ${this.isNodeBookmarked(d.id) ? 'bookmarked' : ''}`)
            .attr('r', this.nodeRadius)
            .attr('fill', d => d.color || this.generateColorFromString(d.name))
            .attr('stroke', d => this.isNodeBookmarked(d.id) ? '#FFD700' : '#ffffff50')
            .attr('stroke-width', d => this.isNodeBookmarked(d.id) ? 3 : 2)
            .attr('filter', 'url(#glow)');
          
          // Text-Label mit besserem Kontrast
          group.append('text')
            .attr('class', 'node-label')
            .attr('dy', '0.35em')
            .attr('text-anchor', 'middle')
            .attr('fill', '#ffffff')
            .attr('stroke', 'rgba(0, 0, 0, 0.4)')
            .attr('stroke-width', '0.7px')
            .attr('paint-order', 'stroke')
            .style('font-size', '12px')
            .style('font-weight', '500')
            .style('pointer-events', 'none')
            .text(d => d.name.length > 12 ? d.name.slice(0, 10) + '...' : d.name);
          
          // Interaktivität hinzufügen
          group
            .on('mouseover', (event, d) => this.nodeMouseover(event, d))
            .on('mouseout', (event, d) => this.nodeMouseout(event, d))
            .on('click', (event, d) => this.nodeClicked(event, d));
          
          return group;
        },
        update => {
          // Knoten aktualisieren
          update.select('.node')
            .attr('class', d => `node ${this.isNodeBookmarked(d.id) ? 'bookmarked' : ''}`)
            .attr('fill', d => d.color || this.generateColorFromString(d.name))
            .attr('stroke', d => this.isNodeBookmarked(d.id) ? '#FFD700' : '#ffffff50')
            .attr('stroke-width', d => this.isNodeBookmarked(d.id) ? 3 : 2);
          
          // Text aktualisieren
          update.select('.node-label')
            .text(d => d.name.length > 12 ? d.name.slice(0, 10) + '...' : d.name);
            
          return update;
        },
        exit => exit.remove()
      );
    
    // Einzelne Elemente für direkten Zugriff speichern
    this.nodeElements = this.g.selectAll('.node');
    this.textElements = this.g.selectAll('.node-label');
    
    // Performance-Optimierung: Weniger Simulationsschritte für schnellere Stabilisierung
    this.simulation
      .nodes(this.nodes)
      .on('tick', () => this.ticked())
      .alpha(0.3) // Reduzierter Wert für schnellere Stabilisierung
      .alphaDecay(0.05); // Erhöhter Wert für schnellere Stabilisierung
    
    this.simulation.force('link')
      .links(this.links);
    
    // Simulation neu starten
    this.simulation.restart();

    // Update connection counts
    this.updateConnectionCounts();
  }
  
  ticked() {
    // Linienpositionen aktualisieren
    this.linkElements
      .attr('x1', d => d.source.x)
      .attr('y1', d => d.source.y)
      .attr('x2', d => d.target.x)
      .attr('y2', d => d.target.y);
    
    // Knotenpositionen aktualisieren
    this.g.selectAll('.node-group')
      .attr('transform', d => `translate(${d.x}, ${d.y})`);
  }
  
  dragStarted(event, d) {
    if (!event.active) this.simulation.alphaTarget(0.3).restart();
    d.fx = d.x;
    d.fy = d.y;
  }
  
  dragged(event, d) {
    d.fx = event.x;
    d.fy = event.y;
  }
  
  dragEnded(event, d) {
    if (!event.active) this.simulation.alphaTarget(0);
    d.fx = null;
    d.fy = null;
  }
  
  nodeMouseover(event, d) {
    this.mouseoverNode = d;
    
    // Tooltip anzeigen
    if (this.tooltipEnabled) {
      const isBookmarked = this.isNodeBookmarked(d.id);
      const tooltipContent = `
        <div class="p-2">
          <strong>${d.name}</strong>
          ${d.description ? `<p class="text-sm text-gray-200 mt-1">${d.description}</p>` : ''}
          <div class="text-xs text-gray-300 mt-1">
            Gedanken: ${d.thought_count}
          </div>
          <div class="mt-2">
            <button id="bookmark-button" class="px-2 py-1 text-xs rounded bg-gray-700 hover:bg-gray-600 text-white" 
                    data-nodeid="${d.id}">
              ${isBookmarked ? '<i class="fas fa-bookmark mr-1"></i> Gemerkt' : '<i class="far fa-bookmark mr-1"></i> Merken'}
            </button>
          </div>
        </div>
      `;
      
      this.tooltipDiv
        .html(tooltipContent)
        .style('left', (event.pageX + 10) + 'px')
        .style('top', (event.pageY - 10) + 'px')
        .transition()
        .duration(200)
        .style('opacity', 1);
      
      // Event-Listener für den Bookmark-Button hinzufügen
      document.getElementById('bookmark-button').addEventListener('click', (e) => {
        e.stopPropagation();
        const nodeId = e.currentTarget.getAttribute('data-nodeid');
        const isNowBookmarked = this.toggleBookmark(nodeId);
        
        // Button-Text aktualisieren
        if (isNowBookmarked) {
          e.currentTarget.innerHTML = '<i class="fas fa-bookmark mr-1"></i> Gemerkt';
        } else {
          e.currentTarget.innerHTML = '<i class="far fa-bookmark mr-1"></i> Merken';
        }
      });
    }
    
    // Knoten visuell hervorheben
    d3.select(event.currentTarget).select('circle')
      .transition()
      .duration(200)
      .attr('r', this.nodeRadius * 1.2)
      .attr('stroke', this.isNodeBookmarked(d.id) ? '#FFD700' : '#ffffff');
  }
  
  nodeMouseout(event, d) {
    this.mouseoverNode = null;
    
    // Tooltip ausblenden
    if (this.tooltipEnabled) {
      this.tooltipDiv
        .transition()
        .duration(200)
        .style('opacity', 0);
    }
    
    // Knoten-Stil zurücksetzen, wenn nicht ausgewählt
    const nodeElement = d3.select(event.currentTarget).select('circle');
    if (d !== this.selectedNode) {
      const isBookmarked = this.isNodeBookmarked(d.id);
      nodeElement
        .transition()
        .duration(200)
        .attr('r', this.nodeRadius)
        .attr('stroke', isBookmarked ? '#FFD700' : '#ffffff50')
        .attr('stroke-width', isBookmarked ? 3 : 2);
    }
  }
  
  nodeClicked(event, d) {
    // Frühere Auswahl zurücksetzen
    if (this.selectedNode && this.selectedNode !== d) {
      this.g.selectAll('.node')
        .filter(n => n === this.selectedNode)
        .transition()
        .duration(200)
        .attr('r', this.nodeRadius)
        .attr('stroke', '#ffffff50');
    }
    
    // Neue Auswahl hervorheben
    if (this.selectedNode !== d) {
      this.selectedNode = d;
      d3.select(event.currentTarget).select('circle')
        .transition()
        .duration(200)
        .attr('r', this.selectedNodeRadius)
        .attr('stroke', '#ffffff');
    }
    
    // Callback mit Node-Daten aufrufen
    this.onNodeClick(d);
  }
  
  showError(message) {
    this.container.html(`
      <div class="w-full text-center p-6">
        <div class="mb-4 text-red-500">
          <i class="fas fa-exclamation-triangle text-4xl"></i>
        </div>
        <p class="text-lg text-gray-200">${message}</p>
      </div>
    `);
  }
  
  // Fokussiert die Ansicht auf einen bestimmten Knoten
  focusNode(nodeId) {
    const node = this.nodes.find(n => n.id === nodeId);
    if (!node) return;
    
    // Simuliere einen Klick auf den Knoten
    const nodeElement = this.g.selectAll('.node-group')
      .filter(d => d.id === nodeId);
    
    nodeElement.dispatch('click');
    
    // Zentriere den Knoten in der Ansicht
    const transform = d3.zoomIdentity
      .translate(this.width / 2, this.height / 2)
      .scale(1.2)
      .translate(-node.x, -node.y);
    
    this.svg.transition()
      .duration(750)
      .call(
        d3.zoom().transform,
        transform
      );
  }
  
  // Filtert die Mindmap basierend auf einem Suchbegriff
  filterBySearchTerm(searchTerm) {
    if (!searchTerm || searchTerm.trim() === '') {
      // Alle Knoten anzeigen
      this.g.selectAll('.node-group')
        .style('opacity', 1)
        .style('pointer-events', 'all');
      
      this.g.selectAll('.link')
        .style('opacity', 1);
      
      return;
    }
    
    const searchLower = searchTerm.toLowerCase();
    const matchingNodes = this.nodes.filter(node => 
      node.name.toLowerCase().includes(searchLower) ||
      (node.description && node.description.toLowerCase().includes(searchLower))
    );
    
    const matchingNodeIds = new Set(matchingNodes.map(n => n.id));
    
    // Passende Knoten hervorheben, andere ausblenden
    this.g.selectAll('.node-group')
      .style('opacity', d => matchingNodeIds.has(d.id) ? 1 : 0.2)
      .style('pointer-events', d => matchingNodeIds.has(d.id) ? 'all' : 'none');
    
    // Verbindungen zwischen passenden Knoten hervorheben
    this.g.selectAll('.link')
      .style('opacity', d => 
        matchingNodeIds.has(d.source.id) && matchingNodeIds.has(d.target.id) ? 1 : 0.1
      );
    
    // Auf den ersten passenden Knoten fokussieren, wenn vorhanden
    if (matchingNodes.length > 0) {
      this.focusNode(matchingNodes[0].id);
    }
  }

  /**
   * Updates the thought_count property for each node based on existing connections
   */
  updateConnectionCounts() {
    // Reset all counts first
    this.nodes.forEach(node => {
      // Initialize thought_count if it doesn't exist
      if (typeof node.thought_count !== 'number') {
        node.thought_count = 0;
      }
      
      // Count connections for this node
      const connectedNodes = this.getConnectedNodes(node);
      node.thought_count = connectedNodes.length;
    });
    
    // Update UI to show counts
    this.updateNodeLabels();
  }
  
  /**
   * Updates the visual representation of node labels to include connection counts
   */
  updateNodeLabels() {
    if (!this.textElements) return;
    
    this.textElements.text(d => {
      if (d.thought_count > 0) {
        return `${d.name} (${d.thought_count})`;
      }
      return d.name;
    });
  }
  
  /**
   * Adds a new connection between nodes and updates the counts
   */
  addConnection(sourceNode, targetNode) {
    if (!sourceNode || !targetNode) return false;
    
    // Check if connection already exists
    if (this.isConnected(sourceNode, targetNode)) return false;
    
    // Add new connection
    this.links.push({
      source: sourceNode.id,
      target: targetNode.id
    });
    
    // Update counts
    this.updateConnectionCounts();
    
    // Update visualization
    this.updateVisualization();
    
    return true;
  }

  // Lädt gemerkete Knoten aus dem LocalStorage
  loadBookmarkedNodes() {
    try {
      const bookmarked = localStorage.getItem('bookmarkedNodes');
      return bookmarked ? JSON.parse(bookmarked) : [];
    } catch (error) {
      console.error('Fehler beim Laden der gemerkten Knoten:', error);
      return [];
    }
  }
  
  // Speichert gemerkete Knoten im LocalStorage
  saveBookmarkedNodes() {
    try {
      localStorage.setItem('bookmarkedNodes', JSON.stringify(this.bookmarkedNodes));
    } catch (error) {
      console.error('Fehler beim Speichern der gemerkten Knoten:', error);
    }
  }
  
  // Prüft, ob ein Knoten gemerkt ist
  isNodeBookmarked(nodeId) {
    return this.bookmarkedNodes.includes(nodeId);
  }
  
  // Merkt einen Knoten oder hebt die Markierung auf
  toggleBookmark(nodeId) {
    const index = this.bookmarkedNodes.indexOf(nodeId);
    if (index === -1) {
      // Node hinzufügen
      this.bookmarkedNodes.push(nodeId);
      this.updateNodeAppearance(nodeId, true);
    } else {
      // Node entfernen
      this.bookmarkedNodes.splice(index, 1);
      this.updateNodeAppearance(nodeId, false);
    }
    
    // Änderungen speichern
    this.saveBookmarkedNodes();
    
    // Event auslösen für andere Komponenten
    const event = new CustomEvent('nodeBookmarkToggled', {
      detail: { 
        nodeId: nodeId, 
        isBookmarked: index === -1 
      }
    });
    document.dispatchEvent(event);
    
    return index === -1; // true wenn jetzt gemerkt, false wenn Markierung aufgehoben
  }
  
  // Aktualisiert das Aussehen eines Knotens basierend auf Bookmark-Status
  updateNodeAppearance(nodeId, isBookmarked) {
    this.g.selectAll('.node-group')
      .filter(d => d.id === nodeId)
      .select('.node')
      .classed('bookmarked', isBookmarked)
      .attr('stroke', isBookmarked ? '#FFD700' : '#ffffff50')
      .attr('stroke-width', isBookmarked ? 3 : 2);
  }
  
  // Aktualisiert das Aussehen aller gemerkten Knoten
  updateAllBookmarkedNodes() {
    this.g.selectAll('.node-group')
      .each((d) => {
        const isBookmarked = this.isNodeBookmarked(d.id);
        this.updateNodeAppearance(d.id, isBookmarked);
      });
  }

  /**
   * Gibt alle direkt verbundenen Knoten eines Knotens zurück
   * @param {Object} node - Der Knoten, für den die Verbindungen gesucht werden
   * @returns {Array} Array der verbundenen Knotenobjekte
   */
  getConnectedNodes(node) {
    if (!node || !this.links || !this.nodes) return [];
    const nodeId = node.id;
    const connectedIds = new Set();
    this.links.forEach(link => {
      if (link.source === nodeId || (link.source && link.source.id === nodeId)) {
        connectedIds.add(link.target.id ? link.target.id : link.target);
      }
      if (link.target === nodeId || (link.target && link.target.id === nodeId)) {
        connectedIds.add(link.source.id ? link.source.id : link.source);
      }
    });
    return this.nodes.filter(n => connectedIds.has(n.id));
  }
}

// Exportiere die Klasse für die Verwendung in anderen Modulen
window.MindMapVisualization = MindMapVisualization; 