/**
 * Ontology Visualizer Component
 * 
 * Renders RDF ontologies as Mermaid diagrams (class diagrams and ER diagrams).
 * Supports loading from .mmd files or generating from RDF data.
 */

import React, { useEffect, useRef, useState } from 'react';
import type { SparqlClient } from '../../lib/sparql/client';
import './OntologyVisualizer.css';

// Lazy load mermaid to avoid bundling issues
let mermaidInstance: typeof import('mermaid').default | null = null;
const getMermaid = async () => {
  if (!mermaidInstance) {
    const mod = await import('mermaid');
    mermaidInstance = mod.default;
    mermaidInstance.initialize({
      startOnLoad: false,
      theme: 'default',
      securityLevel: 'loose',
      fontFamily: 'Arial, sans-serif',
      logLevel: 'error',
    });
  }
  return mermaidInstance;
};

export interface OntologyVisualizerProps {
  /** Pre-loaded Mermaid diagram source */
  mermaidSource?: string;
  /** SPARQL client for querying RDF data */
  sparqlClient?: SparqlClient;
  /** Diagram type to generate from RDF */
  diagramType?: 'class' | 'er';
  /** Max height of diagram container */
  maxHeight?: string;
  /** Show toolbar with zoom/download controls */
  showToolbar?: boolean;
}

