// Graph Explorer View
// Interactive code relationship visualization using Cytoscape.js

// ========== State Variables ==========
var graphData = { nodes: [], edges: [] };
var cyInstance = null;
var activeTab = 'graph';
var activeDataSource = 'code';
var nodeFilters = {
  MODULE: true,
  CLASS: true,
  FUNCTION: true,
  METHOD: true,
  VARIABLE: true
};
var edgeFilters = {
  CALLS: true,
  IMPORTS: true,
  INHERITS: true
};
var selectedNode = null;
var searchProcessData = null;
var availableFiles = [];
var availableModules = [];
var selectedFile = null;
var selectedModule = null;
var filterMode = 'all'; // 'all', 'file', 'module'

// ========== Node/Edge Colors ==========
var NODE_COLORS = {
  MODULE: '#8B5CF6',
  CLASS: '#3B82F6',
  FUNCTION: '#10B981',
  METHOD: '#F59E0B',
  VARIABLE: '#6B7280'
};

var EDGE_COLORS = {
  CALLS: '#10B981',
  IMPORTS: '#3B82F6',
  INHERITS: '#F59E0B'
};

// ========== Main Render Function ==========
async function renderGraphExplorer() {
  var container = document.getElementById('mainContent');
  if (!container) return;

  // Hide stats grid and carousel
  hideStatsAndCarousel();

  // Show loading state
  container.innerHTML = '<div class="graph-explorer-view loading">' +
    '<div class="loading-spinner"><i data-lucide="loader-2" class="w-8 h-8 animate-spin"></i></div>' +
    '<p>' + t('common.loading') + '</p>' +
    '</div>';

  // Load data
  await Promise.all([
    loadGraphData(),
    loadSearchProcessData(),
    loadFilesAndModules()
  ]);

  // Render layout
  container.innerHTML = renderGraphLayout();

  // Initialize Cytoscape.js after DOM is ready
  setTimeout(function() {
    if (activeTab === 'graph') {
      initializeCytoscape();
    }
    if (window.lucide) lucide.createIcons();
  }, 100);
}

// ========== Data Loading ==========
async function loadGraphData() {
  try {
    // Build query parameters based on filter mode
    var queryParams = new URLSearchParams();
    if (filterMode === 'file' && selectedFile) {
      queryParams.set('file', selectedFile);
    } else if (filterMode === 'module' && selectedModule) {
      queryParams.set('module', selectedModule);
    }

    var queryString = queryParams.toString();
    var nodesUrl = '/api/graph/nodes' + (queryString ? '?' + queryString : '');
    var edgesUrl = '/api/graph/edges' + (queryString ? '?' + queryString : '');

    console.log('[Graph] Loading data with filter:', {
      mode: filterMode,
      file: selectedFile,
      module: selectedModule,
      nodesUrl: nodesUrl,
      edgesUrl: edgesUrl
    });

    var nodesResp = await fetch(nodesUrl);
    if (!nodesResp.ok) throw new Error('Failed to load graph nodes');
    var nodesData = await nodesResp.json();

    var edgesResp = await fetch(edgesUrl);
    if (!edgesResp.ok) throw new Error('Failed to load graph edges');
    var edgesData = await edgesResp.json();

    graphData = {
      nodes: nodesData.nodes || [],
      edges: edgesData.edges || []
    };

    console.log('[Graph] Loaded data:', {
      nodes: graphData.nodes.length,
      edges: graphData.edges.length,
      filters: nodesData.filters
    });

    return graphData;
  } catch (err) {
    console.error('Failed to load graph data:', err);
    graphData = { nodes: [], edges: [] };
    return graphData;
  }
}

async function loadFilesAndModules() {
  try {
    var response = await fetch('/api/graph/files');
    if (!response.ok) throw new Error('Failed to load files and modules');
    var data = await response.json();

    availableFiles = data.files || [];
    availableModules = data.modules || [];
    return { files: availableFiles, modules: availableModules };
  } catch (err) {
    console.error('Failed to load files and modules:', err);
    availableFiles = [];
    availableModules = [];
    return { files: [], modules: [] };
  }
}

async function loadCoreMemoryGraphData() {
  try {
    var response = await fetch('/api/core-memory/graph');
    if (!response.ok) throw new Error('Failed to load core memory graph data');
    var data = await response.json();

    graphData = {
      nodes: (data.nodes || []).map(function(node) {
        return {
          id: node.id || node.name,
          name: node.name || node.label || node.id,
          type: node.type || 'MODULE',
          symbolType: node.symbol_type || node.symbolType,
          path: node.path || node.file_path,
          lineNumber: node.line_number || node.lineNumber,
          imports: node.imports || 0,
          exports: node.exports || 0,
          references: node.references || 0
        };
      }),
      edges: (data.edges || []).map(function(edge) {
        return {
          source: edge.source || edge.from,
          target: edge.target || edge.to,
          type: edge.type || edge.relation_type || 'CALLS',
          weight: edge.weight || 1
        };
      })
    };
    return graphData;
  } catch (err) {
    console.error('Failed to load core memory graph data:', err);
    graphData = { nodes: [], edges: [] };
    return graphData;
  }
}

