/**
 * Unified Visualize Page - Schema Visualization
 * Supports both RDF (Turtle, N-Triples) and UML (Mermaid, PlantUML, GraphViz) formats
 */

import React, { useState, useCallback, useRef, useEffect, useMemo } from 'react';
import { useDatabase } from '@/hooks/useDatabase';
import { useRdfParser } from '@/hooks/useRdfParser';
import { useGraphData } from '@/hooks/useGraphData';
import { ForceDirectedGraph, type RdfLayoutType } from '@/components/visualizations/ForceDirectedGraph';
import { RdfAdvancedLayout, type RdfAdvancedLayoutType } from '@/components/rdf/RdfLayouts';
import { GraphControls } from '@/components/visualizations/GraphControls';
import { RdfNodeDetailsPanel } from '@/components/rdf/RdfNodeDetailsPanel';
import { UMLVisualization } from '@/components/uml/UMLVisualization';
import { parseUMLDiagramWithDetails } from '@/components/uml/UMLParser';
import { useLanguage } from '../contexts/LanguageContext';
import { useFullscreen } from '../hooks/useCollapsibleHeader';
import type { GraphNode, GraphLink } from '@/types/rdf';
import type { UMLDiagram, DagreDirection, DagreRanker, LayoutType, ElkAlgorithm } from '@/components/uml/UMLVisualization';
import { 
  Menu, X, Download, Image, FileCode, Code, ChevronDown, Upload, FileText, RefreshCw, Database, Maximize, Minimize, HelpCircle, LayoutGrid
} from 'lucide-react';
import './Visualize.css';
import '../styles/collapsible.css';

// Mobile detection and swipe gesture constants
const SWIPE_THRESHOLD = 50; // Minimum distance for a swipe
const EDGE_ZONE = 30; // Pixels from left edge to start swipe

/**
 * Map UML layout types to RDF layout types
 * UML has more options (dagre variants, elk), we map them to simpler RDF equivalents
 */
function mapToRdfLayout(layoutType: LayoutType, dagreDirection?: DagreDirection): RdfLayoutType {
  switch (layoutType) {
    case 'force':
      return 'force';
    case 'dagre':
      // Map dagre directions to hierarchical layouts
      return dagreDirection === 'LR' || dagreDirection === 'RL' 
        ? 'hierarchical-lr' 
        : 'hierarchical-tb';
    case 'elk':
      // ELK is similar to dagre, use hierarchical TB
      return 'hierarchical-tb';
    case 'circular':
      return 'circular';
    case 'radial':
      return 'radial';
    case 'clustered':
      // Clustered layout - use circular as closest approximation for RDF
      return 'circular';
    default:
      return 'force';
  }
}

// Check if a layout type is an advanced RDF layout
function isAdvancedRdfLayout(layout: string): layout is RdfAdvancedLayoutType {
  return ['chord', 'radial-tree', 'sankey', 'edge-bundling', 'pack', 'tree', 'sunburst'].includes(layout);
}

type UmlDensityMode = 'full' | 'streamlined' | 'module';
type UmlModuleOption = { id: string; label: string; count: number };

function humanizeModuleName(moduleId: string): string {
  return moduleId
    .replace(/_/g, ' ')
    .replace(/\b\w/g, (c) => c.toUpperCase());
}

function buildStreamlinedUmlDiagram(diagram: UMLDiagram): UMLDiagram {
  if (!diagram || !diagram.nodes || !diagram.links) {
    return diagram;
  }

  const nodeCount = diagram.nodes.length;
  if (nodeCount <= 300) {
    return diagram;
  }

  const degree = new Map<string, number>();
  diagram.nodes.forEach((node) => degree.set(node.id, 0));

  diagram.links.forEach((link) => {
    if (!degree.has(link.source) || !degree.has(link.target)) return;
    degree.set(link.source, (degree.get(link.source) || 0) + 1);
    degree.set(link.target, (degree.get(link.target) || 0) + 1);
  });

  const threshold = nodeCount > 1200 ? 3 : nodeCount > 600 ? 2 : 1;
  const keepIds = new Set<string>();

  degree.forEach((d, id) => {
    if (d >= threshold) keepIds.add(id);
  });

  const coreAnchors = ['Custodian', 'CustodianType', 'Organization', 'Person'];
  coreAnchors.forEach((id) => {
    if (degree.has(id)) keepIds.add(id);
  });

  const nodes = diagram.nodes.filter((node) => keepIds.has(node.id));
  const links = diagram.links.filter((link) => keepIds.has(link.source) && keepIds.has(link.target));

  if (nodes.length < 50) {
    return diagram;
  }

  return {
    ...diagram,
    nodes,
    links,
  };
}

function buildModuleFocusedUmlDiagram(diagram: UMLDiagram, moduleId: string): UMLDiagram {
  if (!diagram || !diagram.nodes || !diagram.links) {
    return diagram;
  }

  if (!moduleId || moduleId === '__all__') {
    return diagram;
  }

  const primaryNodes = diagram.nodes.filter((node) => (node.module || 'other') === moduleId);
  if (primaryNodes.length === 0) {
    return diagram;
  }

  const keepIds = new Set<string>(primaryNodes.map((n) => n.id));

  // Include one-hop neighbors for context around the selected module.
  diagram.links.forEach((link) => {
    if (keepIds.has(link.source)) keepIds.add(link.target);
    if (keepIds.has(link.target)) keepIds.add(link.source);
  });

  let nodes = diagram.nodes.filter((node) => keepIds.has(node.id));
  let links = diagram.links.filter((link) => keepIds.has(link.source) && keepIds.has(link.target));

  // If the result is still too small, keep only direct module internals.
  if (nodes.length < 20) {
    const primaryIds = new Set(primaryNodes.map((n) => n.id));
    nodes = primaryNodes;
    links = diagram.links.filter((link) => primaryIds.has(link.source) && primaryIds.has(link.target));
  }

  return {
    ...diagram,
    nodes,
    links,
  };
}

