import { IStateVisualizationService, VisualizationConfig, StateMetrics, NodeStyle, EdgeStyle } from './IStateVisualizationService';
import { IStateHistoryService } from '../StateHistoryService/IStateHistoryService';
import { IStateTrackingService, StateMetadata, StateRelationship } from '../StateTrackingService/IStateTrackingService';

/**
 * @package
 * Implementation of state visualization service.
 */
export class StateVisualizationService implements IStateVisualizationService {
  constructor(
    private historyService: IStateHistoryService,
    private trackingService: IStateTrackingService,
  ) {}

  private generateMermaidGraph(nodes: Map<string, StateMetadata>, edges: StateRelationship[], config: VisualizationConfig): string {
    const lines: string[] = ['graph TD;'];
    
    // Add nodes with styling
    nodes.forEach((metadata, id) => {
      const style = this.getNodeStyle(metadata, config);
      const styleStr = `style="${style.shape},${style.color}"`;
      const label = config.includeMetadata 
        ? `${id}[${metadata.source}${metadata.filePath ? `\\n${metadata.filePath}` : ''}]`
        : `${id}[${metadata.source}]`;
      lines.push(`    ${label} ${styleStr};`);
    });

    // Add edges with styling
    edges.forEach(edge => {
      const style = this.getEdgeStyle(edge, config);
      const styleStr = `style="${style.style},${style.color}"`;
      const label = edge.type;
      lines.push(`    ${edge.targetId} -->|${label}| ${edge.type} ${styleStr};`);
    });

    return lines.join('\n');
  }

  private generateDotGraph(nodes: Map<string, StateMetadata>, edges: StateRelationship[], config: VisualizationConfig): string {
    const lines: string[] = ['digraph G {'];
    
    // Add nodes with styling
    nodes.forEach((metadata, id) => {
      const style = this.getNodeStyle(metadata, config);
      const label = config.includeMetadata
        ? `${id}\\n${metadata.source}${metadata.filePath ? `\\n${metadata.filePath}` : ''}`
        : `${id}\\n${metadata.source}`;
      const attrs = [
        `label="${label}"`,
        `shape="${style.shape}"`,
        `color="${style.color}"`,
      ];
      if (style.tooltip) {
        attrs.push(`tooltip="${style.tooltip}"`);
      }
      lines.push(`    "${id}" [${attrs.join(',')}];`);
    });

    // Add edges with styling
    edges.forEach(edge => {
      const style = this.getEdgeStyle(edge, config);
      const attrs = [
        `style="${style.style}"`,
        `color="${style.color}"`,
        `label="${edge.type}"`,
      ];
      if (style.tooltip) {
        attrs.push(`tooltip="${style.tooltip}"`);
      }
      lines.push(`    "${edge.targetId}" -> "${edge.type}" [${attrs.join(',')}];`);
    });

    lines.push('}');
    return lines.join('\n');
  }

  private getNodeStyle(metadata: StateMetadata, config: VisualizationConfig): NodeStyle {
    if (config.styleNodes) {
      return config.styleNodes(metadata);
    }

    // Default styling based on state type
    const style: NodeStyle = {
      shape: 'box',
      color: '#000000',
    };

    switch (metadata.source) {
      case 'new':
        style.color = '#4CAF50';
        break;
      case 'clone':
        style.color = '#2196F3';
        break;
      case 'merge':
        style.shape = 'diamond';
        style.color = '#9C27B0';
        break;
      case 'implicit':
        style.color = '#757575';
        break;
    }

    return style;
  }

  private getEdgeStyle(relationship: StateRelationship, config: VisualizationConfig): EdgeStyle {
    if (config.styleEdges) {
      return config.styleEdges(relationship);
    }

    // Default styling based on relationship type
    const style: EdgeStyle = {
      style: 'solid',
      color: '#000000',
    };

    switch (relationship.type) {
      case 'parent-child':
        style.style = 'solid';
        break;
      case 'merge-source':
        style.style = 'dashed';
        break;
      case 'merge-target':
        style.style = 'dotted';
        break;
    }

    return style;
  }

  public generateHierarchyView(rootStateId: string, config: VisualizationConfig): string {
    // Validate format first
    if (!['mermaid', 'dot', 'json'].includes(config.format)) {
      throw new Error(`Unsupported format: ${config.format}`);
    }

    const lineage = this.trackingService.getStateLineage(rootStateId);
    const descendants = this.trackingService.getStateDescendants(rootStateId);
    const allStateIds = new Set([...lineage, ...descendants]);

    // Build nodes and edges
    const nodes = new Map<string, StateMetadata>();
    const edges: StateRelationship[] = [];

    // Collect all states and their relationships
    allStateIds.forEach(stateId => {
      // Get state metadata from history
      const operations = this.historyService.getOperationHistory(stateId);
      const createOp = operations.find(op => op.type === 'create');
      if (createOp && createOp.metadata) {
        nodes.set(stateId, createOp.metadata);
      }

      // Get relationships from tracking service
      const stateLineage = this.trackingService.getStateLineage(stateId);
      if (stateLineage.length > 1) {
        const parentIndex = stateLineage.indexOf(stateId) - 1;
        if (parentIndex >= 0) {
          edges.push({
            targetId: stateId,
            type: 'parent-child',
          });
        }
      }
    });

    // Generate visualization in requested format
    switch (config.format) {
      case 'mermaid':
        return this.generateMermaidGraph(nodes, edges, config);
      case 'dot':
        return this.generateDotGraph(nodes, edges, config);
      case 'json':
        return JSON.stringify({
          nodes: Array.from(nodes.entries()).map(([id, metadata]) => ({
            id,
            ...metadata,
          })),
          edges,
        }, null, 2);
      default:
        throw new Error(`Unsupported format: ${config.format}`);
    }
  }