async function loadSearchProcessData() {
  try {
    var response = await fetch('/api/graph/search-process');
    if (!response.ok) throw new Error('Failed to load search process data');
    var data = await response.json();
    searchProcessData = data.searchProcess || null;
    return searchProcessData;
  } catch (err) {
    console.error('Failed to load search process data:', err);
    searchProcessData = null;
    return null;
  }
}

// ========== UI Layout ==========
function renderGraphLayout() {
  return '<div class="graph-explorer-view">' +
    '<div class="graph-explorer-header">' +
    '<h2><i data-lucide="network" class="w-5 h-5"></i> ' + t('graph.title') + '</h2>' +
    '<div class="graph-explorer-tabs">' +
    '<button class="tab-btn ' + (activeTab === 'graph' ? 'active' : '') + '" onclick="switchGraphTab(\'graph\')">' +
    '<i data-lucide="git-branch" class="w-4 h-4"></i> ' + t('graph.codeRelations') +
    '</button>' +
    '<button class="tab-btn ' + (activeTab === 'search' ? 'active' : '') + '" onclick="switchGraphTab(\'search\')">' +
    '<i data-lucide="search" class="w-4 h-4"></i> ' + t('graph.searchProcess') +
    '</button>' +
    '</div>' +
    '</div>' +
    '<div class="graph-explorer-content">' +
    '<div id="graphTab" class="tab-content ' + (activeTab === 'graph' ? 'active' : '') + '">' +
    renderGraphView() +
    '</div>' +
    '<div id="searchTab" class="tab-content ' + (activeTab === 'search' ? 'active' : '') + '">' +
    renderSearchProcessView() +
    '</div>' +
    '</div>' +
    '</div>';
}

function renderGraphView() {
  return '<div class="graph-view">' +
    '<div class="graph-sidebar">' +
    '<div class="graph-controls-section">' +
    '<h3>' + t('graph.filters') + '</h3>' +
    renderFilterDropdowns() +
    '</div>' +
    '<div class="graph-legend-section">' +
    '<h3>' + t('graph.legend') + '</h3>' +
    renderGraphLegend() +
    '</div>' +
    '<div id="nodeDetailsPanel" class="node-details-panel hidden">' +
    '</div>' +
    '</div>' +
    '<div class="graph-main">' +
    '<div class="graph-toolbar">' +
    '<div class="graph-toolbar-left">' +
    '<span class="graph-stats">' +
    '<i data-lucide="circle" class="w-3 h-3"></i> ' +
    graphData.nodes.length + ' ' + t('graph.nodes') +
    '</span>' +
    '<span class="graph-stats">' +
    '<i data-lucide="arrow-right" class="w-3 h-3"></i> ' +
    graphData.edges.length + ' ' + t('graph.edges') +
    '</span>' +
    '<select id="dataSourceSelect" onchange="switchDataSource(this.value)" class="data-source-select">' +
    '<option value="code" ' + (activeDataSource === 'code' ? 'selected' : '') + '>' + t('graph.codeRelations') + '</option>' +
    '<option value="memory" ' + (activeDataSource === 'memory' ? 'selected' : '') + '>' + t('graph.coreMemory') + '</option>' +
    '</select>' +
    '</div>' +
    '<div class="graph-toolbar-right">' +
    '<button class="btn-icon" onclick="fitCytoscape()" title="' + t('graph.fitView') + '">' +
    '<i data-lucide="maximize-2" class="w-4 h-4"></i>' +
    '</button>' +
    '<button class="btn-icon" onclick="centerCytoscape()" title="' + t('graph.center') + '">' +
    '<i data-lucide="crosshair" class="w-4 h-4"></i>' +
    '</button>' +
    '<button class="btn-icon" onclick="resetGraphFilters()" title="' + t('graph.resetFilters') + '">' +
    '<i data-lucide="filter-x" class="w-4 h-4"></i>' +
    '</button>' +
    '<button class="btn-icon" onclick="refreshGraphData()" title="' + t('common.refresh') + '">' +
    '<i data-lucide="refresh-cw" class="w-4 h-4"></i>' +
    '</button>' +
    '</div>' +
    '</div>' +
    '<div id="cytoscapeContainer" class="cytoscape-container"></div>' +
    '</div>' +
    '</div>';
}