// Bilingual text object for translations
const TEXT = {
  // Sidebar
  schemaVisualization: { nl: 'Schemavisualisatie', en: 'Schema Visualization' },
  heritageOntology: { nl: 'Erfgoedbewaarders-ontologie', en: 'Heritage Custodian Ontology' },
  openSidebar: { nl: 'Zijbalk openen', en: 'Open sidebar' },
  closeSidebar: { nl: 'Zijbalk sluiten', en: 'Close sidebar' },
  
  // Load section
  loadData: { nl: 'Data laden', en: 'Load Data' },
  uploadFile: { nl: 'Bestand uploaden', en: 'Upload File' },
  fileHint: { nl: 'RDF: .ttl, .nt, .jsonld | UML: .mmd, .puml, .dot', en: 'RDF: .ttl, .nt, .jsonld | UML: .mmd, .puml, .dot' },
  orPasteDirectly: { nl: 'of plak direct', en: 'or paste directly' },
  pastePlaceholder: { nl: 'Plak Turtle, N-Triples, Mermaid, PlantUML of GraphViz code...', en: 'Paste Turtle, N-Triples, Mermaid, PlantUML, or GraphViz code...' },
  visualize: { nl: 'Visualiseren', en: 'Visualize' },
  
  // Generate section
  generateVisualizations: { nl: 'Visualisaties genereren', en: 'Generate Visualizations' },
  generate: { nl: 'Genereren', en: 'Generate' },
  umlDiagram: { nl: 'UML Diagram', en: 'UML Diagram' },
  generateFromLinkML: { nl: 'Genereren vanuit LinkML-schema (Erfgoedbewaarders-ontologie)', en: 'Generate from LinkML schema (Heritage Custodian Ontology)' },
  generating: { nl: 'Bezig met genereren...', en: 'Generating...' },
  generateUml: { nl: 'Genereer UML', en: 'Generate UML' },
  rdfOverview: { nl: 'RDF Overzicht', en: 'RDF Overview' },
  generateRdfDesc: { nl: 'Genereer RDF grafiek van alle erfgoedbewaarders', en: 'Generate RDF graph of all heritage custodians' },
  comingSoon: { nl: 'Binnenkort beschikbaar', en: 'Coming Soon' },
  comingSoonHint: { nl: 'Beschikbaar na conversie van verrijkte records naar instanties', en: 'Available after converting enriched entries to instances' },
  refreshUml: { nl: 'UML Vernieuwen', en: 'Refresh UML' },
  refreshRdf: { nl: 'RDF Vernieuwen', en: 'Refresh RDF' },
  refreshHint: { nl: 'Haal de nieuwste versie op', en: 'Fetch the latest version' },
  umlDensity: { nl: 'UML Weergavemodus', en: 'UML Display Mode' },
  umlDensityDesc: { nl: 'Kies tussen volledig en gestroomlijnd overzicht', en: 'Choose between full and streamlined overview' },
  umlModeFull: { nl: 'Volledig', en: 'Full' },
  umlModeFullHint: { nl: 'Toon alle klassen en relaties', en: 'Show all classes and relationships' },
  umlModeStreamlined: { nl: 'Gestroomlijnd', en: 'Streamlined' },
  umlModeStreamlinedHint: { nl: 'Toon de belangrijkste, meest verbonden klassen', en: 'Show key, high-connectivity classes' },
  umlModeModule: { nl: 'Module Focus', en: 'Module Focus' },
  umlModeModuleHint: { nl: 'Toon een domein met context', en: 'Show one domain with context' },
  umlModuleSelect: { nl: 'Module', en: 'Module' },
  umlModuleAll: { nl: 'Alle modules', en: 'All modules' },
  umlShowingClasses: { nl: 'klassen zichtbaar', en: 'classes visible' },
  
  // View switcher
  viewUml: { nl: 'UML Weergave', en: 'UML View' },
  viewRdf: { nl: 'RDF Weergave', en: 'RDF View' },
  switchToUml: { nl: 'Schakel naar UML diagram', en: 'Switch to UML diagram' },
  switchToRdf: { nl: 'Schakel naar RDF grafiek', en: 'Switch to RDF graph' },
  
  // Current file section
  loaded: { nl: 'Geladen', en: 'Loaded' },
  rdfGraph: { nl: 'RDF Grafiek', en: 'RDF Graph' },
  
  // Storage info
  storageInfo: { nl: 'Opslag Info', en: 'Storage Info' },
  used: { nl: 'Gebruikt', en: 'Used' },
  available: { nl: 'Beschikbaar', en: 'Available' },
  usage: { nl: 'Gebruik', en: 'Usage' },
  
  // RDF Query Limit
  queryLimit: { nl: 'Query Limiet', en: 'Query Limit' },
  queryLimitDesc: { nl: 'Aantal custodians om te laden', en: 'Number of custodians to load' },
  showingOf: { nl: 'van', en: 'of' },
  custodiansAvailable: { nl: 'beschikbaar', en: 'available' },
  performanceWarning: { nl: '⚠️ Meer dan 1000 kan traag zijn', en: '⚠️ More than 1000 may be slow' },
  
  // RDF Query Mode
  queryMode: { nl: 'Query Modus', en: 'Query Mode' },
  queryModeDesc: { nl: 'Selecteer hoe data wordt opgehaald', en: 'Select how data is fetched' },
  queryModeDetailed: { nl: 'Gedetailleerd (standaard)', en: 'Detailed (default)' },
  queryModeDetailedHint: { nl: 'Specifieke eigenschappen, sneller', en: 'Specific properties, faster' },
  queryModeGeneric: { nl: 'Generiek (alle relaties)', en: 'Generic (all relations)' },
  queryModeGenericHint: { nl: 'Alle triples, meer connectiviteit', en: 'All triples, more connectivity' },
  queryModeCustom: { nl: 'Aangepaste query...', en: 'Custom query...' },
  queryModeCustomHint: { nl: 'Open Query Builder', en: 'Open Query Builder' },
  
  // Selected node
  selectedNode: { nl: 'Geselecteerd knooppunt', en: 'Selected Node' },
  id: { nl: 'ID', en: 'ID' },
  type: { nl: 'Type', en: 'Type' },
  label: { nl: 'Label', en: 'Label' },
  properties: { nl: 'Eigenschappen', en: 'Properties' },
  noProperties: { nl: 'Geen eigenschappen beschikbaar', en: 'No properties available' },
  clearSelection: { nl: 'Selectie wissen', en: 'Clear Selection' },
  
  // Hover info
  hoverInfo: { nl: 'Hover Info', en: 'Hover Info' },
  
  // Toolbar
  fit: { nl: 'Passend', en: 'Fit' },
  fitToScreen: { nl: 'Passend op scherm', en: 'Fit to screen' },
  zoomIn: { nl: 'Inzoomen', en: 'Zoom in' },
  zoomOut: { nl: 'Uitzoomen', en: 'Zoom out' },
  resetView: { nl: 'Weergave resetten', en: 'Reset view' },
  layout: { nl: 'Layout', en: 'Layout' },
  export: { nl: 'Exporteren', en: 'Export' },
  
  // Layout options
  forceLayout: { nl: 'Force-layout', en: 'Force Layout' },
  forceDesc: { nl: 'Op fysica gebaseerd, organisch', en: 'Physics-based, organic' },
  gridLayoutOptions: { nl: 'Grid-layoutopties', en: 'Grid Layout Options' },
  hierarchicalTB: { nl: 'Hiërarchisch (Boven→Onder)', en: 'Hierarchical (Top→Bottom)' },
  hierarchicalTBDesc: { nl: 'Klassieke UML stijl', en: 'Classic UML style' },
  hierarchicalLR: { nl: 'Hiërarchisch (Links→Rechts)', en: 'Hierarchical (Left→Right)' },
  hierarchicalLRDesc: { nl: 'Stroomdiagram stijl', en: 'Flowchart style' },
  adaptiveTightTree: { nl: 'Adaptief (Compact)', en: 'Adaptive (Tight Tree)' },
  adaptiveTightTreeDesc: { nl: 'Compacte ordening', en: 'Compact arrangement' },
  adaptiveLongestPath: { nl: 'Adaptief (Langste Pad)', en: 'Adaptive (Longest Path)' },
  adaptiveLongestPathDesc: { nl: 'Diepe hiërarchieën', en: 'Deep hierarchies' },
  // New layout options
  advancedLayoutOptions: { nl: 'Geavanceerde layouts', en: 'Advanced Layouts' },
  elkLayered: { nl: 'ELK gelaagd', en: 'ELK Layered' },
  elkLayeredDesc: { nl: 'Eclipse Layout Kernel – orthogonaal', en: 'Eclipse Layout Kernel - orthogonal edges' },
  elkTree: { nl: 'ELK boom', en: 'ELK Tree' },
  elkTreeDesc: { nl: 'Boomstructuurlayout', en: 'Tree structure layout' },
  circular: { nl: 'Circulair', en: 'Circular' },
  circularDesc: { nl: 'Knooppunten in een cirkel', en: 'Nodes arranged in a circle' },
  radial: { nl: 'Radiaal', en: 'Radial' },
  radialDesc: { nl: 'Boom vanuit centrum', en: 'Tree radiating from center' },
  clustered: { nl: 'Gegroepeerd', en: 'Clustered' },
  clusteredDesc: { nl: 'Groepeer klassen per module', en: 'Group classes by module' },
  layoutHelp: { nl: 'Meer over layouts', en: 'Learn about layouts' },
  
  // RDF-specific advanced layouts
  rdfAdvancedLayouts: { nl: 'RDF Geavanceerde Layouts', en: 'RDF Advanced Layouts' },
  chordDiagram: { nl: 'Chord Diagram', en: 'Chord Diagram' },
  chordDiagramDesc: { nl: 'Relaties tussen knooppunttypes', en: 'Relationships between node types' },
  radialTreeLayout: { nl: 'Radiale Boom', en: 'Radial Tree' },
  radialTreeLayoutDesc: { nl: 'Hiërarchie vanuit centraal knooppunt', en: 'Hierarchy from central node' },
  edgeBundling: { nl: 'Edge Bundling', en: 'Edge Bundling' },
  edgeBundlingDesc: { nl: 'Gebundelde verbindingspatronen', en: 'Bundled connection patterns' },
  packLayout: { nl: 'Cirkel Packing', en: 'Circle Packing' },
  packLayoutDesc: { nl: 'Geneste cirkels per type', en: 'Nested circles by type' },
  sunburstLayout: { nl: 'Sunburst', en: 'Sunburst' },
  sunburstLayoutDesc: { nl: 'Hiërarchische partitie', en: 'Hierarchical partition view' },
  
  // Export options
  exportAsPng: { nl: 'Exporteer als PNG', en: 'Export as PNG' },
  exportAsSvg: { nl: 'Exporteer als SVG', en: 'Export as SVG' },
  downloadSource: { nl: 'Broncode downloaden', en: 'Download Source' },
  
  // Loading/Error states
  loading: { nl: 'Laden...', en: 'Loading...' },
  error: { nl: 'Fout', en: 'Error' },
  
  // Welcome message
  readyToVisualize: { nl: 'Klaar om te visualiseren', en: 'Ready to Visualize' },
  welcomeDesc: { nl: 'Upload een schemabestand, plak code, of selecteer uit de beschikbare schema\'s om te beginnen.', en: 'Upload a schema file, paste code, or select from Available Schemas to get started.' },
  supportedFormats: { nl: 'Ondersteunde formaten:', en: 'Supported Formats:' },
  features: { nl: 'Mogelijkheden:', en: 'Features:' },
  featureInteractive: { nl: 'Interactieve grafiekvisualisatie', en: 'Interactive graph visualization' },
  featureLayouts: { nl: 'Meerdere layout-opties (force, hiërarchisch, adaptief)', en: 'Multiple layout options (force, hierarchical, adaptive)' },
  featureFilter: { nl: 'Filteren op knooppunttypes en predicaten', en: 'Filter by node types and predicates' },
  featureExport: { nl: 'Exporteer als PNG, SVG of broncode', en: 'Export as PNG, SVG, or source' },
  featureDrag: { nl: 'Versleep knooppunten om te herordenen', en: 'Drag nodes to reorganize' },
  featureClick: { nl: 'Klik op knooppunten voor details', en: 'Click nodes to see details' },
  
  // View source
  viewSourceCode: { nl: 'Broncode bekijken', en: 'View Source Code' },
};

// File type definitions
type SchemaFormat = 'turtle' | 'n-triples' | 'jsonld' | 'mermaid' | 'erdiagram' | 'plantuml' | 'graphviz';

// Detect format from file extension
function detectFormat(filename: string): { format: SchemaFormat; category: 'rdf' | 'uml' } {
  const ext = filename.toLowerCase().split('.').pop() || '';
  
  switch (ext) {
    case 'ttl':
      return { format: 'turtle', category: 'rdf' };
    case 'nt':
      return { format: 'n-triples', category: 'rdf' };
    case 'jsonld':
    case 'json':
      return { format: 'jsonld', category: 'rdf' };
    case 'mmd':
      return { format: 'mermaid', category: 'uml' };
    case 'puml':
      return { format: 'plantuml', category: 'uml' };
    case 'dot':
    case 'gv':
      return { format: 'graphviz', category: 'uml' };
    default:
      // Default to turtle for unknown
      return { format: 'turtle', category: 'rdf' };
  }
}

// Detect format from content (for paste input)
function detectFormatFromContent(content: string): { format: SchemaFormat; category: 'rdf' | 'uml' } {
  const trimmed = content.trim();
  
  // UML detection
  if (trimmed.startsWith('classDiagram') || trimmed.startsWith('erDiagram') || 
      trimmed.startsWith('graph ') || trimmed.startsWith('flowchart')) {
    return { format: 'mermaid', category: 'uml' };
  }
  if (trimmed.startsWith('@startuml') || trimmed.includes('@enduml')) {
    return { format: 'plantuml', category: 'uml' };
  }
  if (trimmed.startsWith('digraph') || trimmed.startsWith('graph') || trimmed.startsWith('strict')) {
    return { format: 'graphviz', category: 'uml' };
  }
  
  // RDF detection
  if (trimmed.startsWith('@prefix') || trimmed.startsWith('@base') || 
      trimmed.includes('^^xsd:') || trimmed.includes('@en')) {
    return { format: 'turtle', category: 'rdf' };
  }
  if (trimmed.startsWith('<') && trimmed.includes('> <') && trimmed.includes('> .')) {
    return { format: 'n-triples', category: 'rdf' };
  }
  if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
    return { format: 'jsonld', category: 'rdf' };
  }
  
  // Default to turtle
  return { format: 'turtle', category: 'rdf' };
}

