import { randomUUID } from 'crypto';

export interface CodeQualityMetrics {
  complexity: number;
  maintainabilityIndex: number;
  codeDuplicationPercentage: number;
  commentDensity: number;
  functionLength: number;
}

export interface SecurityIssue {
  severity: 'HIGH' | 'MEDIUM' | 'LOW';
  description: string;
  location: string;
}

export class CodeNode {
  id: string;
  codeQualityMetrics?: CodeQualityMetrics;
  securityIssues?: SecurityIssue[];
  generatedCode?: string;

  constructor(
    public type: string,
    public value: string,
    public children: CodeNode[] = [],
    public metadata: Record<string, any> = {}
  ) {
    this.id = randomUUID();
  }

  toJSON(): any {
    return {
      id: this.id,
      type: this.type,
      value: this.value,
      children: this.children.map(child => child.toJSON()),
      metadata: this.metadata,
      codeQualityMetrics: this.codeQualityMetrics,
      securityIssues: this.securityIssues,
      generatedCode: this.generatedCode
    };
  }

  static fromJSON(json: any): CodeNode {
    if (!json || typeof json !== 'object') {
      throw new Error('Invalid JSON structure for CodeNode');
    }
    const node = new CodeNode(
      json.type || 'Unknown',
      json.value || '',
      Array.isArray(json.children) ? json.children.map((child: any) => CodeNode.fromJSON(child)) : [],
      json.metadata || {}
    );
    node.id = json.id || randomUUID();
    node.codeQualityMetrics = json.codeQualityMetrics;
    node.securityIssues = json.securityIssues;
    node.generatedCode = json.generatedCode;
    return node;
  }

  toString(indent = ''): string {
    let result = `${indent}${this.type}: ${this.value}\n`;
    for (const child of this.children) {
      result += child.toString(indent + '  ');
    }
    return result;
  }

  // Tree traversal methods
  traverse(callback: (node: CodeNode) => void): void {
    callback(this);
    for (const child of this.children) {
      child.traverse(callback);
    }
  }

  find(predicate: (node: CodeNode) => boolean): CodeNode | null {
    if (predicate(this)) {
      return this;
    }
    for (const child of this.children) {
      const found = child.find(predicate);
      if (found) {
        return found;
      }
    }
    return null;
  }

  // Serialization and deserialization
  serialize(): string {
    return JSON.stringify(this.toJSON());
  }

  static deserialize(serialized: string): CodeNode {
    return CodeNode.fromJSON(JSON.parse(serialized));
  }
}

// Utility functions for working with CodeNode structures
export function findNodeById(root: CodeNode, id: string): CodeNode | null {
  return root.find(node => node.id === id);
}

export function countNodes(root: CodeNode): number {
  let count = 1;
  root.traverse(() => count++);
  return count;
}

export function getLeafNodes(root: CodeNode): CodeNode[] {
  const leafNodes: CodeNode[] = [];
  root.traverse(node => {
    if (node.children.length === 0) {
      leafNodes.push(node);
    }
  });
  return leafNodes;
}

export function getNodeDepth(root: CodeNode, targetNode: CodeNode): number {
  let depth = -1;
  let found = false;

  function traverse(node: CodeNode, currentDepth: number) {
    if (found) return;
    if (node === targetNode) {
      depth = currentDepth;
      found = true;
      return;
    }
    for (const child of node.children) {
      traverse(child, currentDepth + 1);
    }
  }

  traverse(root, 0);
  return depth;
}

export function cloneCodeNode(node: CodeNode): CodeNode {
  return CodeNode.fromJSON(node.toJSON());
}