  public generateTransitionDiagram(stateId: string, config: VisualizationConfig): string {
    const transformations = this.historyService.getTransformationChain(stateId);
    
    if (transformations.length === 0) {
      return '';
    }

    switch (config.format) {
      case 'mermaid':
        return this.generateMermaidTransitionDiagram(transformations, config);
      case 'dot':
        return this.generateDotTransitionDiagram(transformations, config);
      case 'json':
        return JSON.stringify(transformations, null, 2);
      default:
        throw new Error(`Unsupported format: ${config.format}`);
    }
  }

  private generateMermaidTransitionDiagram(transformations: StateTransformation[], config: VisualizationConfig): string {
    const lines: string[] = ['graph LR;'];
    
    // Helper to format value display
    const formatValue = (value: unknown): string => {
      if (typeof value === 'object' && value !== null) {
        return Object.entries(value as Record<string, unknown>)
          .map(([key, val]) => {
            if (Array.isArray(val)) {
              return `${key}: [${val.join(',')}]`;
            } else if (typeof val === 'object' && val !== null) {
              return Object.entries(val as Record<string, unknown>)
                .map(([k, v]) => Array.isArray(v) ? `${key}.${k}: [${v.join(',')}]` : `${key}.${k}: ${v}`)
                .join('\\n');
            }
            return `${key}: ${val}`;
          })
          .join('\\n');
      }
      return String(value);
    };

    // Add nodes and transitions
    transformations.forEach((transform, index) => {
      const beforeId = `state_${index}`;
      const afterId = `state_${index + 1}`;
      
      // Add before state
      const beforeLabel = formatValue(transform.before);
      lines.push(`    ${beforeId}["${beforeLabel}"];`);
      
      // Add after state
      const afterLabel = formatValue(transform.after);
      lines.push(`    ${afterId}["${afterLabel}"];`);
      
      // Add transition with timestamp first for better readability
      const transitionLabel = config.includeTimestamps
        ? `${transform.timestamp} ${transform.operation}`
        : transform.operation;
      lines.push(`    ${beforeId} -->|${transitionLabel}| ${afterId};`);
      
      // Add styling
      const style = this.getNodeStyle({ source: transform.source } as StateMetadata, config);
      lines.push(`    style ${beforeId} fill:${style.color};`);
      lines.push(`    style ${afterId} fill:${style.color};`);
    });

    return lines.join('\n');
  }

  private generateDotTransitionDiagram(transformations: StateTransformation[], config: VisualizationConfig): string {
    const lines: string[] = ['digraph G {'];
    lines.push('    rankdir=LR;'); // Left to right layout
    
    // Helper to format value display
    const formatValue = (value: unknown): string => {
      if (typeof value === 'object' && value !== null) {
        return Object.entries(value as Record<string, unknown>)
          .map(([key, val]) => {
            if (Array.isArray(val)) {
              return `${key}: [${val.join(',')}]`;
            } else if (typeof val === 'object' && val !== null) {
              return Object.entries(val as Record<string, unknown>)
                .map(([k, v]) => `${key}.${k}: ${v}`)
                .join('\\n');
            }
            return `${key}: ${val}`;
          })
          .join('\\n');
      }
      return String(value);
    };

    // Add nodes and transitions
    transformations.forEach((transform, index) => {
      const beforeId = `state_${index}`;
      const afterId = `state_${index + 1}`;
      
      // Add before state
      const beforeLabel = formatValue(transform.before);
      const beforeStyle = this.getNodeStyle({ source: transform.source } as StateMetadata, config);
      lines.push(`    "${beforeId}" [label="${beforeLabel}",shape="${beforeStyle.shape}",color="${beforeStyle.color}"];`);
      
      // Add after state
      const afterLabel = formatValue(transform.after);
      const afterStyle = this.getNodeStyle({ source: transform.source } as StateMetadata, config);
      lines.push(`    "${afterId}" [label="${afterLabel}",shape="${afterStyle.shape}",color="${afterStyle.color}"];`);
      
      // Add transition
      const transitionLabel = config.includeTimestamps
        ? `${transform.operation}\\n${transform.timestamp}`
        : transform.operation;
      lines.push(`    "${beforeId}" -> "${afterId}" [label="${transitionLabel}"];`);
    });

    lines.push('}');
    return lines.join('\n');
  }

  public generateRelationshipGraph(stateIds: string[], config: VisualizationConfig): string {
    if (!['mermaid', 'dot', 'json'].includes(config.format)) {
      throw new Error(`Unsupported format: ${config.format}`);
    }

    // Collect all states and their relationships
    const nodes = new Map<string, StateMetadata>();
    const edges: StateRelationship[] = [];
    const processedStates = new Set<string>();

    // Helper to process a state and its relationships
    const processState = (stateId: string) => {
      if (processedStates.has(stateId)) return;
      processedStates.add(stateId);

      // Get state metadata from history
      const operations = this.historyService.getOperationHistory(stateId);
      const createOrMergeOp = operations.find(op => op.type === 'create' || op.type === 'merge');
      if (createOrMergeOp?.metadata) {
        nodes.set(stateId, createOrMergeOp.metadata);
      }

      // Get lineage relationships
      const lineage = this.trackingService.getStateLineage(stateId);
      if (lineage.length > 1) {
        for (let i = 1; i < lineage.length; i++) {
          edges.push({
            targetId: lineage[i],
            sourceId: lineage[i - 1],
            type: 'parent-child',
          });
        }
      }

      // Get merge relationships
      const mergeOps = operations.filter(op => op.type === 'merge');
      mergeOps.forEach(op => {
        if (op.parentId) {
          edges.push({
            sourceId: op.parentId,
            targetId: stateId,
            type: 'merge-source',
          });
          // Also process the parent state if we haven't yet
          processState(op.parentId);
        }
      });

      // Process descendants
      const descendants = this.trackingService.getStateDescendants(stateId);
      descendants.forEach(descendantId => processState(descendantId));
    };

    // Process all requested states
    stateIds.forEach(stateId => processState(stateId));

    // Generate visualization in requested format
    switch (config.format) {
      case 'mermaid':
        return this.generateMermaidRelationshipGraph(nodes, edges, config);
      case 'dot':
        return this.generateDotRelationshipGraph(nodes, edges, config);
      case 'json':
        return JSON.stringify({
          nodes: Array.from(nodes.entries()).map(([id, metadata]) => ({
            id,
            ...metadata,
          })),
          edges,
        }, null, 2);
      default:
        throw new Error(`Unsupported format: ${config.format}`);
    }
  }