function renderFilterDropdowns() {
  return '<div class="filter-dropdowns">' +
    // Scope filter
    '<div class="filter-group scope-filter">' +
    '<label>' + t('graph.scope') + '</label>' +
    '<div class="scope-selector">' +
    '<label class="filter-radio">' +
    '<input type="radio" name="scopeMode" value="all" ' + (filterMode === 'all' ? 'checked' : '') + ' onchange="changeScopeMode(\'all\')">' +
    '<span>' + t('graph.allFiles') + '</span>' +
    '</label>' +
    '<label class="filter-radio">' +
    '<input type="radio" name="scopeMode" value="module" ' + (filterMode === 'module' ? 'checked' : '') + ' onchange="changeScopeMode(\'module\')">' +
    '<span>' + t('graph.byModule') + '</span>' +
    '</label>' +
    '<label class="filter-radio">' +
    '<input type="radio" name="scopeMode" value="file" ' + (filterMode === 'file' ? 'checked' : '') + ' onchange="changeScopeMode(\'file\')">' +
    '<span>' + t('graph.byFile') + '</span>' +
    '</label>' +
    '</div>' +
    // Module selector (shown when filterMode === 'module')
    (filterMode === 'module' ?
      '<select id="moduleSelect" class="filter-select" onchange="selectModule(this.value)">' +
      '<option value="">' + t('graph.selectModule') + '</option>' +
      availableModules.map(function(module) {
        return '<option value="' + escapeHtml(module) + '" ' + (selectedModule === module ? 'selected' : '') + '>' + escapeHtml(module) + '</option>';
      }).join('') +
      '</select>' : '') +
    // File selector (shown when filterMode === 'file')
    (filterMode === 'file' ?
      '<select id="fileSelect" class="filter-select" onchange="selectFile(this.value)">' +
      '<option value="">' + t('graph.selectFile') + '</option>' +
      availableFiles.map(function(file) {
        return '<option value="' + escapeHtml(file) + '" ' + (selectedFile === file ? 'selected' : '') + '>' + escapeHtml(file) + '</option>';
      }).join('') +
      '</select>' : '') +
    '</div>' +
    '<div class="filter-group">' +
    '<label>' + t('graph.nodeTypes') + '</label>' +
    Object.keys(NODE_COLORS).map(function(type) {
      return '<label class="filter-checkbox">' +
        '<input type="checkbox" ' + (nodeFilters[type] ? 'checked' : '') + ' onchange="toggleNodeFilter(\'' + type + '\', this.checked)">' +
        '<span class="filter-color" style="background-color: ' + NODE_COLORS[type] + '"></span>' +
        '<span>' + type + '</span>' +
        '</label>';
    }).join('') +
    '</div>' +
    '<div class="filter-group">' +
    '<label>' + t('graph.edgeTypes') + '</label>' +
    Object.keys(EDGE_COLORS).map(function(type) {
      return '<label class="filter-checkbox">' +
        '<input type="checkbox" ' + (edgeFilters[type] ? 'checked' : '') + ' onchange="toggleEdgeFilter(\'' + type + '\', this.checked)">' +
        '<span class="filter-color" style="background-color: ' + EDGE_COLORS[type] + '"></span>' +
        '<span>' + type + '</span>' +
        '</label>';
    }).join('') +
    '</div>' +
    '</div>';
}

function renderGraphLegend() {
  return '<div class="graph-legend">' +
    '<div class="legend-title">' + t('graph.nodeTypes') + '</div>' +
    Object.keys(NODE_COLORS).map(function(type) {
      return '<div class="legend-item">' +
        '<span class="legend-dot" style="background-color: ' + NODE_COLORS[type] + '"></span>' +
        '<span>' + type + '</span>' +
        '</div>';
    }).join('') +
    '<div class="legend-title" style="margin-top: 1rem;">' + t('graph.edgeTypes') + '</div>' +
    Object.keys(EDGE_COLORS).map(function(type) {
      return '<div class="legend-item">' +
        '<span class="legend-line" style="background-color: ' + EDGE_COLORS[type] + '"></span>' +
        '<span>' + type + '</span>' +
        '</div>';
    }).join('') +
    '</div>';
}

function renderSearchProcessView() {
  if (!searchProcessData) {
    return '<div class="search-process-empty">' +
      '<i data-lucide="search-x" class="w-8 h-8"></i>' +
      '<p>' + t('graph.noSearchData') + '</p>' +
      '</div>';
  }

  return '<div class="search-process-view">' +
    '<div class="search-process-header">' +
    '<h3>' + t('graph.searchProcessTitle') + '</h3>' +
    '<p class="search-process-desc">' + t('graph.searchProcessDesc') + '</p>' +
    '</div>' +
    '<div class="search-process-timeline">' +
    (searchProcessData.steps || []).map(function(step, index) {
      return '<div class="search-step">' +
        '<div class="search-step-number">' + (index + 1) + '</div>' +
        '<div class="search-step-content">' +
        '<h4>' + escapeHtml(step.name || 'Step ' + (index + 1)) + '</h4>' +
        '<p>' + escapeHtml(step.description || '') + '</p>' +
        (step.results ? '<div class="search-step-results">' +
          '<span class="result-count">' + (step.results.length || 0) + ' ' + t('graph.resultsFound') + '</span>' +
          '</div>' : '') +
        '</div>' +
        '</div>';
    }).join('') +
    '</div>' +
    '</div>';
}

