/**
 * content-graph-shim.js
 *
 * Thin bridge between Leptos/WASM and Cytoscape.js.
 * Exposes window.ContentGraph with a single render() entry point.
 *
 * Called from GraphView component after mount:
 *   window.ContentGraph.render(containerId, focusNodeId, theme)
 *
 * Reads graph data from:
 *   <script type="application/json" id="content-graph-data">{ nodes, edges }</script>
 *
 * Requires (loaded before this script via assets pipeline):
 *   - cytoscape.min.js
 *   - cytoscape-cose-bilkent.min.js
 */

(function () {
  'use strict';

  // ── Theme tokens ────────────────────────────────────────────────────────────

  function buildPalette(isDark) {
    return {
      // Content node variants
      contentFill:   isDark ? '#3b82f6' : '#2563eb',
      // Ontology node variants by level
      axiomFill:     isDark ? '#8b5cf6' : '#7c3aed',
      tensionFill:   isDark ? '#f59e0b' : '#d97706',
      practiceFill:  isDark ? '#10b981' : '#059669',
      projectFill:   isDark ? '#06b6d4' : '#0891b2',
      // ADR
      adrFill:       isDark ? '#f97316' : '#ea580c',
      // Ego node ring
      egoStroke:     isDark ? '#facc15' : '#ca8a04',
      // Edge colours by kind group
      declaredEdge:  isDark ? '#6b7280' : '#9ca3af',
      autoEdge:      isDark ? '#4b5563' : '#d1d5db',
      implicitEdge:  isDark ? '#374151' : '#e5e7eb',
      // Labels
      labelColor:    isDark ? '#f9fafb' : '#111827',
      labelBg:       isDark ? 'rgba(17,24,39,0.75)' : 'rgba(255,255,255,0.75)',
      // Background
      bg:            isDark ? '#111827' : '#ffffff',
    };
  }

  // ── Cytoscape stylesheet ─────────────────────────────────────────────────────

  function buildStylesheet(palette, egoId) {
    const label = {
      label:             'data(title)',
      color:             palette.labelColor,
      'background-color':palette.labelBg,
      'background-opacity': 0.75,
      'background-padding': '3px',
      'font-size':       '11px',
      'text-valign':     'bottom',
      'text-halign':     'center',
      'text-margin-y':   '4px',
    };

    return [
      // Default node
      {
        selector: 'node',
        style: {
          ...label,
          shape:              'ellipse',
          width:              '36px',
          height:             '36px',
          'background-color': palette.contentFill,
          'border-width':     '0px',
          'cursor':           'pointer',
        },
      },
      // Ego node (focused)
      {
        selector: `node[id="${egoId}"]`,
        style: {
          width:          '48px',
          height:         '48px',
          'border-width': '3px',
          'border-color': palette.egoStroke,
          'font-size':    '13px',
          'font-weight':  'bold',
        },
      },
      // Ontology variants
      { selector: 'node[level="Axiom"]',    style: { 'background-color': palette.axiomFill,    shape: 'diamond' } },
      { selector: 'node[level="Tension"]',  style: { 'background-color': palette.tensionFill,  shape: 'triangle' } },
      { selector: 'node[level="Practice"]', style: { 'background-color': palette.practiceFill, shape: 'rectangle' } },
      { selector: 'node[level="Project"]',  style: { 'background-color': palette.projectFill,  shape: 'rectangle' } },
      // ADR
      { selector: 'node[type="adr"]', style: { 'background-color': palette.adrFill, shape: 'pentagon' } },
      // Hover
      {
        selector: 'node:selected',
        style: { 'border-width': '3px', 'border-color': palette.egoStroke },
      },
      // Default edge
      {
        selector: 'edge',
        style: {
          width:               '1.5px',
          'line-color':        palette.declaredEdge,
          'target-arrow-color':palette.declaredEdge,
          'target-arrow-shape':'triangle',
          'curve-style':       'bezier',
          opacity:             0.7,
        },
      },
      // Auto-backlink edges (lighter)
      {
        selector: 'edge[source="auto_backlink"]',
        style: { 'line-color': palette.autoEdge, 'target-arrow-color': palette.autoEdge, opacity: 0.5 },
      },
      // Implicit / SharedTag edges (dashed, very light)
      {
        selector: 'edge[kind="shared_tag"]',
        style: {
          'line-style':        'dashed',
          'line-color':        palette.implicitEdge,
          'target-arrow-color':palette.implicitEdge,
          opacity:             0.35,
        },
      },
    ];
  }

  // ── Element conversion ───────────────────────────────────────────────────────

  function toCytoscapeElements(graphData) {
    const nodes = (graphData.nodes || []).map(n => ({
      data: {
        id:       n.id,
        title:    n.title || n.name || n.id,
        type:     n.type,
        level:    n.level  || null,
        url:      n.url    || null,
        instance: n.instance || null,
      },
    }));

    const edges = (graphData.edges || []).map((e, i) => ({
      data: {
        id:     `e-${i}`,
        source: e.from,
        target: e.to,
        kind:   e.kind,
        source_type: e.source, // "declared" | "auto_backlink" | "implicit"
      },
    }));

    return [...nodes, ...edges];
  }

  // ── Layout config ────────────────────────────────────────────────────────────

  function buildLayout(nodeCount) {
    // cose-bilkent for larger graphs; grid fallback for tiny graphs
    if (nodeCount <= 4) {
      return { name: 'circle', animate: false, padding: 40 };
    }
    return {
      name:            'cose-bilkent',
      animate:         false,
      nodeDimensionsIncludeLabels: true,
      idealEdgeLength: 100,
      nodeRepulsion:   8000,
      padding:         30,
    };
  }

  // ── Instances registry ───────────────────────────────────────────────────────
  // Keeps track of active cy instances so they can be destroyed on re-render.

  const _instances = new Map();

  // ── Public API ───────────────────────────────────────────────────────────────

  window.ContentGraph = {
    /**
     * Render the knowledge graph into `containerId`.
     *
     * @param {string} containerId  - DOM id of the container element
     * @param {string} focusNodeId  - node id to highlight/center; may be empty
     * @param {string} theme        - "dark" | "light"
     */
    render(containerId, focusNodeId, theme) {
      const container = document.getElementById(containerId);
      if (!container) {
        console.warn('[ContentGraph] container not found:', containerId);
        return;
      }

      // Destroy previous instance if re-rendering
      if (_instances.has(containerId)) {
        _instances.get(containerId).destroy();
        _instances.delete(containerId);
      }

      // Read graph data embedded by SSR
      const dataEl = document.getElementById('content-graph-data');
      if (!dataEl) {
        console.warn('[ContentGraph] #content-graph-data not found');
        return;
      }

      let graphData;
      try {
        graphData = JSON.parse(dataEl.textContent);
      } catch (e) {
        console.error('[ContentGraph] failed to parse graph data:', e);
        return;
      }

      const isDark  = theme === 'dark';
      const palette = buildPalette(isDark);
      const egoId   = focusNodeId || '';

      const cy = window.cytoscape({
        container,
        elements: toCytoscapeElements(graphData),
        style:    buildStylesheet(palette, egoId),
        layout:   buildLayout((graphData.nodes || []).length),
        minZoom:  0.3,
        maxZoom:  4,
      });

      _instances.set(containerId, cy);

      // Navigate to content URL on node tap
      cy.on('tap', 'node', evt => {
        const url = evt.target.data('url');
        if (url) window.location.href = url;
      });

      // Pointer cursor on hover
      cy.on('mouseover', 'node[?url]', () => { container.style.cursor = 'pointer'; });
      cy.on('mouseout',  'node',       () => { container.style.cursor = 'default'; });

      // Focus and center on ego node
      if (egoId) {
        const egoNode = cy.$(`#${CSS.escape(egoId)}`);
        if (egoNode.length) {
          cy.animate({ fit: { eles: egoNode.neighborhood().add(egoNode), padding: 60 } }, { duration: 400 });
        }
      }
    },

    /**
     * Destroy the Cytoscape instance for a given container (cleanup on unmount).
     */
    destroy(containerId) {
      if (_instances.has(containerId)) {
        _instances.get(containerId).destroy();
        _instances.delete(containerId);
      }
    },
  };
})();