  private generateMermaidRelationshipGraph(
    nodes: Map<string, StateMetadata>,
    edges: StateRelationship[],
    config: VisualizationConfig
  ): string {
    const lines: string[] = ['graph TD;'];
    
    // Add nodes with styling
    nodes.forEach((metadata, id) => {
      const style = this.getNodeStyle(metadata, config);
      const label = config.includeMetadata 
        ? `${id}[${metadata.source}${metadata.filePath ? `\\n${metadata.filePath}` : ''}]`
        : `${id}[${metadata.source}]`;
      lines.push(`    ${label};`);
      lines.push(`    style ${id} fill:${style.color},stroke:${style.color},stroke-width:2px,${style.shape};`);
    });

    // Add edges with styling
    edges.forEach(edge => {
      const style = this.getEdgeStyle(edge, config);
      const sourceId = edge.sourceId || 'unknown';
      const label = config.includeMetadata ? edge.type : '';
      lines.push(`    ${sourceId} -->|${label}| ${edge.targetId};`);
      lines.push(`    linkStyle ${lines.length - 2} stroke:${style.color},stroke-width:2px,${style.style};`);
    });

    return lines.join('\n');
  }

  private generateDotRelationshipGraph(
    nodes: Map<string, StateMetadata>,
    edges: StateRelationship[],
    config: VisualizationConfig
  ): string {
    const lines: string[] = ['digraph G {'];
    lines.push('    rankdir=TB;'); // Top to bottom layout
    
    // Add nodes with styling
    nodes.forEach((metadata, id) => {
      const style = this.getNodeStyle(metadata, config);
      const label = config.includeMetadata
        ? `${id}\\n${metadata.source}${metadata.filePath ? `\\n${metadata.filePath}` : ''}`
        : `${id}\\n${metadata.source}`;
      const attrs = [
        `label="${label}"`,
        `shape="${style.shape}"`,
        `color="${style.color}"`,
        `style="filled"`,
        `fillcolor="${style.color}22"`, // Add transparency to fill color
      ];
      if (style.tooltip) {
        attrs.push(`tooltip="${style.tooltip}"`);
      }
      lines.push(`    "${id}" [${attrs.join(',')}];`);
    });

    // Add edges with styling
    edges.forEach(edge => {
      const style = this.getEdgeStyle(edge, config);
      const sourceId = edge.sourceId || 'unknown';
      const attrs = [
        `style="${style.style}"`,
        `color="${style.color}"`,
        `penwidth=2`,
      ];
      if (config.includeMetadata) {
        attrs.push(`label="${edge.type}"`);
      }
      if (style.tooltip) {
        attrs.push(`tooltip="${style.tooltip}"`);
      }
      lines.push(`    "${sourceId}" -> "${edge.targetId}" [${attrs.join(',')}];`);
    });

    lines.push('}');
    return lines.join('\n');
  }

  public generateTimeline(stateIds: string[], config: VisualizationConfig): string {
    const operations = stateIds.flatMap(id => this.historyService.getOperationHistory(id));
    operations.sort((a, b) => a.timestamp - b.timestamp);

    if (operations.length === 0) {
      return '';
    }

    switch (config.format) {
      case 'mermaid':
        return this.generateMermaidTimeline(operations, config);
      case 'dot':
        return this.generateDotTimeline(operations, config);
      case 'json':
        return JSON.stringify(operations, null, 2);
      default:
        throw new Error(`Unsupported format: ${config.format}`);
    }
  }

  private generateMermaidTimeline(operations: StateOperation[], config: VisualizationConfig): string {
    const lines: string[] = [
      'gantt',
      '    dateFormat X',
      '    axisFormat %s',
      '',
    ];

    // Group operations by state
    const stateGroups = new Map<string, StateOperation[]>();
    operations.forEach(op => {
      if (!stateGroups.has(op.stateId)) {
        stateGroups.set(op.stateId, []);
      }
      stateGroups.get(op.stateId)!.push(op);
    });

    // Add sections for each state
    stateGroups.forEach((stateOps, stateId) => {
      lines.push(`    section ${stateId}`);
      
      stateOps.forEach((op, index) => {
        const duration = index < stateOps.length - 1 ? stateOps[index + 1].timestamp - op.timestamp : 1000;
        const taskId = `${stateId}_${op.type}_${op.timestamp}`;
        const label = config.includeTimestamps
          ? `${op.type} (${op.timestamp})`
          : op.type;
        
        lines.push(`    ${label} :${taskId}, ${op.timestamp}, ${duration}ms`);
      });
      
      lines.push('');
    });

    return lines.join('\n');
  }