// ========== Tab Switching ==========
function switchGraphTab(tab) {
  activeTab = tab;

  // Update tab buttons
  var tabBtns = document.querySelectorAll('.graph-explorer-tabs .tab-btn');
  tabBtns.forEach(function(btn) {
    btn.classList.remove('active');
  });
  event.target.closest('.tab-btn').classList.add('active');

  // Update tab content
  document.getElementById('graphTab').classList.toggle('active', tab === 'graph');
  document.getElementById('searchTab').classList.toggle('active', tab === 'search');

  // Initialize Cytoscape if switching to graph tab
  if (tab === 'graph' && !cyInstance) {
    setTimeout(function() {
      initializeCytoscape();
    }, 100);
  }
}

// ========== Cytoscape.js Integration ==========
function initializeCytoscape() {
  var container = document.getElementById('cytoscapeContainer');
  if (!container) return;

  // Check if Cytoscape.js is loaded
  if (typeof cytoscape === 'undefined') {
    container.innerHTML = '<div class="cytoscape-error">' +
      '<i data-lucide="alert-triangle" class="w-6 h-6"></i>' +
      '<p>' + t('graph.cytoscapeNotLoaded') + '</p>' +
      '</div>';
    if (window.lucide) lucide.createIcons();
    return;
  }

  if (graphData.nodes.length === 0) {
    container.innerHTML = '<div class="cytoscape-empty">' +
      '<i data-lucide="network" class="w-8 h-8"></i>' +
      '<p>' + t('graph.noGraphData') + '</p>' +
      '</div>';
    if (window.lucide) lucide.createIcons();
    return;
  }

  // Transform data for Cytoscape
  var elements = transformDataForCytoscape();

  // Create Cytoscape instance
  cyInstance = cytoscape({
    container: container,
    elements: elements,
    style: getCytoscapeStyles(),
    layout: {
      name: 'cose',
      idealEdgeLength: 180,
      nodeOverlap: 50,
      refresh: 20,
      fit: true,
      padding: 50,
      randomize: false,
      componentSpacing: 150,
      nodeRepulsion: 600000,
      edgeElasticity: 100,
      nestingFactor: 5,
      gravity: 60,
      numIter: 1000,
      initialTemp: 200,
      coolingFactor: 0.95,
      minTemp: 1.0
    },
    minZoom: 0.1,
    maxZoom: 3,
    wheelSensitivity: 0.2
  });

  // Bind events
  cyInstance.on('tap', 'node', function(evt) {
    var node = evt.target;
    selectNode(node.data());
  });

  cyInstance.on('tap', function(evt) {
    if (evt.target === cyInstance) {
      deselectNode();
    }
  });

  // Mouse hover events for nodes
  cyInstance.on('mouseover', 'node', function(evt) {
    var node = evt.target;
    node.addClass('hover');
    // Highlight connected edges
    node.connectedEdges().addClass('hover');
  });

  cyInstance.on('mouseout', 'node', function(evt) {
    var node = evt.target;
    node.removeClass('hover');
    // Remove edge highlights (unless they are highlighted due to selection)
    node.connectedEdges().removeClass('hover');
  });

  // Mouse hover events for edges
  cyInstance.on('mouseover', 'edge', function(evt) {
    var edge = evt.target;
    edge.addClass('hover');
    // Also highlight connected nodes
    edge.source().addClass('hover');
    edge.target().addClass('hover');
  });

  cyInstance.on('mouseout', 'edge', function(evt) {
    var edge = evt.target;
    edge.removeClass('hover');
    // Remove node highlights
    edge.source().removeClass('hover');
    edge.target().removeClass('hover');
  });

  // Fit view after layout
  setTimeout(function() {
    fitCytoscape();
  }, 100);
}