// Session storage key for preserving state across navigation
const VISUALIZE_STATE_KEY = 'visualize-page-state';

interface PersistedState {
  fileName: string;
  currentCategory: 'rdf' | 'uml' | null;
  umlFileContent: string;
  umlDiagram: UMLDiagram | null;
  // Cached state for both views
  hasUmlCache: boolean;
  hasRdfCache: boolean;
  rdfNodeCount: number;
}

function saveStateToSession(state: PersistedState) {
  try {
    sessionStorage.setItem(VISUALIZE_STATE_KEY, JSON.stringify(state));
  } catch (e) {
    console.warn('Failed to save visualize state to sessionStorage:', e);
  }
}

function loadStateFromSession(): PersistedState | null {
  try {
    const stored = sessionStorage.getItem(VISUALIZE_STATE_KEY);
    if (stored) {
      return JSON.parse(stored);
    }
  } catch (e) {
    console.warn('Failed to load visualize state from sessionStorage:', e);
  }
  return null;
}

export function Visualize() {
  // Language hook
  const { language } = useLanguage();
  const t = (key: keyof typeof TEXT) => TEXT[key][language];

  // Load persisted state on mount
  const persistedState = useRef<PersistedState | null>(null);
  if (persistedState.current === null) {
    persistedState.current = loadStateFromSession();
  }

  // File and format state
  const [fileName, setFileName] = useState<string>(persistedState.current?.fileName || '');
  const [currentCategory, setCurrentCategory] = useState<'rdf' | 'uml' | null>(persistedState.current?.currentCategory || null);
  const [loadSectionExpanded, setLoadSectionExpanded] = useState<boolean>(false);
  const [customInput, setCustomInput] = useState<string>('');
  const [sidebarOpen, setSidebarOpen] = useState<boolean>(true);
  const [isHeaderCollapsed, setIsHeaderCollapsed] = useState<boolean>(false);
  
  // Mobile detection and swipe gesture state
  const [isMobile, setIsMobile] = useState<boolean>(false);
  const touchStartX = useRef<number>(0);
  const touchStartY = useRef<number>(0);
  const touchStartedInEdge = useRef<boolean>(false);
  const sidebarRef = useRef<HTMLElement>(null);
  const overlayRef = useRef<HTMLDivElement>(null);
  
  // Fullscreen support
  const mainContentRef = useRef<HTMLDivElement>(null);
  const { isFullscreen, toggleFullscreen } = useFullscreen(mainContentRef);
  
  // UML-specific state
  const [umlDiagram, setUmlDiagram] = useState<UMLDiagram | null>(persistedState.current?.umlDiagram || null);
  const [umlFileContent, setUmlFileContent] = useState<string>(persistedState.current?.umlFileContent || '');
  
  // Layout state
  const [layoutType, setLayoutType] = useState<LayoutType>(() => {
    const saved = localStorage.getItem('visualize-layout-type');
    return (saved === 'dagre' || saved === 'force' || saved === 'elk' || saved === 'circular' || saved === 'radial') ? saved : 'force';
  });
  const [dagreDirection, setDagreDirection] = useState<DagreDirection>(() => {
    const saved = localStorage.getItem('visualize-dagre-direction');
    return (saved === 'TB' || saved === 'BT' || saved === 'LR' || saved === 'RL') ? saved : 'TB';
  });
  const [dagreRanker, setDagreRanker] = useState<DagreRanker>(() => {
    const saved = localStorage.getItem('visualize-dagre-ranker');
    return (saved === 'network-simplex' || saved === 'tight-tree' || saved === 'longest-path') ? saved : 'network-simplex';
  });
  const [elkAlgorithm, setElkAlgorithm] = useState<ElkAlgorithm>(() => {
    const saved = localStorage.getItem('visualize-elk-algorithm');
    return (saved === 'layered' || saved === 'mrtree' || saved === 'force' || saved === 'stress') ? saved : 'layered';
  });
  
  // RDF-specific advanced layout state
  const [rdfAdvancedLayout, setRdfAdvancedLayout] = useState<RdfAdvancedLayoutType | null>(() => {
    const saved = localStorage.getItem('visualize-rdf-advanced-layout');
    if (saved && isAdvancedRdfLayout(saved)) {
      return saved;
    }
    return null;
  });

  const [umlDensityMode, setUmlDensityMode] = useState<UmlDensityMode>(() => {
    const saved = localStorage.getItem('visualize-uml-density-mode');
    return (saved === 'streamlined' || saved === 'module') ? saved : 'full';
  });
  const [selectedUmlModule, setSelectedUmlModule] = useState<string>(() => {
    return localStorage.getItem('visualize-uml-module') || '__all__';
  });
  
  // Dropdown state
  const [exportDropdownOpen, setExportDropdownOpen] = useState<boolean>(false);
  const [layoutDropdownOpen, setLayoutDropdownOpen] = useState<boolean>(false);
  const exportDropdownRef = useRef<HTMLDivElement>(null);
  const layoutDropdownRef = useRef<HTMLDivElement>(null);
  
  // Cache tracking - both views can be loaded simultaneously
  const [hasUmlCache, setHasUmlCache] = useState<boolean>(persistedState.current?.hasUmlCache || false);
  const [hasRdfCache, setHasRdfCache] = useState<boolean>(persistedState.current?.hasRdfCache || false);
  const [rdfNodeCount, setRdfNodeCount] = useState<number>(persistedState.current?.rdfNodeCount || 0);
  
  // RDF query limit - default to 500 to prevent browser overload
  // Oxigraph contains 27,000+ custodians; rendering all at once crashes the browser
  const [rdfLimit, setRdfLimit] = useState<number>(() => {
    const saved = localStorage.getItem('visualize-rdf-limit');
    return saved ? parseInt(saved, 10) : 500;
  });
  const [totalCustodiansAvailable, setTotalCustodiansAvailable] = useState<number | null>(null);
  
  // Track the limit that was used for the current cached data
  const cachedRdfLimitRef = useRef<number | null>(null);
  
  // Prevent duplicate RDF fetch requests (React StrictMode protection)
  const rdfFetchInProgressRef = useRef<boolean>(false);
  
  // RDF Query Mode - allows switching between detailed (limited properties) and generic (all triples)
  type RdfQueryMode = 'detailed' | 'generic' | 'custom';
  const [rdfQueryMode, setRdfQueryMode] = useState<RdfQueryMode>(() => {
    const saved = localStorage.getItem('visualize-rdf-query-mode');
    return (saved === 'detailed' || saved === 'generic' || saved === 'custom') ? saved : 'detailed';
  });
  
  // Track the mode used for cached data (to show Apply button when changed)
  const cachedRdfQueryModeRef = useRef<RdfQueryMode | null>(null);
  
  // Hooks
  const { isInitialized, isLoading: dbLoading, storageInfo } = useDatabase();
  const { parse, isLoading: parserLoading, error: parserError } = useRdfParser();
  const {
    nodes,
    links,
    filteredNodes,
    filteredLinks,
    nodeTypes,
    predicates,
    filters,
    setFilters,
    resetFilters,
    selectedNode,
    setSelectedNode,
    loadGraphData,
    stats,
  } = useGraphData();

  // Combined loading state
  const [umlLoading, setUmlLoading] = useState(false);
  const [umlError, setUmlError] = useState<string | null>(null);
  const isLoading = dbLoading || parserLoading || umlLoading;

  // Generator state
  const [generatingUml, setGeneratingUml] = useState(false);
  const [_generatingRdf, setGeneratingRdf] = useState(false);

  // Clear current visualization
  const clearVisualization = useCallback(() => {
    setUmlDiagram(null);
    setUmlFileContent('');
    setUmlError(null);
    // Reset RDF graph data would require loadGraphData with empty result
  }, []);

  // Load UML content
  const loadUmlContent = useCallback(
    (content: string, name: string) => {
      clearVisualization();
      setCurrentCategory('uml');
      setUmlLoading(true);
      setUmlError(null);
      
      // Auto-select dagre (Grid) layout for UML diagrams
      setLayoutType('dagre');
      localStorage.setItem('visualize-layout-type', 'dagre');
      
      try {
        const result = parseUMLDiagramWithDetails(content);
        
        if (result.error) {
          throw new Error(result.error);
        }
        
        if (!result.diagram) {
          throw new Error('Failed to parse diagram. No diagram data returned.');
        }
        
        // Log warnings if any
        if (result.warnings.length > 0) {
          console.warn('[Visualize] Parse warnings:', result.warnings);
        }
        
        setUmlFileContent(content);
        setUmlDiagram({
          ...result.diagram,
          title: name
        });
      } catch (err) {
        console.error('Error parsing UML:', err);
        setUmlError(err instanceof Error ? err.message : 'Unknown error occurred');
        setUmlDiagram(null);
      } finally {
        setUmlLoading(false);
      }
    },
    [clearVisualization]
  );

  // Generate UML from LinkML schema (fetches pre-generated file)
  const handleGenerateUml = useCallback(async () => {
    setGeneratingUml(true);
    setUmlError(null);
    
    try {
      // Fetch the pre-generated Mermaid file from public folder
      const response = await fetch('/data/heritage_custodian_ontology.mmd');
      
      if (!response.ok) {
        throw new Error(`Failed to load UML diagram: ${response.statusText}`);
      }
      
      const mermaidContent = await response.text();
      
      if (mermaidContent) {
        setFileName('Heritage Custodian Ontology (Generated)');
        loadUmlContent(mermaidContent, 'Heritage Custodian Ontology');
        setHasUmlCache(true);
        setCurrentCategory('uml');
      } else {
        throw new Error('No Mermaid diagram content found');
      }
    } catch (err) {
      console.error('Error loading UML:', err);
      setUmlError(err instanceof Error ? err.message : 'Failed to load UML diagram');
    } finally {
      setGeneratingUml(false);
    }
  }, [loadUmlContent]);

  // Generate RDF overview - Fetch and visualize all heritage custodian RDF data
  const handleGenerateRdf = useCallback(async () => {
    // Prevent duplicate concurrent fetches (React StrictMode protection)
    if (rdfFetchInProgressRef.current) {
      console.log('[RDF] Fetch already in progress, skipping duplicate request');
      return;
    }
    
    rdfFetchInProgressRef.current = true;
    setGeneratingRdf(true);
    // Don't clear UML visualization - we want to keep both cached
    setCurrentCategory('rdf');
    setFileName('NDE Heritage Custodians');
    
    // Auto-select force layout for RDF graphs
    setLayoutType('force');
    localStorage.setItem('visualize-layout-type', 'force');
    
    try {
      // Determine SPARQL endpoint URL
      // In production (bronhouder.nl), use relative URL which Caddy proxies to Oxigraph
      // In development (localhost), use direct Oxigraph URL
      const isLocalhost = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
      const sparqlEndpoint = isLocalhost 
        ? (import.meta.env.VITE_SPARQL_ENDPOINT || 'http://localhost:7878/query')
        : '/query';  // Always use relative URL in production
      
      // First, get total count of custodians available (for UI display)
      const countQuery = `
        PREFIX nde: <https://nde.nl/ontology/hc/class/>
        SELECT (COUNT(?s) as ?count) WHERE { ?s a nde:Custodian }
      `;
      
      try {
        const countResponse = await fetch(sparqlEndpoint, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/sparql-query',
            'Accept': 'application/sparql-results+json',
          },
          body: countQuery,
        });
        
        if (countResponse.ok) {
          const countResult = await countResponse.json();
          const total = parseInt(countResult.results?.bindings?.[0]?.count?.value || '0', 10);
          setTotalCustodiansAvailable(total);
          console.log(`Total custodians in Oxigraph: ${total}`);
        }
      } catch (countErr) {
        console.warn('Could not fetch custodian count:', countErr);
      }
      
      // SPARQL query - conditional based on rdfQueryMode
      // - detailed: Specific properties only (faster, less connectivity)
      // - generic: All triples for custodians (slower, full connectivity)
      let constructQuery: string;
      
      if (rdfQueryMode === 'generic') {
        // Generic query: Returns ALL triples for custodians
        // This provides maximum connectivity in the graph but may be slower
        console.log('Using GENERIC query mode - fetching all triples');
        constructQuery = `
          PREFIX nde: <https://nde.nl/ontology/hc/class/>
          
          CONSTRUCT { ?s ?p ?o }
          WHERE {
            {
              # All triples where custodian is subject
              ?s a nde:Custodian .
              ?s ?p ?o .
            }
            UNION
            {
              # All triples where custodian is object (incoming links)
              ?o a nde:Custodian .
              ?s ?p ?o .
            }
          }
          LIMIT ${rdfLimit * 10}
        `;
        // Note: Higher limit because generic query returns more triples per custodian
      } else {
        // Detailed query: Specific properties only (default)
        // Namespaces match the Python sync scripts:
        // - nde: <https://nde.nl/ontology/hc/class/> for Custodian type
        // - hc: <https://w3id.org/heritage/custodian/> for ghcid, isil predicates
        // - hp: <https://w3id.org/heritage/person/> for person URIs
        console.log('Using DETAILED query mode - specific properties');
        constructQuery = `
          PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
          PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
          PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
          PREFIX schema: <http://schema.org/>
          PREFIX foaf: <http://xmlns.com/foaf/0.1/>
          PREFIX owl: <http://www.w3.org/2002/07/owl#>
          PREFIX org: <http://www.w3.org/ns/org#>
          PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
          PREFIX cidoc: <http://www.cidoc-crm.org/cidoc-crm/>
          PREFIX nde: <https://nde.nl/ontology/hc/class/>
          PREFIX hc: <https://w3id.org/heritage/custodian/>
          PREFIX hp: <https://w3id.org/heritage/person/>

          CONSTRUCT {
            # Custodians - core data
            ?custodian a nde:Custodian ;
              rdfs:label ?label ;
              skos:prefLabel ?prefLabel ;
              schema:name ?name ;
              hc:ghcid ?ghcid ;
              hc:isil ?isil ;
              schema:url ?website ;
              foaf:homepage ?homepage ;
              owl:sameAs ?wikidata .
            
            # Location (schema:location, not crm:P53)
            ?custodian schema:location ?location .
            ?location geo:lat ?lat ;
              geo:long ?lon .
            
            # Persons linked to custodians
            ?person a schema:Person ;
              rdfs:label ?personLabel ;
              schema:name ?personName ;
              schema:worksFor ?custodian ;
              org:memberOf ?custodian ;
              schema:jobTitle ?jobTitle .
          }
          WHERE {
            # Get all custodians (nde:Custodian is the primary type)
            ?custodian a nde:Custodian .
            OPTIONAL { ?custodian rdfs:label ?label }
            OPTIONAL { ?custodian skos:prefLabel ?prefLabel }
            OPTIONAL { ?custodian schema:name ?name }
            OPTIONAL { ?custodian hc:ghcid ?ghcid }
            OPTIONAL { ?custodian hc:isil ?isil }
            OPTIONAL { ?custodian schema:url ?website }
            OPTIONAL { ?custodian foaf:homepage ?homepage }
            OPTIONAL { 
              ?custodian owl:sameAs ?wikidata . 
              FILTER(STRSTARTS(STR(?wikidata), "http://www.wikidata.org/"))
            }
            
            # Location using schema:location (as generated by oxigraph_sync.py)
            OPTIONAL {
              ?custodian schema:location ?location .
              OPTIONAL { ?location geo:lat ?lat }
              OPTIONAL { ?location geo:long ?lon }
            }
            
            # Persons linked to custodians via schema:worksFor
            OPTIONAL {
              ?person a schema:Person ;
                schema:worksFor ?custodian .
              OPTIONAL { ?person rdfs:label ?personLabel }
              OPTIONAL { ?person schema:name ?personName }
              OPTIONAL { ?person schema:jobTitle ?jobTitle }
              OPTIONAL { ?person org:memberOf ?custodian }
            }
          }
          LIMIT ${rdfLimit}
        `;
      }
      
      let rdfData = '';
      let dataFormat: 'application/n-triples' | 'text/turtle' = 'application/n-triples';
      
      try {
        // Request N-Triples format - simpler to parse than Turtle
        // Oxigraph's abbreviated Turtle syntax is hard to parse correctly
        console.log('Fetching from SPARQL endpoint:', sparqlEndpoint);
        const response = await fetch(sparqlEndpoint, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/sparql-query',
            'Accept': 'application/n-triples',
          },
          body: constructQuery,
        });
        
        if (response.ok) {
          rdfData = await response.text();
          console.log(`SPARQL returned ${rdfData.length} bytes, ${rdfData.split('\n').length} lines`);
        } else {
          console.warn('SPARQL response not OK:', response.status, response.statusText);
        }
      } catch (fetchErr) {
        console.warn('SPARQL endpoint not available:', fetchErr);
      }
      
      // Fallback: try to load from pre-built static file (Turtle format)
      if (!rdfData || rdfData.trim().length === 0) {
        console.log('Attempting to load from static file...');
        const staticResponse = await fetch('/data/nde_heritage_custodians.ttl');
        
        if (staticResponse.ok) {
          rdfData = await staticResponse.text();
          dataFormat = 'text/turtle'; // Static file is Turtle, not N-Triples
          console.log('Loaded from static file (Turtle format)');
        }
      }
      
      if (!rdfData || rdfData.trim().length === 0) {
        throw new Error(
          'No RDF data available.\n\n' +
          'Options:\n' +
          '1. Run Oxigraph locally with the NDE data\n' +
          '2. Place nde_heritage_custodians.ttl in public/data/'
        );
      }
      
      // Parse the RDF data (format depends on source)
      console.log(`Parsing ${rdfData.length} bytes as ${dataFormat}`);
      const result = await parse(rdfData, dataFormat);
      console.log(`Parsed: ${result.nodes.length} nodes, ${result.links.length} links`);
      loadGraphData(result);
      
      // Show ALL node types by default - no random filtering
      // Users can filter down using the sidebar controls if needed
      if (result.nodes.length > 0) {
        // Extract unique node types from the result
        const uniqueTypes = new Set(result.nodes.map(n => n.type));
        const typesArray = Array.from(uniqueTypes);
        
        // Set filter to show ALL types by default
        setFilters({ nodeTypes: new Set(typesArray) });
        
        console.log(`RDF loaded: showing all ${result.nodes.length} nodes across ${typesArray.length} types: ${typesArray.join(', ')}`);
      }
      
      // Update cache state and track the limit and mode used
      setHasRdfCache(true);
      setRdfNodeCount(result.nodes.length);
      cachedRdfLimitRef.current = rdfLimit;  // Remember which limit was used for this cache
      cachedRdfQueryModeRef.current = rdfQueryMode;  // Remember which mode was used
      
      // Update filename with count and mode indicator
      const modeLabel = rdfQueryMode === 'generic' ? 'all triples' : 'detailed';
      setFileName(`NDE Heritage Custodians (${result.nodes.length} entities, ${modeLabel})`);
      
    } catch (err) {
      console.error('Error generating RDF overview:', err);
      setUmlError(
        err instanceof Error 
          ? `Failed to load RDF data: ${err.message}`
          : 'Failed to load RDF data'
      );
    } finally {
      setGeneratingRdf(false);
      rdfFetchInProgressRef.current = false;  // Allow new fetches
    }
  }, [rdfLimit, rdfQueryMode, parse, loadGraphData]);

  // Close dropdowns when clicking outside
  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (exportDropdownRef.current && !exportDropdownRef.current.contains(event.target as Node)) {
        setExportDropdownOpen(false);
      }
      if (layoutDropdownRef.current && !layoutDropdownRef.current.contains(event.target as Node)) {
        setLayoutDropdownOpen(false);
      }
    };

    document.addEventListener('mousedown', handleClickOutside);
    return () => document.removeEventListener('mousedown', handleClickOutside);
  }, []);

  // Persist state to sessionStorage whenever relevant state changes
  useEffect(() => {
    saveStateToSession({
      fileName,
      currentCategory,
      umlFileContent,
      umlDiagram,
      hasUmlCache,
      hasRdfCache,
      rdfNodeCount,
    });
  }, [fileName, currentCategory, umlFileContent, umlDiagram, hasUmlCache, hasRdfCache, rdfNodeCount]);

  // Mobile detection and sidebar state management
  useEffect(() => {
    const checkMobile = () => {
      const mobile = window.innerWidth <= 900;
      setIsMobile(mobile);
      // On mobile, sidebar starts closed
      if (mobile) {
        setSidebarOpen(false);
      }
    };
    
    checkMobile();
    window.addEventListener('resize', checkMobile);
    return () => window.removeEventListener('resize', checkMobile);
  }, []);

  // Swipe gesture handling for mobile sidebar
  useEffect(() => {
    if (!isMobile) return;
    
    const handleTouchStart = (e: TouchEvent) => {
      const touch = e.touches[0];
      touchStartX.current = touch.clientX;
      touchStartY.current = touch.clientY;
      
      // Check if touch started in the left edge zone (for opening)
      // or if sidebar is open (for closing)
      touchStartedInEdge.current = touch.clientX <= EDGE_ZONE || sidebarOpen;
    };
    
    const handleTouchMove = (e: TouchEvent) => {
      if (!touchStartedInEdge.current) return;
      
      const touch = e.touches[0];
      const deltaX = touch.clientX - touchStartX.current;
      const deltaY = touch.clientY - touchStartY.current;
      
      // Only consider horizontal swipes (more horizontal than vertical)
      if (Math.abs(deltaX) > Math.abs(deltaY)) {
        // Prevent scroll during horizontal swipe
        if (Math.abs(deltaX) > 10) {
          e.preventDefault();
        }
      }
    };
    
    const handleTouchEnd = (e: TouchEvent) => {
      if (!touchStartedInEdge.current) return;
      
      const touch = e.changedTouches[0];
      const deltaX = touch.clientX - touchStartX.current;
      const deltaY = touch.clientY - touchStartY.current;
      
      // Only consider horizontal swipes
      if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > SWIPE_THRESHOLD) {
        if (deltaX > 0 && !sidebarOpen) {
          // Swipe right - open sidebar
          setSidebarOpen(true);
        } else if (deltaX < 0 && sidebarOpen) {
          // Swipe left - close sidebar
          setSidebarOpen(false);
        }
      }
      
      touchStartedInEdge.current = false;
    };
    
    document.addEventListener('touchstart', handleTouchStart, { passive: true });
    document.addEventListener('touchmove', handleTouchMove, { passive: false });
    document.addEventListener('touchend', handleTouchEnd, { passive: true });
    
    return () => {
      document.removeEventListener('touchstart', handleTouchStart);
      document.removeEventListener('touchmove', handleTouchMove);
      document.removeEventListener('touchend', handleTouchEnd);
    };
  }, [isMobile, sidebarOpen]);

  // Load RDF content
  const loadRdfContent = useCallback(
    async (content: string, format: 'turtle' | 'n-triples' | 'jsonld') => {
      clearVisualization();
      setCurrentCategory('rdf');
      
      const mimeType = format === 'turtle' ? 'text/turtle' : 
                       format === 'n-triples' ? 'application/n-triples' :
                       'application/ld+json';
      
      const result = await parse(content, mimeType);
      loadGraphData(result);
    },
    [parse, loadGraphData, clearVisualization]
  );

  // Handle file upload (unified)
  const handleFileUpload = useCallback(
    async (event: React.ChangeEvent<HTMLInputElement>) => {
      const file = event.target.files?.[0];
      if (!file) return;

      console.log('[Visualize] File upload triggered:', file.name);
      setFileName(file.name);
      const { format, category } = detectFormat(file.name);
      
      const reader = new FileReader();
      reader.onload = async (e) => {
        const content = e.target?.result as string;
        console.log('[Visualize] File read complete, content length:', content.length);
        
        try {
          if (category === 'rdf') {
            await loadRdfContent(content, format as 'turtle' | 'n-triples' | 'jsonld');
          } else {
            loadUmlContent(content, file.name);
          }
        } catch (err) {
          console.error('Failed to parse file:', err);
        }
      };
      reader.readAsText(file);
      
      // Reset the input value to allow re-uploading the same file
      event.target.value = '';
    },
    [loadRdfContent, loadUmlContent]
  );

  // Handle custom input (paste)
  const handleLoadCustomInput = useCallback(async () => {
    if (!customInput.trim()) return;
    
    const { format, category } = detectFormatFromContent(customInput);
    setFileName('Custom Input');
    
    try {
      if (category === 'rdf') {
        await loadRdfContent(customInput, format as 'turtle' | 'n-triples' | 'jsonld');
      } else {
        loadUmlContent(customInput, 'Custom Diagram');
      }
      setLoadSectionExpanded(false);
    } catch (err) {
      console.error('Failed to parse custom input:', err);
    }
  }, [customInput, loadRdfContent, loadUmlContent]);

  // Handle node click (RDF)
  const handleNodeClick = useCallback(
    (node: GraphNode) => {
      setSelectedNode(node);
    },
    [setSelectedNode]
  );

  // Handle link click (RDF)
  const handleLinkClick = useCallback(
    (link: GraphLink) => {
      const sourceNode = filteredNodes.find((n) => n.id === link.source);
      if (sourceNode) {
        setSelectedNode(sourceNode);
      }
    },
    [filteredNodes, setSelectedNode]
  );

  // Hovered node state (RDF)
  const [hoveredNode, setHoveredNode] = useState<GraphNode | null>(null);

  // Export handlers
  const handleExportPNG = () => {
    if (currentCategory === 'uml') {
      const event = new CustomEvent('uml-export-png', { 
        detail: { filename: fileName.replace(/[^a-z0-9]/gi, '_').toLowerCase() || 'diagram' }
      });
      window.dispatchEvent(event);
    }
    // TODO: Add RDF graph PNG export
    setExportDropdownOpen(false);
  };

  const handleExportSVG = () => {
    if (currentCategory === 'uml') {
      const event = new CustomEvent('uml-export-svg', { 
        detail: { filename: fileName.replace(/[^a-z0-9]/gi, '_').toLowerCase() || 'diagram' }
      });
      window.dispatchEvent(event);
    }
    // TODO: Add RDF graph SVG export
    setExportDropdownOpen(false);
  };

  const handleDownloadSource = () => {
    const content = currentCategory === 'uml' ? umlFileContent : '';
    if (!content) return;
    
    const blob = new Blob([content], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `${fileName.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.txt`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
    setExportDropdownOpen(false);
  };

  // Layout selection handler
  const selectLayout = (type: LayoutType, direction?: DagreDirection, ranker?: DagreRanker, elkAlg?: ElkAlgorithm) => {
    setLayoutType(type);
    localStorage.setItem('visualize-layout-type', type);
    
    // Clear RDF advanced layout when selecting a basic layout
    setRdfAdvancedLayout(null);
    localStorage.removeItem('visualize-rdf-advanced-layout');
    
    if (direction) {
      setDagreDirection(direction);
      localStorage.setItem('visualize-dagre-direction', direction);
    }
    if (ranker) {
      setDagreRanker(ranker);
      localStorage.setItem('visualize-dagre-ranker', ranker);
    }
    if (elkAlg) {
      setElkAlgorithm(elkAlg);
      localStorage.setItem('visualize-elk-algorithm', elkAlg);
    }
    setLayoutDropdownOpen(false);
  };

  // RDF Advanced layout selection handler
  const selectRdfAdvancedLayout = (layout: RdfAdvancedLayoutType) => {
    setRdfAdvancedLayout(layout);
    localStorage.setItem('visualize-rdf-advanced-layout', layout);
    setLayoutDropdownOpen(false);
  };

  // View switching handlers - switch between cached UML and RDF views
  const handleSwitchToUml = useCallback(() => {
    if (!hasUmlCache) {
      // No cache, generate it
      handleGenerateUml();
    } else {
      // Switch to cached UML view
      setCurrentCategory('uml');
      setLayoutType('dagre');
      localStorage.setItem('visualize-layout-type', 'dagre');
    }
  }, [hasUmlCache, handleGenerateUml]);

  const handleSwitchToRdf = useCallback(() => {
    // Check if we have cache AND it was fetched with the current limit setting
    const cacheValid = hasRdfCache && cachedRdfLimitRef.current === rdfLimit;
    
    if (!cacheValid) {
      // No cache, or limit has changed - fetch fresh data
      handleGenerateRdf();
    } else {
      // Switch to cached RDF view
      setCurrentCategory('rdf');
      setLayoutType('force');
      localStorage.setItem('visualize-layout-type', 'force');
    }
  }, [hasRdfCache, rdfLimit, handleGenerateRdf]);

  // Check if we have content to display
  const hasRdfContent = filteredNodes.length > 0;
  const hasUmlContent = umlDiagram !== null;
  const hasContent = hasRdfContent || hasUmlContent;

  const umlModuleOptions = useMemo<UmlModuleOption[]>(() => {
    if (!umlDiagram) return [];
    const counts = new Map<string, number>();
    umlDiagram.nodes.forEach((node) => {
      const moduleId = node.module || 'other';
      counts.set(moduleId, (counts.get(moduleId) || 0) + 1);
    });

    const options: UmlModuleOption[] = [{ id: '__all__', label: t('umlModuleAll'), count: umlDiagram.nodes.length }];
    const sorted = Array.from(counts.entries()).sort((a, b) => {
      if (b[1] !== a[1]) return b[1] - a[1];
      return a[0].localeCompare(b[0]);
    });

    sorted.forEach(([id, count]) => {
      options.push({ id, label: humanizeModuleName(id), count });
    });

    return options;
  }, [umlDiagram, t]);

  useEffect(() => {
    if (!umlModuleOptions.length) return;
    if (umlModuleOptions.some((option) => option.id === selectedUmlModule)) return;

    setSelectedUmlModule('__all__');
    localStorage.setItem('visualize-uml-module', '__all__');
  }, [umlModuleOptions, selectedUmlModule]);

  const displayUmlDiagram = useMemo(() => {
    if (!umlDiagram) return null;
    if (umlDensityMode === 'streamlined') {
      return buildStreamlinedUmlDiagram(umlDiagram);
    }
    if (umlDensityMode === 'module') {
      return buildModuleFocusedUmlDiagram(umlDiagram, selectedUmlModule);
    }
    return umlDiagram;
  }, [umlDiagram, umlDensityMode, selectedUmlModule]);

  return (
    <div className={`visualize-page ${isFullscreen ? 'fullscreen-active' : ''} ${isMobile ? 'is-mobile' : ''}`}>
      {/* Mobile overlay when sidebar is open */}
      {isMobile && sidebarOpen && (
        <div 
          className="sidebar-overlay"
          ref={overlayRef}
          onClick={() => setSidebarOpen(false)}
          aria-hidden="true"
        />
      )}
      
      {/* Sidebar Collapse Toggle (when collapsed) */}
      {!sidebarOpen && (
        <button 
          className={`sidebar-toggle ${isMobile ? 'sidebar-toggle--mobile' : ''}`}
          onClick={() => setSidebarOpen(true)}
          aria-label={t('openSidebar')}
        >
          <Menu size={20} />
        </button>
      )}

      {/* Sidebar */}
      <aside 
        className={`sidebar ${!sidebarOpen ? 'collapsed' : ''} ${isMobile ? 'sidebar--mobile' : ''}`}
        ref={sidebarRef}
      >
        {/* Header */}
        <div className={`sidebar-header collapsible-header ${isHeaderCollapsed ? 'collapsible-header--collapsed' : ''}`}>
          <div className="sidebar-header-content">
            <h2>{t('schemaVisualization')}</h2>
            <p className="sidebar-subtitle">{t('heritageOntology')}</p>
          </div>
          <button 
            className="sidebar-collapse-button"
            onClick={() => setSidebarOpen(false)}
            aria-label={t('closeSidebar')}
          >
            <X size={18} />
          </button>
        </div>

        {/* Header Toggle Button */}
        <button 
          className="header-toggle-bar"
          onClick={() => setIsHeaderCollapsed(!isHeaderCollapsed)}
          title={isHeaderCollapsed ? (language === 'nl' ? 'Toon koptekst' : 'Show header') : (language === 'nl' ? 'Verberg koptekst' : 'Hide header')}
        >
          {isHeaderCollapsed ? '▼' : '▲'} {isHeaderCollapsed ? (language === 'nl' ? 'Koptekst tonen' : 'Show header') : (language === 'nl' ? 'Koptekst verbergen' : 'Hide header')}
        </button>

        {/* Load Data Section */}
        <div className="load-section">
          <button 
            className="load-header"
            onClick={() => setLoadSectionExpanded(!loadSectionExpanded)}
          >
            <Upload size={16} />
            <span>{t('loadData')}</span>
            <ChevronDown 
              size={16} 
              className={`load-chevron ${loadSectionExpanded ? 'expanded' : ''}`} 
            />
          </button>
          
          {loadSectionExpanded && (
            <div className="load-content">
              <div className="load-file">
                <label htmlFor="file-upload-input" className="load-file-label">
                  <FileText size={16} />
                  <span>{t('uploadFile')}</span>
                </label>
                <input
                  id="file-upload-input"
                  type="file"
                  accept=".ttl,.nt,.jsonld,.json,.mmd,.puml,.dot,.gv"
                  onChange={handleFileUpload}
                  className="load-file-input"
                  disabled={isLoading}
                />
                <p className="load-hint">{t('fileHint')}</p>
              </div>
              
              <div className="load-divider">
                <span>{t('orPasteDirectly')}</span>
              </div>
              
              <textarea
                className="load-textarea"
                placeholder={t('pastePlaceholder')}
                value={customInput}
                onChange={(e) => setCustomInput(e.target.value)}
                rows={6}
              />
              
              <button 
                className="load-button"
                onClick={handleLoadCustomInput}
                disabled={!customInput.trim() || isLoading}
              >
                {t('visualize')}
              </button>
            </div>
          )}
        </div>

        {/* Generate Section */}
        <div className="generate-section">
          {/* View Switcher - Toggle between UML and RDF */}
          <div className="view-switcher">
            <button 
              className={`view-switch-button ${currentCategory === 'uml' ? 'view-switch-button--active' : ''}`}
              onClick={handleSwitchToUml}
              disabled={generatingUml}
              title={t('switchToUml')}
            >
              <LayoutGrid size={16} />
              <span>UML</span>
              {hasUmlCache && <span className="cache-indicator">●</span>}
            </button>
            <button 
              className={`view-switch-button ${currentCategory === 'rdf' ? 'view-switch-button--active' : ''}`}
              onClick={handleSwitchToRdf}
              disabled={_generatingRdf}
              title={t('switchToRdf')}
            >
              <Database size={16} />
              <span>RDF</span>
              {hasRdfCache && <span className="cache-indicator">●</span>}
              {hasRdfCache && rdfNodeCount > 0 && <span className="node-count">{rdfNodeCount}</span>}
            </button>
          </div>
          
          {/* Generate Button - simple button based on current view */}
          <button 
            className="generate-button-simple"
            onClick={currentCategory === 'uml' ? handleGenerateUml : handleGenerateRdf}
            disabled={generatingUml || _generatingRdf}
            title={currentCategory === 'uml' ? t('refreshUml') : t('refreshRdf')}
          >
            {(generatingUml || _generatingRdf) ? (
              <>
                <RefreshCw size={16} className="spinning" />
                {t('generating')}
              </>
            ) : (
              <>
                <RefreshCw size={16} />
                {currentCategory === 'uml' ? t('refreshUml') : t('refreshRdf')}
              </>
            )}
          </button>
        </div>

        {/* Current File */}
        {fileName && (
          <div className="current-file-section">
            <h3>{t('loaded')}</h3>
            <p className="current-file-name">{fileName}</p>
            <span className="current-file-type">
              {currentCategory === 'rdf' ? t('rdfGraph') : t('umlDiagram')}
            </span>
          </div>
        )}

        {/* Database Status (RDF only) */}
        {isInitialized && storageInfo && currentCategory === 'rdf' && (
          <div className="status-section">
            <h3>{t('storageInfo')}</h3>
            <p><strong>{t('used')}:</strong> {storageInfo.usageInMB}</p>
            <p><strong>{t('available')}:</strong> {storageInfo.quotaInMB}</p>
            <p><strong>{t('usage')}:</strong> {storageInfo.percentUsed}</p>
          </div>
        )}

        {/* RDF Query Limit Control */}
        {currentCategory === 'rdf' && (
          <div className="query-limit-section">
            <h3>{t('queryLimit')}</h3>
            <p className="query-limit-desc">{t('queryLimitDesc')}</p>
            <select 
              className="query-limit-select"
              value={rdfLimit}
              onChange={(e) => {
                const newLimit = parseInt(e.target.value, 10);
                setRdfLimit(newLimit);
                localStorage.setItem('visualize-rdf-limit', String(newLimit));
                // Invalidate cache so next view switch triggers refresh
                // User will need to click "Refresh RDF" or switch away and back
              }}
            >
              <option value="100">100</option>
              <option value="250">250</option>
              <option value="500">500</option>
              <option value="1000">1,000</option>
              <option value="2000">2,000</option>
              <option value="5000">5,000</option>
              <option value="10000">10,000</option>
              <option value="50000">All (50,000+)</option>
            </select>
            {/* Show refresh prompt if limit changed from cached value */}
            {hasRdfCache && cachedRdfLimitRef.current !== null && cachedRdfLimitRef.current !== rdfLimit && (
              <button 
                className="query-limit-refresh-button"
                onClick={handleGenerateRdf}
                disabled={_generatingRdf}
              >
                <RefreshCw size={14} />
                {language === 'nl' ? 'Toepassen' : 'Apply'}
              </button>
            )}
            {totalCustodiansAvailable && (
              <p className="query-limit-info">
                {rdfNodeCount > 0 ? rdfNodeCount : rdfLimit} {t('showingOf')} {totalCustodiansAvailable.toLocaleString()} {t('custodiansAvailable')}
              </p>
            )}
            {rdfLimit > 1000 && (
              <p className="query-limit-warning">{t('performanceWarning')}</p>
            )}
            
            {/* Query Mode Selector */}
            <div className="query-mode-subsection">
              <h4>{t('queryMode')}</h4>
              <p className="query-mode-desc">{t('queryModeDesc')}</p>
              <div className="query-mode-options">
                <label className={`query-mode-option ${rdfQueryMode === 'detailed' ? 'active' : ''}`}>
                  <input
                    type="radio"
                    name="queryMode"
                    value="detailed"
                    checked={rdfQueryMode === 'detailed'}
                    onChange={() => {
                      setRdfQueryMode('detailed');
                      localStorage.setItem('visualize-rdf-query-mode', 'detailed');
                    }}
                  />
                  <div className="query-mode-content">
                    <span className="query-mode-label">{t('queryModeDetailed')}</span>
                    <span className="query-mode-hint">{t('queryModeDetailedHint')}</span>
                  </div>
                </label>
                <label className={`query-mode-option ${rdfQueryMode === 'generic' ? 'active' : ''}`}>
                  <input
                    type="radio"
                    name="queryMode"
                    value="generic"
                    checked={rdfQueryMode === 'generic'}
                    onChange={() => {
                      setRdfQueryMode('generic');
                      localStorage.setItem('visualize-rdf-query-mode', 'generic');
                    }}
                  />
                  <div className="query-mode-content">
                    <span className="query-mode-label">{t('queryModeGeneric')}</span>
                    <span className="query-mode-hint">{t('queryModeGenericHint')}</span>
                  </div>
                </label>
                <label 
                  className="query-mode-option query-mode-custom"
                  onClick={(e) => {
                    e.preventDefault();
                    window.open('/query-builder', '_blank');
                  }}
                >
                  <div className="query-mode-content">
                    <span className="query-mode-label">{t('queryModeCustom')}</span>
                    <span className="query-mode-hint">{t('queryModeCustomHint')}</span>
                  </div>
                  <span className="query-mode-external-icon">↗</span>
                </label>
              </div>
              {/* Show Apply button if mode changed from cached value */}
              {hasRdfCache && cachedRdfQueryModeRef.current !== null && cachedRdfQueryModeRef.current !== rdfQueryMode && (
                <button 
                  className="query-mode-refresh-button"
                  onClick={handleGenerateRdf}
                  disabled={_generatingRdf}
                >
                  <RefreshCw size={14} />
                  {language === 'nl' ? 'Toepassen' : 'Apply'}
                </button>
              )}
            </div>
          </div>
        )}

        {hasUmlContent && currentCategory === 'uml' && (
          <div className="uml-density-section">
            <h3>{t('umlDensity')}</h3>
            <p className="uml-density-desc">{t('umlDensityDesc')}</p>
            <div className="uml-density-options">
              <button
                className={`uml-density-option ${umlDensityMode === 'full' ? 'active' : ''}`}
                onClick={() => {
                  setUmlDensityMode('full');
                  localStorage.setItem('visualize-uml-density-mode', 'full');
                }}
              >
                <span className="uml-density-label">{t('umlModeFull')}</span>
                <span className="uml-density-hint">{t('umlModeFullHint')}</span>
              </button>
              <button
                className={`uml-density-option ${umlDensityMode === 'streamlined' ? 'active' : ''}`}
                onClick={() => {
                  setUmlDensityMode('streamlined');
                  localStorage.setItem('visualize-uml-density-mode', 'streamlined');
                }}
              >
                <span className="uml-density-label">{t('umlModeStreamlined')}</span>
                <span className="uml-density-hint">{t('umlModeStreamlinedHint')}</span>
              </button>
              <button
                className={`uml-density-option ${umlDensityMode === 'module' ? 'active' : ''}`}
                onClick={() => {
                  setUmlDensityMode('module');
                  localStorage.setItem('visualize-uml-density-mode', 'module');
                }}
              >
                <span className="uml-density-label">{t('umlModeModule')}</span>
                <span className="uml-density-hint">{t('umlModeModuleHint')}</span>
              </button>
            </div>
            {umlDensityMode === 'module' && umlModuleOptions.length > 0 && (
              <div className="uml-module-picker">
                <label htmlFor="uml-module-select" className="uml-module-label">{t('umlModuleSelect')}</label>
                <select
                  id="uml-module-select"
                  className="uml-module-select"
                  value={selectedUmlModule}
                  onChange={(e) => {
                    const next = e.target.value;
                    setSelectedUmlModule(next);
                    localStorage.setItem('visualize-uml-module', next);
                  }}
                >
                  {umlModuleOptions.map((option) => (
                    <option key={option.id} value={option.id}>
                      {option.label} ({option.count.toLocaleString()})
                    </option>
                  ))}
                </select>
              </div>
            )}
            {displayUmlDiagram && umlDiagram && (
              <p className="uml-density-info">
                {displayUmlDiagram.nodes.length.toLocaleString()} / {umlDiagram.nodes.length.toLocaleString()} {t('umlShowingClasses')}
              </p>
            )}
          </div>
        )}

        {/* Graph Controls (RDF only) */}
        {hasRdfContent && currentCategory === 'rdf' && (
          <GraphControls
            nodeTypes={nodeTypes}
            predicates={predicates}
            allNodes={nodes}
            filters={filters}
            onFiltersChange={setFilters}
            onReset={resetFilters}
            onNodeSelect={setSelectedNode}
            stats={stats}
            language={language}
          />
        )}

        {/* Hovered Node Info (RDF) - Brief hint in sidebar */}
        {hoveredNode && !selectedNode && currentCategory === 'rdf' && (
          <div className="hover-info-section">
            <h3>{t('hoverInfo')}</h3>
            <p><strong>{t('type')}:</strong> {hoveredNode.type}</p>
            {hoveredNode.label && (
              <p><strong>{t('label')}:</strong> {hoveredNode.label}</p>
            )}
            {hoveredNode.properties && Object.keys(hoveredNode.properties).length > 0 && (
              <p className="hover-properties-hint">
                <strong>{t('properties')}:</strong> {Object.keys(hoveredNode.properties).length} {language === 'nl' ? 'velden' : 'fields'}
              </p>
            )}
          </div>
        )}

        {/* Source Code View (UML) - in sidebar */}
        {hasUmlContent && umlFileContent && !isLoading && currentCategory === 'uml' && (
          <div className="source-section">
            <details>
              <summary>{t('viewSourceCode')}</summary>
              <div className="source-code-container">
                <pre><code>{umlFileContent}</code></pre>
              </div>
            </details>
          </div>
        )}

      </aside>

      {/* Main Visualization */}
      <main className={`main-content ${isFullscreen ? 'main-content--fullscreen' : ''}`} ref={mainContentRef}>
        {/* Toolbar (when content loaded) */}
        {hasContent && !isLoading && (
          <div className="toolbar">
            <div className="toolbar-left">
              {/* Zoom Controls */}
              <button 
                className="toolbar-button"
                title={t('fitToScreen')}
                onClick={() => {
                  if (currentCategory === 'uml') {
                    window.dispatchEvent(new CustomEvent('uml-fit-to-screen'));
                  } else if (currentCategory === 'rdf') {
                    window.dispatchEvent(new CustomEvent('rdf-fit-to-screen'));
                  }
                }}
              >
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="18" height="18">
                  <path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3" />
                </svg>
                {t('fit')}
              </button>
              <button 
                className="toolbar-button"
                title={t('zoomIn')}
                onClick={() => {
                  if (currentCategory === 'uml') {
                    window.dispatchEvent(new CustomEvent('uml-zoom-in'));
                  } else if (currentCategory === 'rdf') {
                    window.dispatchEvent(new CustomEvent('rdf-zoom-in'));
                  }
                }}
              >
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="18" height="18">
                  <circle cx="11" cy="11" r="8" />
                  <path d="m21 21-4.35-4.35" />
                  <line x1="11" y1="8" x2="11" y2="14" />
                  <line x1="8" y1="11" x2="14" y2="11" />
                </svg>
              </button>
              <button 
                className="toolbar-button"
                title={t('zoomOut')}
                onClick={() => {
                  if (currentCategory === 'uml') {
                    window.dispatchEvent(new CustomEvent('uml-zoom-out'));
                  } else if (currentCategory === 'rdf') {
                    window.dispatchEvent(new CustomEvent('rdf-zoom-out'));
                  }
                }}
              >
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="18" height="18">
                  <circle cx="11" cy="11" r="8" />
                  <path d="m21 21-4.35-4.35" />
                  <line x1="8" y1="11" x2="14" y2="11" />
                </svg>
              </button>
              <button 
                className="toolbar-button"
                title={t('resetView')}
                onClick={() => {
                  if (currentCategory === 'uml') {
                    window.dispatchEvent(new CustomEvent('uml-reset-view'));
                  } else if (currentCategory === 'rdf') {
                    window.dispatchEvent(new CustomEvent('rdf-reset-view'));
                  }
                }}
              >
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="18" height="18">
                  <polyline points="1 4 1 10 7 10" />
                  <polyline points="23 20 23 14 17 14" />
                  <path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15" />
                </svg>
              </button>
              
              {/* Fullscreen Toggle */}
              <button 
                className={`toolbar-button ${isFullscreen ? 'toolbar-button--active' : ''}`}
                title={isFullscreen ? (language === 'nl' ? 'Volledig scherm afsluiten' : 'Exit fullscreen') : (language === 'nl' ? 'Volledig scherm' : 'Fullscreen')}
                onClick={toggleFullscreen}
              >
                {isFullscreen ? <Minimize size={18} /> : <Maximize size={18} />}
              </button>
              
              {/* Layout Dropdown */}
              <div className="dropdown" ref={layoutDropdownRef}>
                <button 
                  className="toolbar-button"
                  onClick={() => setLayoutDropdownOpen(!layoutDropdownOpen)}
                  title={`${language === 'nl' ? 'Huidig' : 'Current'}: ${rdfAdvancedLayout || (layoutType === 'force' ? 'Force' : 'Grid')}`}
                >
                  {rdfAdvancedLayout ? (
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="18" height="18">
                      <circle cx="12" cy="12" r="10" />
                      <path d="M12 2a10 10 0 0 1 0 20" />
                      <line x1="12" y1="12" x2="12" y2="6" />
                    </svg>
                  ) : layoutType === 'force' ? (
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="18" height="18">
                      <circle cx="6" cy="6" r="3" />
                      <circle cx="18" cy="6" r="3" />
                      <circle cx="18" cy="18" r="3" />
                      <circle cx="6" cy="18" r="3" />
                    </svg>
                  ) : (
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" width="18" height="18">
                      <rect x="3" y="3" width="7" height="7" />
                      <rect x="14" y="3" width="7" height="7" />
                      <rect x="14" y="14" width="7" height="7" />
                      <rect x="3" y="14" width="7" height="7" />
                    </svg>
                  )}
                  {t('layout')}
                  <ChevronDown size={14} />
                </button>
                
                {layoutDropdownOpen && (
                  <div className="dropdown-menu dropdown-menu--layout">
                    {/* Basic layouts - shown for both UML and RDF */}
                    <button 
                      className={`dropdown-item ${!rdfAdvancedLayout && layoutType === 'force' ? 'dropdown-item--active' : ''}`}
                      onClick={() => selectLayout('force')}
                    >
                      <span className="dropdown-item-title">{t('forceLayout')}</span>
                      <span className="dropdown-item-desc">{t('forceDesc')}</span>
                    </button>
                    
                    <div className="dropdown-divider"></div>
                    <div className="dropdown-header">{t('gridLayoutOptions')}</div>
                    
                    <button 
                      className={`dropdown-item ${!rdfAdvancedLayout && layoutType === 'dagre' && dagreDirection === 'TB' && dagreRanker === 'network-simplex' ? 'dropdown-item--active' : ''}`}
                      onClick={() => selectLayout('dagre', 'TB', 'network-simplex')}
                    >
                      <span className="dropdown-item-title">{t('hierarchicalTB')}</span>
                      <span className="dropdown-item-desc">{t('hierarchicalTBDesc')}</span>
                    </button>
                    
                    <button 
                      className={`dropdown-item ${!rdfAdvancedLayout && layoutType === 'dagre' && dagreDirection === 'LR' && dagreRanker === 'network-simplex' ? 'dropdown-item--active' : ''}`}
                      onClick={() => selectLayout('dagre', 'LR', 'network-simplex')}
                    >
                      <span className="dropdown-item-title">{t('hierarchicalLR')}</span>
                      <span className="dropdown-item-desc">{t('hierarchicalLRDesc')}</span>
                    </button>
                    
                    <button 
                      className={`dropdown-item ${!rdfAdvancedLayout && layoutType === 'dagre' && dagreRanker === 'tight-tree' ? 'dropdown-item--active' : ''}`}
                      onClick={() => selectLayout('dagre', 'TB', 'tight-tree')}
                    >
                      <span className="dropdown-item-title">{t('adaptiveTightTree')}</span>
                      <span className="dropdown-item-desc">{t('adaptiveTightTreeDesc')}</span>
                    </button>
                    
                    <button 
                      className={`dropdown-item ${!rdfAdvancedLayout && layoutType === 'dagre' && dagreRanker === 'longest-path' ? 'dropdown-item--active' : ''}`}
                      onClick={() => selectLayout('dagre', 'TB', 'longest-path')}
                    >
                      <span className="dropdown-item-title">{t('adaptiveLongestPath')}</span>
                      <span className="dropdown-item-desc">{t('adaptiveLongestPathDesc')}</span>
                    </button>
                    
                    {/* Show UML-specific advanced layouts only for UML mode */}
                    {currentCategory === 'uml' && (
                      <>
                        <div className="dropdown-divider"></div>
                        <div className="dropdown-header">{t('advancedLayoutOptions')}</div>
                        
                        <button 
                          className={`dropdown-item ${layoutType === 'elk' && elkAlgorithm === 'layered' ? 'dropdown-item--active' : ''}`}
                          onClick={() => selectLayout('elk', undefined, undefined, 'layered')}
                        >
                          <span className="dropdown-item-title">{t('elkLayered')}</span>
                          <span className="dropdown-item-desc">{t('elkLayeredDesc')}</span>
                        </button>
                        
                        <button 
                          className={`dropdown-item ${layoutType === 'elk' && elkAlgorithm === 'mrtree' ? 'dropdown-item--active' : ''}`}
                          onClick={() => selectLayout('elk', undefined, undefined, 'mrtree')}
                        >
                          <span className="dropdown-item-title">{t('elkTree')}</span>
                          <span className="dropdown-item-desc">{t('elkTreeDesc')}</span>
                        </button>
                        
                        <button 
                          className={`dropdown-item ${layoutType === 'circular' ? 'dropdown-item--active' : ''}`}
                          onClick={() => selectLayout('circular')}
                        >
                          <span className="dropdown-item-title">{t('circular')}</span>
                          <span className="dropdown-item-desc">{t('circularDesc')}</span>
                        </button>
                        
                        <button 
                          className={`dropdown-item ${layoutType === 'radial' ? 'dropdown-item--active' : ''}`}
                          onClick={() => selectLayout('radial')}
                        >
                          <span className="dropdown-item-title">{t('radial')}</span>
                          <span className="dropdown-item-desc">{t('radialDesc')}</span>
                        </button>
                        
                        <button 
                          className={`dropdown-item ${layoutType === 'clustered' ? 'dropdown-item--active' : ''}`}
                          onClick={() => selectLayout('clustered')}
                        >
                          <span className="dropdown-item-title">{t('clustered')}</span>
                          <span className="dropdown-item-desc">{t('clusteredDesc')}</span>
                        </button>
                      </>
                    )}
                    
                    {/* Show RDF-specific advanced layouts only for RDF mode */}
                    {currentCategory === 'rdf' && (
                      <>
                        <div className="dropdown-divider"></div>
                        <div className="dropdown-header">{t('rdfAdvancedLayouts')}</div>
                        
                        <button 
                          className={`dropdown-item ${rdfAdvancedLayout === 'chord' ? 'dropdown-item--active' : ''}`}
                          onClick={() => selectRdfAdvancedLayout('chord')}
                        >
                          <span className="dropdown-item-title">{t('chordDiagram')}</span>
                          <span className="dropdown-item-desc">{t('chordDiagramDesc')}</span>
                        </button>
                        
                        <button 
                          className={`dropdown-item ${rdfAdvancedLayout === 'radial-tree' ? 'dropdown-item--active' : ''}`}
                          onClick={() => selectRdfAdvancedLayout('radial-tree')}
                        >
                          <span className="dropdown-item-title">{t('radialTreeLayout')}</span>
                          <span className="dropdown-item-desc">{t('radialTreeLayoutDesc')}</span>
                        </button>
                        
                        <button 
                          className={`dropdown-item ${rdfAdvancedLayout === 'edge-bundling' ? 'dropdown-item--active' : ''}`}
                          onClick={() => selectRdfAdvancedLayout('edge-bundling')}
                        >
                          <span className="dropdown-item-title">{t('edgeBundling')}</span>
                          <span className="dropdown-item-desc">{t('edgeBundlingDesc')}</span>
                        </button>
                        
                        <button 
                          className={`dropdown-item ${rdfAdvancedLayout === 'pack' ? 'dropdown-item--active' : ''}`}
                          onClick={() => selectRdfAdvancedLayout('pack')}
                        >
                          <span className="dropdown-item-title">{t('packLayout')}</span>
                          <span className="dropdown-item-desc">{t('packLayoutDesc')}</span>
                        </button>
                        
                        <button 
                          className={`dropdown-item ${rdfAdvancedLayout === 'sunburst' ? 'dropdown-item--active' : ''}`}
                          onClick={() => selectRdfAdvancedLayout('sunburst')}
                        >
                          <span className="dropdown-item-title">{t('sunburstLayout')}</span>
                          <span className="dropdown-item-desc">{t('sunburstLayoutDesc')}</span>
                        </button>
                        
                        <button 
                          className={`dropdown-item ${!rdfAdvancedLayout && layoutType === 'circular' ? 'dropdown-item--active' : ''}`}
                          onClick={() => selectLayout('circular')}
                        >
                          <span className="dropdown-item-title">{t('circular')}</span>
                          <span className="dropdown-item-desc">{t('circularDesc')}</span>
                        </button>
                        
                        <button 
                          className={`dropdown-item ${!rdfAdvancedLayout && layoutType === 'radial' ? 'dropdown-item--active' : ''}`}
                          onClick={() => selectLayout('radial')}
                        >
                          <span className="dropdown-item-title">{t('radial')}</span>
                          <span className="dropdown-item-desc">{t('radialDesc')}</span>
                        </button>
                      </>
                    )}
                    
                    <div className="dropdown-divider"></div>
                    <a 
                      href="/docs/UML_LAYOUT_OPTIONS.md" 
                      target="_blank"
                      rel="noopener noreferrer"
                      className="dropdown-item dropdown-item--link"
                      onClick={() => setLayoutDropdownOpen(false)}
                    >
                      <HelpCircle size={16} />
                      <span className="dropdown-item-title">{t('layoutHelp')}</span>
                    </a>
                  </div>
                )}
              </div>
            </div>
            
            <div className="toolbar-right">
              <span className="toolbar-title">{fileName}</span>
              
              {/* Export Dropdown */}
              <div className="dropdown" ref={exportDropdownRef}>
                <button 
                  className="toolbar-button toolbar-button--primary"
                  onClick={() => setExportDropdownOpen(!exportDropdownOpen)}
                >
                  <Download size={18} />
                  {t('export')}
                  <ChevronDown size={14} />
                </button>
                
                {exportDropdownOpen && (
                  <div className="dropdown-menu">
                    <button className="dropdown-item" onClick={handleExportPNG}>
                      <Image size={16} />
                      <span className="dropdown-item-title">{t('exportAsPng')}</span>
                    </button>
                    <button className="dropdown-item" onClick={handleExportSVG}>
                      <FileCode size={16} />
                      <span className="dropdown-item-title">{t('exportAsSvg')}</span>
                    </button>
                    <div className="dropdown-divider"></div>
                    <button className="dropdown-item" onClick={handleDownloadSource}>
                      <Code size={16} />
                      <span className="dropdown-item-title">{t('downloadSource')}</span>
                    </button>
                  </div>
                )}
              </div>
            </div>
          </div>
        )}

        {/* Loading State */}
        {isLoading && (
          <div className="loading-overlay">
            <div className="spinner" />
            <p>{t('loading')}</p>
          </div>
        )}

        {/* Error State */}
        {(parserError || umlError) && (
          <div className="error-message">
            <h2>{t('error')}</h2>
            <div className="error-details">
              {(parserError?.message || umlError || '').split('\n').map((line, i) => (
                <p key={i}>{line}</p>
              ))}
            </div>
          </div>
        )}

        {/* Welcome State (no content) */}
        {!isLoading && !parserError && !umlError && !hasContent && (
          <div className="welcome-message">
            <h2>{t('readyToVisualize')}</h2>
            <p>{t('welcomeDesc')}</p>
            <div className="features">
              <h3>{t('supportedFormats')}</h3>
              <ul>
                <li><strong>RDF:</strong> Turtle (.ttl), N-Triples (.nt), JSON-LD (.jsonld)</li>
                <li><strong>UML:</strong> Mermaid (.mmd), PlantUML (.puml), GraphViz (.dot)</li>
              </ul>
              <h3>{t('features')}</h3>
              <ul>
                <li>{t('featureInteractive')}</li>
                <li>{t('featureLayouts')}</li>
                <li>{t('featureFilter')}</li>
                <li>{t('featureExport')}</li>
                <li>{t('featureDrag')}</li>
                <li>{t('featureClick')}</li>
              </ul>
            </div>
          </div>
        )}

        {/* RDF Visualization */}
        {!isLoading && !parserError && hasRdfContent && currentCategory === 'rdf' && (
          rdfAdvancedLayout ? (
            // Advanced RDF layouts (chord, radial-tree, edge-bundling, pack, sunburst)
            <RdfAdvancedLayout
              nodes={filteredNodes}
              links={filteredLinks}
              layoutType={rdfAdvancedLayout}
              width={1200}
              height={800}
              onNodeClick={handleNodeClick}
              onNodeHover={setHoveredNode}
              selectedNode={selectedNode}
              language={language}
            />
          ) : (
            // Basic RDF layouts (force, hierarchical, circular, radial)
            <ForceDirectedGraph
              nodes={filteredNodes}
              links={filteredLinks}
              width={1200}
              height={800}
              layoutType={mapToRdfLayout(layoutType, dagreDirection)}
              selectedNode={selectedNode}
              onNodeClick={handleNodeClick}
              onLinkClick={handleLinkClick}
              onNodeHover={setHoveredNode}
              className="graph-visualization"
            />
          )
        )}

        {/* RDF Node Details Popup */}
        {selectedNode && currentCategory === 'rdf' && (
          <RdfNodeDetailsPanel
            node={selectedNode}
            links={links}
            nodes={nodes}
            onClose={() => setSelectedNode(null)}
            onNodeClick={(node) => setSelectedNode(node)}
            language={language}
          />
        )}

        {/* UML Visualization */}
        {!isLoading && !umlError && hasUmlContent && currentCategory === 'uml' && (
          <div className="uml-canvas">
            <UMLVisualization 
              diagram={displayUmlDiagram || umlDiagram!} 
              width={1400} 
              height={900}
              layoutType={layoutType}
              dagreDirection={dagreDirection}
              dagreRanker={dagreRanker}
              elkAlgorithm={elkAlgorithm}
            />
          </div>
        )}


      </main>
    </div>
  );
}