  private generateDotTimeline(operations: StateOperation[], config: VisualizationConfig): string {
    const lines: string[] = ['digraph G {'];
    lines.push('    rankdir=LR;');
    
    // Add nodes for each operation
    operations.forEach((op, index) => {
      const label = config.includeTimestamps
        ? `${op.type}\\n${op.timestamp}`
        : op.type;
      lines.push(`    "op_${index}" [label="${label}"];`);
      
      // Add edge to next operation if it exists
      if (index < operations.length - 1) {
        lines.push(`    "op_${index}" -> "op_${index + 1}";`);
      }
    });
    
    lines.push('}');
    return lines.join('\n');
  }

  public getMetrics(timeRange?: { start: number; end: number }): StateMetrics {
    // Get all operations within time range
    const operations = this.historyService.queryHistory({
      timeRange,
    });

    // Calculate metrics
    const metrics: StateMetrics = {
      totalStates: 0,
      statesByType: {},
      averageTransformationsPerState: 0,
      maxTransformationChainLength: 0,
      averageChildrenPerState: 0,
      maxTreeDepth: 0,
      operationFrequency: {},
    };

    if (operations.length === 0) {
      return metrics;
    }

    // Count unique states and their types
    const stateIds = new Set<string>();
    const stateTypes = new Map<string, number>();
    const transformationsPerState = new Map<string, number>();
    const operationCounts = new Map<string, number>();

    operations.forEach(op => {
      // Count states
      stateIds.add(op.stateId);

      // Count state types
      if ((op.type === 'create' || op.type === 'merge') && op.source) {
        stateTypes.set(op.source, (stateTypes.get(op.source) || 0) + 1);
      }

      // Count transformations per state
      if (op.type === 'transform') {
        transformationsPerState.set(op.stateId, (transformationsPerState.get(op.stateId) || 0) + 1);
      }

      // Count operation frequencies
      operationCounts.set(op.type, (operationCounts.get(op.type) || 0) + 1);
    });

    // Calculate tree depth metrics
    const stateLineages = Array.from(stateIds)
      .map(id => this.trackingService.getStateLineage(id))
      .filter(lineage => lineage && lineage.length > 0); // Filter out undefined or empty lineages

    const maxDepth = stateLineages.length > 0
      ? Math.max(...stateLineages.map(lineage => lineage.length))
      : 0;
    
    // Calculate children per state
    const childrenCounts = new Map<string, number>();
    stateLineages.forEach(lineage => {
      if (lineage.length > 1) {
        const parentId = lineage[lineage.length - 2];
        childrenCounts.set(parentId, (childrenCounts.get(parentId) || 0) + 1);
      }
    });

    // Set metrics
    metrics.totalStates = stateIds.size;
    metrics.statesByType = Object.fromEntries(stateTypes);
    metrics.averageTransformationsPerState = stateIds.size > 0
      ? Array.from(transformationsPerState.values()).reduce((a, b) => a + b, 0) / stateIds.size
      : 0;
    metrics.maxTransformationChainLength = transformationsPerState.size > 0
      ? Math.max(...Array.from(transformationsPerState.values()))
      : 0;
    metrics.averageChildrenPerState = childrenCounts.size > 0
      ? Array.from(childrenCounts.values()).reduce((a, b) => a + b, 0) / childrenCounts.size
      : 0;
    metrics.maxTreeDepth = maxDepth;
    metrics.operationFrequency = Object.fromEntries(operationCounts);

    return metrics;
  }

  public exportStateGraph(config: VisualizationConfig): string {
    // TODO: Implement complete graph export
    return '';
  }

  /**
   * Generate a context hierarchy visualization showing context boundaries
   * @param rootStateId - The root state to start visualization from
   * @param config - Context visualization configuration
   * @returns Context hierarchy visualization in the specified format
   */
  public visualizeContextHierarchy(rootStateId: string, config: ContextVisualizationConfig): string {
    // Get the hierarchy information from the tracking service
    const hierarchyInfo = this.trackingService.getContextHierarchy(rootStateId);
    
    // Generate visualization based on the format
    switch (config.format) {
      case 'mermaid':
        return this.generateMermaidContextHierarchy(hierarchyInfo, config);
      case 'dot':
        return this.generateDotContextHierarchy(hierarchyInfo, config);
      case 'json':
        return JSON.stringify(hierarchyInfo, null, 2);
      default:
        throw new Error(`Unsupported format: ${config.format}`);
    }
  }

  /**
   * Generate a variable propagation visualization showing how variables move across contexts
   * @param variableName - The name of the variable to track propagation for
   * @param rootStateId - Optional root state to limit visualization scope
   * @param config - Context visualization configuration
   * @returns Variable propagation visualization in the specified format
   */
  public visualizeVariablePropagation(variableName: string, rootStateId?: string, config?: ContextVisualizationConfig): string {
    const defaultConfig: ContextVisualizationConfig = {
      format: 'mermaid',
      includeVars: true,
      filterToRelevantVars: true,
      includeTimestamps: true,
      includeFilePaths: true
    };
    
    const mergedConfig = { ...defaultConfig, ...config };
    
    // Get all states or limit to the subtree from rootStateId
    let states: StateMetadata[] = [];
    
    if (rootStateId) {
      const hierarchyInfo = this.trackingService.getContextHierarchy(rootStateId);
      states = hierarchyInfo.states;
    } else {
      states = this.trackingService.getAllStates();
    }
    
    // Get all variable crossings for the specified variable
    const allCrossings = states.flatMap(state => 
      this.trackingService.getVariableCrossings(state.id)
    );
    
    // Filter to just the specified variable
    const variableCrossings = allCrossings.filter(
      crossing => crossing.variableName === variableName
    );
    
    // If there are no crossings, return a simple message
    if (variableCrossings.length === 0) {
      return `// No variable crossings found for variable "${variableName}"`;
    }
    
    // Generate visualization based on the format
    switch (mergedConfig.format) {
      case 'mermaid':
        return this.generateMermaidVariablePropagation(variableName, states, variableCrossings, mergedConfig);
      case 'dot':
        return this.generateDotVariablePropagation(variableName, states, variableCrossings, mergedConfig);
      case 'json':
        return JSON.stringify({ variableName, states, crossings: variableCrossings }, null, 2);
      default:
        throw new Error(`Unsupported format: ${mergedConfig.format}`);
    }
  }