function transformDataForCytoscape() {
  var elements = [];

  // Filter nodes
  var filteredNodes = graphData.nodes.filter(function(node) {
    var type = node.type || 'MODULE';
    return nodeFilters[type];
  });

  // Create node ID set and name-to-id mapping for edge resolution
  var nodeIdSet = new Set();
  var nodeNameToIds = {}; // Map symbol names to their node IDs

  filteredNodes.forEach(function(node) {
    var nodeId = node.id;
    nodeIdSet.add(nodeId);

    // Extract symbol name for matching
    var name = node.name || '';
    if (!nodeNameToIds[name]) {
      nodeNameToIds[name] = [];
    }
    nodeNameToIds[name].push(nodeId);
  });

  // Add nodes
  filteredNodes.forEach(function(node) {
    elements.push({
      group: 'nodes',
      data: {
        id: node.id,
        label: node.name || node.id,
        type: node.type || 'MODULE',
        symbolType: node.symbolType,
        path: node.path || node.file,
        lineNumber: node.lineNumber || node.line,
        imports: node.imports || 0,
        exports: node.exports || 0,
        references: node.references || 0
      }
    });
  });

  // Filter and resolve edges
  var filteredEdges = graphData.edges.filter(function(edge) {
    var type = edge.type || 'CALLS';
    return edgeFilters[type];
  });

  // Process edges with target resolution
  var edgeCount = 0;
  filteredEdges.forEach(function(edge) {
    var sourceId = edge.source;
    var targetId = edge.target;

    // Check if source exists
    if (!nodeIdSet.has(sourceId)) {
      return; // Skip if source node doesn't exist
    }

    // Try to resolve target
    var resolvedTargetId = null;

    // 1. Direct match
    if (nodeIdSet.has(targetId)) {
      resolvedTargetId = targetId;
    }
    // 2. Try to match by qualified name (extract symbol name)
    else if (targetId) {
      // Try to extract symbol name from qualified name
      var targetName = targetId;

      // Handle qualified names like "module.ClassName.methodName" or "file:name:line"
      if (targetId.includes('.')) {
        var parts = targetId.split('.');
        targetName = parts[parts.length - 1]; // Get last part
      } else if (targetId.includes(':')) {
        var colonParts = targetId.split(':');
        if (colonParts.length >= 2) {
          targetName = colonParts[1]; // file:name:line format
        }
      }

      // Look up in name-to-id mapping
      if (nodeNameToIds[targetName] && nodeNameToIds[targetName].length > 0) {
        // If multiple matches, prefer one in the same file
        var sourceFile = edge.sourceFile || '';
        var matchInSameFile = nodeNameToIds[targetName].find(function(id) {
          return id.startsWith(sourceFile);
        });
        resolvedTargetId = matchInSameFile || nodeNameToIds[targetName][0];
      }
    }

    // Only add edge if both source and target are resolved
    if (resolvedTargetId && sourceId !== resolvedTargetId) {
      elements.push({
        group: 'edges',
        data: {
          id: 'edge-' + edgeCount++,
          source: sourceId,
          target: resolvedTargetId,
          type: edge.type || 'CALLS',
          weight: edge.weight || 1
        }
      });
    }
  });

  console.log('[Graph] Transformed elements:', {
    nodes: filteredNodes.length,
    edges: edgeCount,
    totalRawEdges: filteredEdges.length
  });

  return elements;
}

function getCytoscapeStyles() {
  var styles = [
    // Node styles by type - no label by default
    {
      selector: 'node',
      style: {
        'background-color': function(ele) {
          return NODE_COLORS[ele.data('type')] || '#6B7280';
        },
        'label': '',  // No label by default
        'width': function(ele) {
          var refs = ele.data('references') || 0;
          return Math.max(20, Math.min(48, 20 + refs * 1.5));
        },
        'height': function(ele) {
          var refs = ele.data('references') || 0;
          return Math.max(20, Math.min(48, 20 + refs * 1.5));
        },
        'border-width': 2,
        'border-color': function(ele) {
          var color = NODE_COLORS[ele.data('type')] || '#6B7280';
          return darkenColor(color, 20);
        },
        'overlay-padding': 6
      }
    },
    // Hovered node - show label
    {
      selector: 'node.hover',
      style: {
        'label': 'data(label)',
        'text-valign': 'top',
        'text-halign': 'center',
        'text-margin-y': -8,
        'font-size': '11px',
        'font-weight': 'bold',
        'color': '#1f2937',
        'text-outline-color': '#fff',
        'text-outline-width': 2,
        'text-background-color': '#fff',
        'text-background-opacity': 0.9,
        'text-background-padding': '4px',
        'text-background-shape': 'roundrectangle',
        'z-index': 999
      }
    },
    // Selected node - show label
    {
      selector: 'node:selected',
      style: {
        'label': 'data(label)',
        'border-width': 4,
        'border-color': '#000',
        'text-valign': 'top',
        'text-halign': 'center',
        'text-margin-y': -8,
        'font-size': '11px',
        'font-weight': 'bold',
        'color': '#1f2937',
        'text-outline-color': '#fff',
        'text-outline-width': 2,
        'text-background-color': '#fff',
        'text-background-opacity': 0.9,
        'text-background-padding': '4px',
        'text-background-shape': 'roundrectangle',
        'overlay-color': '#000',
        'overlay-opacity': 0.2,
        'z-index': 999
      }
    },
    // Edge styles by type - enhanced visibility
    {
      selector: 'edge',
      style: {
        'width': function(ele) {
          return Math.max(2, (ele.data('weight') || 1) * 1.5);
        },
        'line-color': function(ele) {
          return EDGE_COLORS[ele.data('type')] || '#6B7280';
        },
        'target-arrow-color': function(ele) {
          return EDGE_COLORS[ele.data('type')] || '#6B7280';
        },
        'target-arrow-shape': 'triangle',
        'curve-style': 'bezier',
        'arrow-scale': 1.5,
        'opacity': 0.8,
        'z-index': 1
      }
    },
    // Hovered edge
    {
      selector: 'edge.hover',
      style: {
        'width': 4,
        'opacity': 1,
        'z-index': 100
      }
    },
    // Highlighted edge (connected to selected node)
    {
      selector: 'edge.highlighted',
      style: {
        'width': 3,
        'opacity': 1,
        'z-index': 50
      }
    },
    // Selected edge
    {
      selector: 'edge:selected',
      style: {
        'line-color': '#000',
        'target-arrow-color': '#000',
        'width': 4,
        'opacity': 1,
        'z-index': 100
      }
    }
  ];

  return styles;
}