export const OntologyVisualizer: React.FC<OntologyVisualizerProps> = ({
  mermaidSource,
  sparqlClient,
  diagramType = 'class',
  maxHeight = '800px',
  showToolbar = true,
}) => {
  const containerRef = useRef<HTMLDivElement>(null);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [zoom, setZoom] = useState(1);
  const [generatedSource, setGeneratedSource] = useState<string | null>(null);
  const [mermaidReady, setMermaidReady] = useState(false);

  // Initialize Mermaid (lazy loaded)
  useEffect(() => {
    getMermaid().then(() => setMermaidReady(true)).catch(console.error);
  }, []);

  // Generate Mermaid diagram from RDF data
  const generateFromRdf = async () => {
    if (!sparqlClient) return;

    setIsLoading(true);
    setError(null);

    try {
      if (diagramType === 'class') {
        const source = await generateClassDiagram(sparqlClient);
        setGeneratedSource(source);
      } else {
        const source = await generateErDiagram(sparqlClient);
        setGeneratedSource(source);
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to generate diagram');
    } finally {
      setIsLoading(false);
    }
  };

  // Render Mermaid diagram
  useEffect(() => {
    const source = mermaidSource || generatedSource;
    if (!source || !containerRef.current || !mermaidReady) return;

    const renderDiagram = async () => {
      try {
        const mermaid = await getMermaid();
        const { svg } = await mermaid.render('mermaid-diagram', source);
        if (containerRef.current) {
          containerRef.current.innerHTML = svg;
        }
      } catch (err) {
        console.error('Mermaid render error:', err);
        setError('Failed to render diagram. Check Mermaid syntax.');
      }
    };

    renderDiagram();
  }, [mermaidSource, generatedSource, mermaidReady]);

  // Generate diagram when sparqlClient is provided
  useEffect(() => {
    if (sparqlClient && !mermaidSource) {
      generateFromRdf();
    }
  }, [sparqlClient, diagramType]);

  // Download diagram as SVG
  const handleDownload = () => {
    if (!containerRef.current) return;
    
    const svg = containerRef.current.querySelector('svg');
    if (!svg) return;

    const svgData = new XMLSerializer().serializeToString(svg);
    const blob = new Blob([svgData], { type: 'image/svg+xml' });
    const url = URL.createObjectURL(blob);
    
    const link = document.createElement('a');
    link.href = url;
    link.download = `ontology-diagram-${Date.now()}.svg`;
    link.click();
    
    URL.revokeObjectURL(url);
  };

  // Zoom controls
  const handleZoomIn = () => setZoom((z) => Math.min(z + 0.1, 3));
  const handleZoomOut = () => setZoom((z) => Math.max(z - 0.1, 0.3));
  const handleZoomReset = () => setZoom(1);

  if (isLoading) {
    return (
      <div className="ontology-visualizer">
        <div className="visualizer-loading">
          <div className="spinner" />
          <p>Generating ontology diagram...</p>
        </div>
      </div>
    );
  }

  if (error) {
    return (
      <div className="ontology-visualizer">
        <div className="visualizer-error">
          <p className="error-title">Failed to load diagram</p>
          <p className="error-message">{error}</p>
          {sparqlClient && (
            <button onClick={generateFromRdf} className="retry-btn">
              Retry
            </button>
          )}
        </div>
      </div>
    );
  }

  return (
    <div className="ontology-visualizer">
      {showToolbar && (
        <div className="visualizer-toolbar">
          <div className="zoom-controls">
            <button
              onClick={handleZoomOut}
              className="toolbar-btn"
              title="Zoom out"
              disabled={zoom <= 0.3}
            >
              −
            </button>
            <span className="zoom-level">{Math.round(zoom * 100)}%</span>
            <button
              onClick={handleZoomIn}
              className="toolbar-btn"
              title="Zoom in"
              disabled={zoom >= 3}
            >
              +
            </button>
            <button onClick={handleZoomReset} className="toolbar-btn" title="Reset zoom">
              Reset
            </button>
          </div>

          <div className="toolbar-actions">
            {sparqlClient && (
              <button onClick={generateFromRdf} className="toolbar-btn">
                Regenerate
              </button>
            )}
            <button onClick={handleDownload} className="toolbar-btn">
              Download SVG
            </button>
          </div>
        </div>
      )}

      <div
        className="visualizer-container"
        style={{
          maxHeight,
          transform: `scale(${zoom})`,
          transformOrigin: 'top left',
        }}
      >
        <div ref={containerRef} className="mermaid-diagram" />
      </div>
    </div>
  );
};

/**
 * Generate Mermaid class diagram from RDF data
 */
async function generateClassDiagram(client: SparqlClient): Promise<string> {
  // Query for classes and their properties
  const query = `
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    PREFIX owl: <http://www.w3.org/2002/07/owl#>
    
    SELECT DISTINCT ?class ?label ?superclass WHERE {
      ?class a owl:Class .
      OPTIONAL { ?class rdfs:label ?label }
      OPTIONAL { ?class rdfs:subClassOf ?superclass }
      FILTER(isIRI(?class))
    }
    ORDER BY ?class
    LIMIT 50
  `;

  const results = await client.executeSelect(query);
  const classes = new Map<string, { label: string; superclasses: string[] }>();

  // Build class hierarchy
  for (const binding of results.results.bindings) {
    const classUri = binding.class?.value;
    if (!classUri) continue;

    const className = extractLocalName(classUri);
    const label = binding.label?.value || className;
    const superclass = binding.superclass?.value;

    if (!classes.has(className)) {
      classes.set(className, { label, superclasses: [] });
    }

    if (superclass) {
      const superclassName = extractLocalName(superclass);
      classes.get(className)!.superclasses.push(superclassName);
    }
  }

  // Generate Mermaid syntax
  let mermaid = 'classDiagram\n';
  mermaid += '    %% Heritage Custodian Ontology - Class Diagram\n';
  mermaid += '    %% Auto-generated from RDF data\n\n';

  // Define classes
  for (const [className] of classes) {
    mermaid += `    class ${className} {\n`;
    mermaid += `    }\n\n`;
  }

  // Add inheritance relationships
  mermaid += '    %% Inheritance relationships\n';
  for (const [className, data] of classes) {
    for (const superclass of data.superclasses) {
      if (classes.has(superclass)) {
        mermaid += `    ${superclass} <|-- ${className}\n`;
      }
    }
  }

  return mermaid;
}

/**
 * Generate Mermaid ER diagram from RDF data
 */
async function generateErDiagram(client: SparqlClient): Promise<string> {
  // Query for classes and properties
  const query = `
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    PREFIX owl: <http://www.w3.org/2002/07/owl#>
    
    SELECT DISTINCT ?class ?property ?range WHERE {
      ?class a owl:Class .
      ?property rdfs:domain ?class .
      OPTIONAL { ?property rdfs:range ?range }
      FILTER(isIRI(?class))
    }
    ORDER BY ?class ?property
    LIMIT 100
  `;

  const results = await client.executeSelect(query);
  const entities = new Map<string, Set<string>>();
  const relationships = new Set<string>();

  // Build entity structure
  for (const binding of results.results.bindings) {
    const classUri = binding.class?.value;
    const propertyUri = binding.property?.value;
    const rangeUri = binding.range?.value;

    if (!classUri) continue;

    const className = extractLocalName(classUri);
    
    if (!entities.has(className)) {
      entities.set(className, new Set());
    }

    if (propertyUri) {
      const propName = extractLocalName(propertyUri);
      entities.get(className)!.add(propName);

      // Add relationship if range is another class
      if (rangeUri && entities.has(extractLocalName(rangeUri))) {
        const rangeName = extractLocalName(rangeUri);
        relationships.add(`${className} ||--o{ ${rangeName} : "${propName}"`);
      }
    }
  }

  // Generate Mermaid syntax
  let mermaid = 'erDiagram\n';
  
  // Define entities
  for (const [entityName, properties] of entities) {
    mermaid += `${entityName} {\n`;
    for (const prop of properties) {
      mermaid += `    string ${prop}\n`;
    }
    mermaid += `}\n\n`;
  }

  // Add relationships
  for (const rel of relationships) {
    mermaid += `${rel}\n`;
  }

  return mermaid;
}

/**
 * Extract local name from URI
 */
function extractLocalName(uri: string): string {
  const lastSlash = Math.max(uri.lastIndexOf('/'), uri.lastIndexOf('#'));
  return lastSlash > 0 ? uri.substring(lastSlash + 1) : uri;
}