  /**
   * Generate a combined context and variable flow visualization
   * @param rootStateId - The root state to start visualization from
   * @param config - Context visualization configuration
   * @returns Combined context and variable flow visualization
   */
  public visualizeContextsAndVariableFlow(rootStateId: string, config: ContextVisualizationConfig): string {
    // Get the hierarchy information from the tracking service
    const hierarchyInfo = this.trackingService.getContextHierarchy(rootStateId);
    
    // Generate visualization based on the format
    switch (config.format) {
      case 'mermaid':
        return this.generateMermaidContextsAndFlow(hierarchyInfo, config);
      case 'dot':
        return this.generateDotContextsAndFlow(hierarchyInfo, config);
      case 'json':
        return JSON.stringify(hierarchyInfo, null, 2);
      default:
        throw new Error(`Unsupported format: ${config.format}`);
    }
  }

  /**
   * Generate a resolution path timeline visualization for a specific variable
   * @param variableName - The name of the variable to track resolution for
   * @param rootStateId - Optional root state to limit visualization scope
   * @param config - Context visualization configuration
   * @returns Resolution path timeline visualization
   */
  public visualizeResolutionPathTimeline(variableName: string, rootStateId?: string, config?: ContextVisualizationConfig): string {
    const defaultConfig: ContextVisualizationConfig = {
      format: 'mermaid',
      includeVars: true,
      includeTimestamps: true,
      includeFilePaths: true
    };
    
    const mergedConfig = { ...defaultConfig, ...config };
    
    // Get all states or limit to the subtree from rootStateId
    let states: StateMetadata[] = [];
    
    if (rootStateId) {
      const hierarchyInfo = this.trackingService.getContextHierarchy(rootStateId);
      states = hierarchyInfo.states;
    } else {
      states = this.trackingService.getAllStates();
    }
    
    // Get all variable crossings for the specified variable
    const allCrossings = states.flatMap(state => 
      this.trackingService.getVariableCrossings(state.id)
    );
    
    // Filter to just the specified variable
    const variableCrossings = allCrossings.filter(
      crossing => crossing.variableName === variableName
    );
    
    // If there are no crossings, return a simple message
    if (variableCrossings.length === 0) {
      return `// No variable crossings found for variable "${variableName}"`;
    }
    
    // Generate visualization based on the format
    switch (mergedConfig.format) {
      case 'mermaid':
        return this.generateMermaidResolutionTimeline(variableName, states, variableCrossings, mergedConfig);
      case 'dot':
        return this.generateDotResolutionTimeline(variableName, states, variableCrossings, mergedConfig);
      case 'json':
        return JSON.stringify({ variableName, states, crossings: variableCrossings }, null, 2);
      default:
        throw new Error(`Unsupported format: ${mergedConfig.format}`);
    }
  }

  /**
   * Generate a Mermaid diagram for context hierarchy
   * @private
   */
  private generateMermaidContextHierarchy(hierarchyInfo: ContextHierarchyInfo, config: ContextVisualizationConfig): string {
    const { states, boundaries } = hierarchyInfo;
    
    let mermaid = 'graph TD\n';
    
    // Add states as nodes
    states.forEach(state => {
      const label = this.formatStateLabel(state, config);
      mermaid += `  ${state.id}["${label}"]\n`;
      mermaid += `  style ${state.id} ${this.getContextNodeStyle(state, config)}\n`;
    });
    
    // Add boundaries as edges
    boundaries.forEach(boundary => {
      const style = this.getContextBoundaryStyle(boundary, config);
      
      let label = '';
      if (config.includeBoundaryTypes) {
        label = ` |${boundary.boundaryType}|`;
      }
      
      mermaid += `  ${boundary.sourceStateId} --> ${boundary.targetStateId}${label}\n`;
    });
    
    // Add variable crossings if requested
    if (config.includeVars && hierarchyInfo.variableCrossings.length > 0) {
      mermaid += '\n  %% Variable crossings\n';
      
      hierarchyInfo.variableCrossings.forEach(crossing => {
        const sourceNodeId = crossing.sourceStateId;
        const targetNodeId = crossing.targetStateId;
        
        let label = `${crossing.variableName}`;
        if (crossing.alias && crossing.alias !== crossing.variableName) {
          label += ` as ${crossing.alias}`;
        }
        
        mermaid += `  ${sourceNodeId} -. "${label}" .-> ${targetNodeId}\n`;
      });
    }
    
    return mermaid;
  }

  /**
   * Generate a DOT diagram for context hierarchy
   * @private
   */
  private generateDotContextHierarchy(hierarchyInfo: ContextHierarchyInfo, config: ContextVisualizationConfig): string {
    const { states, boundaries } = hierarchyInfo;
    
    let dot = 'digraph ContextHierarchy {\n';
    dot += '  rankdir=TB;\n';
    dot += '  node [shape=box, style=filled, fontname="Arial"];\n';
    
    // Add states as nodes
    states.forEach(state => {
      const label = this.formatStateLabel(state, config);
      dot += `  "${state.id}" [label="${label}" ${this.getContextNodeStyleDot(state, config)}];\n`;
    });
    
    // Add boundaries as edges
    boundaries.forEach(boundary => {
      let label = '';
      if (config.includeBoundaryTypes) {
        label = `label="${boundary.boundaryType}"`;
      }
      
      dot += `  "${boundary.sourceStateId}" -> "${boundary.targetStateId}" [${label} ${this.getContextBoundaryStyleDot(boundary, config)}];\n`;
    });
    
    // Add variable crossings if requested
    if (config.includeVars && hierarchyInfo.variableCrossings.length > 0) {
      dot += '\n  // Variable crossings\n';
      
      hierarchyInfo.variableCrossings.forEach(crossing => {
        const sourceNodeId = crossing.sourceStateId;
        const targetNodeId = crossing.targetStateId;
        
        let label = `${crossing.variableName}`;
        if (crossing.alias && crossing.alias !== crossing.variableName) {
          label += ` as ${crossing.alias}`;
        }
        
        dot += `  "${sourceNodeId}" -> "${targetNodeId}" [label="${label}", style=dashed, color=blue];\n`;
      });
    }
    
    dot += '}\n';
    
    return dot;
  }