// Helper function to darken a color
function darkenColor(hex, percent) {
  var num = parseInt(hex.replace('#', ''), 16);
  var amt = Math.round(2.55 * percent);
  var R = Math.max(0, (num >> 16) - amt);
  var G = Math.max(0, ((num >> 8) & 0x00FF) - amt);
  var B = Math.max(0, (num & 0x0000FF) - amt);
  return '#' + (0x1000000 + R * 0x10000 + G * 0x100 + B).toString(16).slice(1);
}

// ========== Node Selection ==========
function selectNode(nodeData) {
  selectedNode = nodeData;

  // Highlight in cytoscape
  if (cyInstance) {
    cyInstance.nodes().removeClass('selected');
    var node = cyInstance.getElementById(nodeData.id);
    if (node) {
      node.addClass('selected');
      // Highlight connected edges
      cyInstance.edges().removeClass('highlighted');
      node.connectedEdges().addClass('highlighted');
    }
  }

  // Show details panel
  var panel = document.getElementById('nodeDetailsPanel');
  if (panel) {
    panel.classList.remove('hidden');
    panel.innerHTML = renderNodeDetails(nodeData);
    if (window.lucide) lucide.createIcons();

    // Attach event listener for impact analysis button (prevents XSS)
    var impactBtn = document.getElementById('impactAnalysisBtn');
    if (impactBtn) {
      impactBtn.addEventListener('click', function() {
        var nodeId = this.getAttribute('data-node-id');
        if (nodeId) showImpactAnalysis(nodeId);
      });
    }
  }
}

function deselectNode() {
  selectedNode = null;

  // Remove highlights
  if (cyInstance) {
    cyInstance.nodes().removeClass('selected');
    cyInstance.edges().removeClass('highlighted');
  }

  // Hide details panel
  var panel = document.getElementById('nodeDetailsPanel');
  if (panel) {
    panel.classList.add('hidden');
  }
}

function renderNodeDetails(node) {
  var typeIcon = node.type === 'MODULE' ? 'package' :
                 node.type === 'CLASS' ? 'box' :
                 node.type === 'FUNCTION' ? 'code' :
                 node.type === 'METHOD' ? 'code-2' :
                 'variable';

  return '<div class="node-details-content">' +
    '<div class="node-details-header">' +
    '<h4><i data-lucide="' + typeIcon + '" class="w-4 h-4"></i> ' + escapeHtml(node.label || node.id) + '</h4>' +
    '<button class="btn-icon btn-sm" onclick="deselectNode()" title="' + t('common.close') + '">' +
    '<i data-lucide="x" class="w-3 h-3"></i>' +
    '</button>' +
    '</div>' +
    '<div class="node-details-meta">' +
    '<div class="meta-item">' +
    '<span class="meta-label">' + t('graph.type') + '</span>' +
    '<span class="meta-value">' + (node.type || 'MODULE') + '</span>' +
    '</div>' +
    (node.symbolType ? '<div class="meta-item">' +
      '<span class="meta-label">' + t('graph.symbolType') + '</span>' +
      '<span class="meta-value">' + escapeHtml(node.symbolType) + '</span>' +
      '</div>' : '') +
    (node.path ? '<div class="meta-item">' +
      '<span class="meta-label">' + t('graph.path') + '</span>' +
      '<span class="meta-value path-value">' + escapeHtml(node.path) + '</span>' +
      '</div>' : '') +
    (node.lineNumber ? '<div class="meta-item">' +
      '<span class="meta-label">' + t('graph.line') + '</span>' +
      '<span class="meta-value">' + node.lineNumber + '</span>' +
      '</div>' : '') +
    '</div>' +
    '<div class="node-details-stats">' +
    '<div class="stat-item">' +
    '<i data-lucide="download" class="w-3 h-3"></i>' +
    '<span>' + (node.imports || 0) + ' ' + t('graph.imports') + '</span>' +
    '</div>' +
    '<div class="stat-item">' +
    '<i data-lucide="upload" class="w-3 h-3"></i>' +
    '<span>' + (node.exports || 0) + ' ' + t('graph.exports') + '</span>' +
    '</div>' +
    '<div class="stat-item">' +
    '<i data-lucide="link" class="w-3 h-3"></i>' +
    '<span>' + (node.references || 0) + ' ' + t('graph.references') + '</span>' +
    '</div>' +
    '</div>' +
    '<div class="node-details-actions">' +
    '<button class="btn btn-sm btn-primary" id="impactAnalysisBtn" data-node-id="' + escapeHtml(node.id) + '">' +
    '<i data-lucide="target" class="w-3 h-3"></i> ' + t('graph.impactAnalysis') +
    '</button>' +
    '</div>' +
    '</div>';
}