  /**
   * Generate a Mermaid diagram for variable propagation
   * @private
   */
  private generateMermaidVariablePropagation(
    variableName: string, 
    states: StateMetadata[], 
    crossings: VariableCrossing[], 
    config: ContextVisualizationConfig
  ): string {
    // Create a map for quick state lookup
    const stateMap = new Map<string, StateMetadata>();
    states.forEach(state => stateMap.set(state.id, state));
    
    let mermaid = `graph TD\n  %% Variable propagation for "${variableName}"\n`;
    
    // Add states involved in crossings
    const involvedStateIds = new Set<string>();
    crossings.forEach(crossing => {
      involvedStateIds.add(crossing.sourceStateId);
      involvedStateIds.add(crossing.targetStateId);
    });
    
    // Add states as nodes
    Array.from(involvedStateIds).forEach(stateId => {
      const state = stateMap.get(stateId);
      if (state) {
        const label = this.formatStateLabel(state, config);
        mermaid += `  ${state.id}["${label}"]\n`;
        mermaid += `  style ${state.id} ${this.getContextNodeStyle(state, config)}\n`;
      }
    });
    
    // Add crossings as edges
    crossings.forEach(crossing => {
      const sourceNodeId = crossing.sourceStateId;
      const targetNodeId = crossing.targetStateId;
      
      let label = variableName;
      if (crossing.alias && crossing.alias !== variableName) {
        label += ` as ${crossing.alias}`;
      }
      
      let edge = '';
      if (crossing.variableType === 'text') {
        edge = ` -. "${label} (text)" .-> `;
      } else if (crossing.variableType === 'data') {
        edge = ` -. "${label} (data)" .-> `;
      } else if (crossing.variableType === 'path') {
        edge = ` -. "${label} (path)" .-> `;
      } else {
        edge = ` -. "${label}" .-> `;
      }
      
      mermaid += `  ${sourceNodeId}${edge}${targetNodeId}\n`;
    });
    
    return mermaid;
  }

  /**
   * Generate a DOT diagram for variable propagation
   * @private
   */
  private generateDotVariablePropagation(
    variableName: string, 
    states: StateMetadata[], 
    crossings: VariableCrossing[], 
    config: ContextVisualizationConfig
  ): string {
    // Create a map for quick state lookup
    const stateMap = new Map<string, StateMetadata>();
    states.forEach(state => stateMap.set(state.id, state));
    
    let dot = `digraph VariablePropagation {\n  // Variable propagation for "${variableName}"\n`;
    dot += '  rankdir=TB;\n';
    dot += '  node [shape=box, style=filled, fontname="Arial"];\n';
    
    // Add states involved in crossings
    const involvedStateIds = new Set<string>();
    crossings.forEach(crossing => {
      involvedStateIds.add(crossing.sourceStateId);
      involvedStateIds.add(crossing.targetStateId);
    });
    
    // Add states as nodes
    Array.from(involvedStateIds).forEach(stateId => {
      const state = stateMap.get(stateId);
      if (state) {
        const label = this.formatStateLabel(state, config);
        dot += `  "${state.id}" [label="${label}" ${this.getContextNodeStyleDot(state, config)}];\n`;
      }
    });
    
    // Add crossings as edges
    crossings.forEach(crossing => {
      const sourceNodeId = crossing.sourceStateId;
      const targetNodeId = crossing.targetStateId;
      
      let label = variableName;
      if (crossing.alias && crossing.alias !== variableName) {
        label += ` as ${crossing.alias}`;
      }
      
      if (crossing.variableType) {
        label += ` (${crossing.variableType})`;
      }
      
      dot += `  "${sourceNodeId}" -> "${targetNodeId}" [label="${label}", style=dashed, color=blue];\n`;
    });
    
    dot += '}\n';
    
    return dot;
  }

  /**
   * Generate a Mermaid diagram for combined context and variable flow
   * @private
   */
  private generateMermaidContextsAndFlow(hierarchyInfo: ContextHierarchyInfo, config: ContextVisualizationConfig): string {
    const { states, boundaries, variableCrossings } = hierarchyInfo;
    
    let mermaid = 'graph TD\n';
    
    // Add states as nodes
    states.forEach(state => {
      const label = this.formatStateLabel(state, config);
      mermaid += `  ${state.id}["${label}"]\n`;
      mermaid += `  style ${state.id} ${this.getContextNodeStyle(state, config)}\n`;
    });
    
    // Add boundaries as edges
    boundaries.forEach(boundary => {
      const style = this.getContextBoundaryStyle(boundary, config);
      
      let label = '';
      if (config.includeBoundaryTypes) {
        label = ` |${boundary.boundaryType}|`;
      }
      
      mermaid += `  ${boundary.sourceStateId} --> ${boundary.targetStateId}${label}\n`;
    });
    
    // Group variable crossings by variable name
    const crossingsByVariable = new Map<string, VariableCrossing[]>();
    
    variableCrossings.forEach(crossing => {
      if (!crossingsByVariable.has(crossing.variableName)) {
        crossingsByVariable.set(crossing.variableName, []);
      }
      
      crossingsByVariable.get(crossing.variableName)!.push(crossing);
    });
    
    // Add variable crossings grouped by variable
    if (config.includeVars && variableCrossings.length > 0) {
      mermaid += '\n  %% Variable flows\n';
      
      crossingsByVariable.forEach((crossings, variableName) => {
        mermaid += `  %% Flow for variable "${variableName}"\n`;
        
        crossings.forEach(crossing => {
          const sourceNodeId = crossing.sourceStateId;
          const targetNodeId = crossing.targetStateId;
          
          let label = variableName;
          if (crossing.alias && crossing.alias !== variableName) {
            label += ` as ${crossing.alias}`;
          }
          
          mermaid += `  ${sourceNodeId} -. "${label}" .-> ${targetNodeId}\n`;
        });
      });
    }
    
    return mermaid;
  }

  /**
   * Generate a DOT diagram for combined context and variable flow
   * @private
   */
  private generateDotContextsAndFlow(hierarchyInfo: ContextHierarchyInfo, config: ContextVisualizationConfig): string {
    const { states, boundaries, variableCrossings } = hierarchyInfo;
    
    let dot = 'digraph ContextsAndVariableFlow {\n';
    dot += '  rankdir=TB;\n';
    dot += '  node [shape=box, style=filled, fontname="Arial"];\n';
    
    // Add states as nodes
    states.forEach(state => {
      const label = this.formatStateLabel(state, config);
      dot += `  "${state.id}" [label="${label}" ${this.getContextNodeStyleDot(state, config)}];\n`;
    });
    
    // Add boundaries as edges
    boundaries.forEach(boundary => {
      let label = '';
      if (config.includeBoundaryTypes) {
        label = `label="${boundary.boundaryType}"`;
      }
      
      dot += `  "${boundary.sourceStateId}" -> "${boundary.targetStateId}" [${label} ${this.getContextBoundaryStyleDot(boundary, config)}];\n`;
    });
    
    // Group variable crossings by variable name
    const crossingsByVariable = new Map<string, VariableCrossing[]>();
    
    variableCrossings.forEach(crossing => {
      if (!crossingsByVariable.has(crossing.variableName)) {
        crossingsByVariable.set(crossing.variableName, []);
      }
      
      crossingsByVariable.get(crossing.variableName)!.push(crossing);
    });
    
    // Add variable crossings grouped by variable
    if (config.includeVars && variableCrossings.length > 0) {
      dot += '\n  // Variable flows\n';
      
      crossingsByVariable.forEach((crossings, variableName) => {
        dot += `  // Flow for variable "${variableName}"\n`;
        
        crossings.forEach(crossing => {
          const sourceNodeId = crossing.sourceStateId;
          const targetNodeId = crossing.targetStateId;
          
          let label = variableName;
          if (crossing.alias && crossing.alias !== variableName) {
            label += ` as ${crossing.alias}`;
          }
          
          dot += `  "${sourceNodeId}" -> "${targetNodeId}" [label="${label}", style=dashed, color=blue];\n`;
        });
      });
    }
    
    dot += '}\n';
    
    return dot;
  }

  /**
   * Generate a Mermaid timeline diagram for variable resolution
   * @private
   */
  private generateMermaidResolutionTimeline(
    variableName: string, 
    states: StateMetadata[], 
    crossings: VariableCrossing[], 
    config: ContextVisualizationConfig
  ): string {
    // Create a map for quick state lookup
    const stateMap = new Map<string, StateMetadata>();
    states.forEach(state => stateMap.set(state.id, state));
    
    // Sort crossings by timestamp
    const sortedCrossings = [...crossings].sort((a, b) => a.timestamp - b.timestamp);
    
    let mermaid = `gantt\n  title Resolution Timeline for "${variableName}"\n`;
    mermaid += `  dateFormat X\n`;
    mermaid += `  axisFormat %s\n`;
    
    // Define context sections
    const contextIds = new Set<string>();
    crossings.forEach(crossing => {
      contextIds.add(crossing.sourceStateId);
      contextIds.add(crossing.targetStateId);
    });
    
    // Add context sections
    Array.from(contextIds).forEach(stateId => {
      const state = stateMap.get(stateId);
      if (state) {
        const contextName = state.filePath ? `${state.id} (${state.filePath})` : state.id;
        mermaid += `  section ${contextName}\n`;
        
        // Find all crossings where this state is involved
        const relevantCrossings = sortedCrossings.filter(
          crossing => crossing.sourceStateId === stateId || crossing.targetStateId === stateId
        );
        
        if (relevantCrossings.length === 0) {
          mermaid += `  No crossings : 0, 0\n`;
        } else {
          relevantCrossings.forEach(crossing => {
            const direction = crossing.sourceStateId === stateId ? 'out' : 'in';
            const otherStateId = direction === 'out' ? crossing.targetStateId : crossing.sourceStateId;
            
            const description = `${direction === 'out' ? 'Export to' : 'Import from'} ${otherStateId}`;
            
            // For timelines, use the timestamp directly
            const timestamp = crossing.timestamp;
            const duration = 10; // Small fixed duration for visibility
            
            mermaid += `  ${description} : ${timestamp}, ${timestamp + duration}\n`;
          });
        }
      }
    });
    
    return mermaid;
  }