// ========== Filter Actions ==========
function toggleNodeFilter(type, checked) {
  nodeFilters[type] = checked;
  refreshCytoscape();
}

function toggleEdgeFilter(type, checked) {
  edgeFilters[type] = checked;
  refreshCytoscape();
}

function resetGraphFilters() {
  // Reset all filters to true
  Object.keys(nodeFilters).forEach(function(key) {
    nodeFilters[key] = true;
  });
  Object.keys(edgeFilters).forEach(function(key) {
    edgeFilters[key] = true;
  });

  // Update checkboxes
  var checkboxes = document.querySelectorAll('.filter-checkbox input[type="checkbox"]');
  checkboxes.forEach(function(cb) {
    cb.checked = true;
  });

  refreshCytoscape();
}

function refreshCytoscape() {
  if (!cyInstance) return;

  var elements = transformDataForCytoscape();
  cyInstance.elements().remove();
  cyInstance.add(elements);
  cyInstance.layout({
    name: 'cose',
    idealEdgeLength: 180,
    nodeOverlap: 50,
    refresh: 20,
    fit: true,
    padding: 50,
    componentSpacing: 150,
    nodeRepulsion: 600000,
    gravity: 60
  }).run();

  deselectNode();
}

// ========== Cytoscape Controls ==========
function fitCytoscape() {
  if (cyInstance) {
    cyInstance.fit(null, 50);
  }
}

function centerCytoscape() {
  if (cyInstance) {
    cyInstance.center();
  }
}

// ========== Impact Analysis ==========
async function showImpactAnalysis(symbolId) {
  try {
    var response = await fetch('/api/graph/impact?symbol=' + encodeURIComponent(symbolId));
    if (!response.ok) throw new Error('Failed to fetch impact analysis');
    var data = await response.json();

    // Show modal with impact analysis results
    showImpactModal(data.impact);
  } catch (err) {
    console.error('Failed to fetch impact analysis:', err);
    if (window.showToast) {
      showToast(t('graph.impactAnalysisError'), 'error');
    }
  }
}

function showImpactModal(impact) {
  var modal = document.createElement('div');
  modal.className = 'modal-overlay';
  modal.innerHTML = '<div class="modal-container">' +
    '<div class="modal-header">' +
    '<h3><i data-lucide="target" class="w-4 h-4"></i> ' + t('graph.impactAnalysis') + '</h3>' +
    '<button class="btn-icon" onclick="closeImpactModal()">' +
    '<i data-lucide="x" class="w-4 h-4"></i>' +
    '</button>' +
    '</div>' +
    '<div class="modal-body">' +
    '<div class="impact-summary">' +
    '<div class="impact-stat">' +
    '<span class="impact-stat-value">' + (impact.affectedFiles || 0) + '</span>' +
    '<span class="impact-stat-label">' + t('graph.affectedFiles') + '</span>' +
    '</div>' +
    '<div class="impact-stat">' +
    '<span class="impact-stat-value">' + (impact.affectedSymbols || 0) + '</span>' +
    '<span class="impact-stat-label">' + t('graph.affectedSymbols') + '</span>' +
    '</div>' +
    '<div class="impact-stat">' +
    '<span class="impact-stat-value">' + (impact.depth || 0) + '</span>' +
    '<span class="impact-stat-label">' + t('graph.depth') + '</span>' +
    '</div>' +
    '</div>' +
    (impact.files && impact.files.length > 0 ? '<div class="impact-files">' +
      '<h4>' + t('graph.affectedFiles') + '</h4>' +
      '<div class="impact-files-list">' +
      impact.files.map(function(file) {
        return '<div class="impact-file-item">' +
          '<i data-lucide="file" class="w-3 h-3"></i>' +
          '<span>' + escapeHtml(file) + '</span>' +
          '</div>';
      }).join('') +
      '</div>' +
      '</div>' : '') +
    '</div>' +
    '<div class="modal-footer">' +
    '<button class="btn btn-secondary" onclick="closeImpactModal()">' + t('common.close') + '</button>' +
    '</div>' +
    '</div>';

  document.body.appendChild(modal);
  if (window.lucide) lucide.createIcons();

  // Close on overlay click
  modal.addEventListener('click', function(e) {
    if (e.target === modal) {
      closeImpactModal();
    }
  });
}