  /**
   * Generate a DOT timeline diagram for variable resolution
   * @private
   */
  private generateDotResolutionTimeline(
    variableName: string, 
    states: StateMetadata[], 
    crossings: VariableCrossing[], 
    config: ContextVisualizationConfig
  ): string {
    // Create a map for quick state lookup
    const stateMap = new Map<string, StateMetadata>();
    states.forEach(state => stateMap.set(state.id, state));
    
    // Sort crossings by timestamp
    const sortedCrossings = [...crossings].sort((a, b) => a.timestamp - b.timestamp);
    
    let dot = `digraph ResolutionTimeline {\n  label="Resolution Timeline for "${variableName}"\n`;
    dot += '  rankdir=LR;\n';
    dot += '  node [shape=box, style=filled, fontname="Arial"];\n';
    
    // Create a timeline node for each crossing
    sortedCrossings.forEach((crossing, index) => {
      const sourceState = stateMap.get(crossing.sourceStateId);
      const targetState = stateMap.get(crossing.targetStateId);
      
      const sourceLabel = sourceState?.filePath ? `${crossing.sourceStateId} (${sourceState.filePath})` : crossing.sourceStateId;
      const targetLabel = targetState?.filePath ? `${crossing.targetStateId} (${targetState.filePath})` : crossing.targetStateId;
      
      const eventTime = new Date(crossing.timestamp).toISOString().replace('T', ' ').substring(0, 19);
      const label = `${eventTime}\\n${variableName}${crossing.alias ? ` as ${crossing.alias}` : ''}`;
      
      dot += `  "event${index}" [label="${label}", shape=circle, color=lightblue];\n`;
      
      // Add edge from source to event
      dot += `  "${crossing.sourceStateId}" -> "event${index}" [label="export", style=dashed];\n`;
      
      // Add edge from event to target
      dot += `  "event${index}" -> "${crossing.targetStateId}" [label="import", style=dashed];\n`;
      
      // Add node labels if first occurrence
      if (!dot.includes(`"${crossing.sourceStateId}" [`)) {
        dot += `  "${crossing.sourceStateId}" [label="${sourceLabel}", ${this.getContextNodeStyleDot(sourceState!, config)}];\n`;
      }
      
      if (!dot.includes(`"${crossing.targetStateId}" [`)) {
        dot += `  "${crossing.targetStateId}" [label="${targetLabel}", ${this.getContextNodeStyleDot(targetState!, config)}];\n`;
      }
    });
    
    // Add timeline constraint
    if (sortedCrossings.length > 1) {
      dot += '\n  // Timeline ordering\n';
      dot += '  { rank=same; ';
      
      for (let i = 0; i < sortedCrossings.length; i++) {
        dot += `"event${i}" `;
      }
      
      dot += '}\n';
      
      // Add invisible edges for timeline ordering
      for (let i = 0; i < sortedCrossings.length - 1; i++) {
        dot += `  "event${i}" -> "event${i+1}" [style=invis];\n`;
      }
    }
    
    dot += '}\n';
    
    return dot;
  }

  /**
   * Format a state label for visualization
   * @private
   */
  private formatStateLabel(state: StateMetadata, config: ContextVisualizationConfig): string {
    let label = state.id;
    
    if (config.includeFilePaths && state.filePath) {
      label += `\\n${state.filePath}`;
    }
    
    if (config.includeTimestamps && state.createdAt) {
      const date = new Date(state.createdAt);
      label += `\\n${date.toISOString().replace('T', ' ').substring(0, 19)}`;
    }
    
    return label;
  }

  /**
   * Get Mermaid style string for a context node
   * @private
   */
  private getContextNodeStyle(state: StateMetadata, config: ContextVisualizationConfig): string {
    let style = '';
    
    // Style based on state source
    switch (state.source) {
      case 'new':
        style = 'fill:#e1f5fe,stroke:#01579b';
        break;
      case 'clone':
        style = 'fill:#fff9c4,stroke:#fbc02d';
        break;
      case 'child':
        style = 'fill:#c8e6c9,stroke:#388e3c';
        break;
      case 'merge':
        style = 'fill:#f8bbd0,stroke:#c2185b';
        break;
      case 'implicit':
        style = 'fill:#d1c4e9,stroke:#512da8';
        break;
      default:
        style = 'fill:#f5f5f5,stroke:#616161';
    }
    
    return style;
  }

  /**
   * Get DOT style string for a context node
   * @private
   */
  private getContextNodeStyleDot(state: StateMetadata, config: ContextVisualizationConfig): string {
    let fillColor = '';
    let strokeColor = '';
    
    // Style based on state source
    switch (state.source) {
      case 'new':
        fillColor = '#e1f5fe';
        strokeColor = '#01579b';
        break;
      case 'clone':
        fillColor = '#fff9c4';
        strokeColor = '#fbc02d';
        break;
      case 'child':
        fillColor = '#c8e6c9';
        strokeColor = '#388e3c';
        break;
      case 'merge':
        fillColor = '#f8bbd0';
        strokeColor = '#c2185b';
        break;
      case 'implicit':
        fillColor = '#d1c4e9';
        strokeColor = '#512da8';
        break;
      default:
        fillColor = '#f5f5f5';
        strokeColor = '#616161';
    }
    
    return `fillcolor="${fillColor}", color="${strokeColor}"`;
  }

  /**
   * Get Mermaid style for a context boundary edge
   * @private
   */
  private getContextBoundaryStyle(boundary: ContextBoundary, config: ContextVisualizationConfig): string {
    if (boundary.boundaryType === 'import') {
      return 'stroke:#388e3c,stroke-width:2';
    } else {
      return 'stroke:#01579b,stroke-width:2';
    }
  }

  /**
   * Get DOT style for a context boundary edge
   * @private
   */
  private getContextBoundaryStyleDot(boundary: ContextBoundary, config: ContextVisualizationConfig): string {
    if (boundary.boundaryType === 'import') {
      return 'color="#388e3c", penwidth=2';
    } else {
      return 'color="#01579b", penwidth=2';
    }
  }
} 