function closeImpactModal() {
  var modal = document.querySelector('.modal-overlay');
  if (modal) {
    modal.remove();
  }
}

// ========== Data Source Switching ==========
async function switchDataSource(source) {
  activeDataSource = source;

  // Show loading state
  var container = document.getElementById('cytoscapeContainer');
  if (container) {
    container.innerHTML = '<div class="cytoscape-empty">' +
      '<i data-lucide="loader-2" class="w-8 h-8 animate-spin"></i>' +
      '<p>' + t('common.loading') + '</p>' +
      '</div>';
    if (window.lucide) lucide.createIcons();
  }

  // Load data based on source
  if (source === 'memory') {
    await loadCoreMemoryGraphData();
  } else {
    await loadGraphData();
  }

  // Update stats display
  updateGraphStats();

  // Reinitialize Cytoscape with new data
  if (cyInstance) {
    cyInstance.destroy();
    cyInstance = null;
  }
  initializeCytoscape();

  // Show toast notification
  if (window.showToast) {
    var sourceName = source === 'memory' ? t('graph.coreMemory') : t('graph.codeRelations');
    showToast(t('graph.dataSourceSwitched') + ': ' + sourceName, 'success');
  }
}

// ========== Data Refresh ==========
async function refreshGraphData() {
  if (window.showToast) {
    showToast(t('common.refreshing'), 'info');
  }

  // Show loading state in container
  var container = document.getElementById('cytoscapeContainer');
  if (container) {
    container.innerHTML = '<div class="cytoscape-empty">' +
      '<i data-lucide="loader-2" class="w-8 h-8 animate-spin"></i>' +
      '<p>' + t('common.loading') + '</p>' +
      '</div>';
    if (window.lucide) lucide.createIcons();
  }

  // Load data based on source
  if (activeDataSource === 'memory') {
    await loadCoreMemoryGraphData();
  } else {
    await loadGraphData();
  }

  // Update stats display
  updateGraphStats();

  // Reinitialize Cytoscape with new data
  if (cyInstance) {
    cyInstance.destroy();
    cyInstance = null;
  }

  if (activeTab === 'graph') {
    initializeCytoscape();
  }

  if (window.showToast) {
    showToast(t('common.refreshed'), 'success');
  }
}

// Update graph statistics display
function updateGraphStats() {
  var statsSpans = document.querySelectorAll('.graph-stats');
  if (statsSpans.length >= 2) {
    statsSpans[0].innerHTML = '<i data-lucide="circle" class="w-3 h-3"></i> ' +
      graphData.nodes.length + ' ' + t('graph.nodes');
    statsSpans[1].innerHTML = '<i data-lucide="arrow-right" class="w-3 h-3"></i> ' +
      graphData.edges.length + ' ' + t('graph.edges');
    if (window.lucide) lucide.createIcons();
  }
}

// ========== Utility ==========
function hideStatsAndCarousel() {
  var statsGrid = document.getElementById('statsGrid');
  var carousel = document.getElementById('carouselContainer');
  if (statsGrid) statsGrid.style.display = 'none';
  if (carousel) carousel.style.display = 'none';
}

// ========== Cleanup Function ==========
/**
 * Clean up Cytoscape instance to prevent memory leaks
 * Should be called when navigating away from the graph explorer view
 */
function cleanupGraphExplorer() {
  if (cyInstance) {
    cyInstance.destroy();
    cyInstance = null;
  }
  selectedNode = null;
  searchProcessData = null;
}

// ========== Scope Filter Actions ==========
async function changeScopeMode(mode) {
  console.log('[Graph] Changing scope mode to:', mode);
  filterMode = mode;
  selectedFile = null;
  selectedModule = null;

  // Re-render the filter panel
  var sidebar = document.querySelector('.graph-sidebar');
  if (sidebar) {
    var controlsSection = sidebar.querySelector('.graph-controls-section');
    if (controlsSection) {
      controlsSection.innerHTML = '<h3>' + t('graph.filters') + '</h3>' + renderFilterDropdowns();
      if (window.lucide) lucide.createIcons();
    }
  }

  // If mode is 'all', reload graph immediately
  if (mode === 'all') {
    await refreshGraphData();
  }
}

async function selectModule(modulePath) {
  console.log('[Graph] Selecting module:', modulePath);
  selectedModule = modulePath;
  if (modulePath) {
    await refreshGraphData();
  }
}

async function selectFile(filePath) {
  console.log('[Graph] Selecting file:', filePath);
  selectedFile = filePath;
  if (filePath) {
    await refreshGraphData();
  }
}

// Register cleanup on navigation (called by navigation.js before switching views)
if (typeof window !== 'undefined') {
  window.cleanupGraphExplorer = cleanupGraphExplorer;
}
