import { ASTNode, TagNode, TextNode, HeadingNode } from '../types';
import logger from '../utils/logger';

/**
 * Transforms LLM-XML AST back into Markdown AST format
 */
export class LLMToMarkdownTransformer {
  /**
   * Convert LLM-XML AST to Markdown AST
   * 
   * @param nodes - Array of LLM-XML AST nodes
   * @returns Array of Markdown AST nodes
   */
  public transform(nodes: ASTNode[]): ASTNode[] {
    const result: ASTNode[] = [];
    
    for (const node of nodes) {
      const converted = this.convertNode(node);
      if (Array.isArray(converted)) {
        result.push(...converted);
      } else if (converted) {
        result.push(converted);
      }
    }

    return result;
  }

  /**
   * Convert a single LLM-XML AST node to Markdown AST node(s)
   * 
   * @param node - LLM-XML AST node
   * @returns Single node, array of nodes, or null if node should be skipped
   */
  private convertNode(node: ASTNode): ASTNode | ASTNode[] | null {
    switch (node.type) {
      case 'tag':
        return this.convertTagNode(node as TagNode);
      case 'text':
        return this.convertTextNode(node as TextNode);
      default:
        logger.warn('Unknown node type', { type: node.type });
        return null;
    }
  }

  /**
   * Convert a tag node to Markdown AST nodes
   * 
   * @param node - LLM-XML tag node
   * @returns Array of Markdown AST nodes
   */
  private convertTagNode(node: TagNode): ASTNode[] {
    const result: ASTNode[] = [];

    // Create heading from tag
    const heading: HeadingNode = {
      type: 'heading',
      depth: parseInt(node.attributes?.hlevel || '1', 10),
      text: node.attributes?.title || node.name,
      children: [],
    };
    result.push(heading);

    // Convert children
    if (node.children?.length) {
      for (const child of node.children) {
        if (child.type === 'tag') {
          // For tag nodes, ensure they have the correct heading level
          const tagNode = child as TagNode;
          if (!tagNode.attributes) {
            tagNode.attributes = {};
          }
          // If hlevel is not set, use parent's level + 1
          if (!tagNode.attributes.hlevel) {
            tagNode.attributes.hlevel = String(heading.depth + 1);
          }
        }
        const converted = this.convertNode(child);
        if (Array.isArray(converted)) {
          result.push(...converted);
        } else if (converted) {
          result.push(converted);
        }
      }
    }

    return result;
  }

  /**
   * Convert a text node to Markdown AST node
   * 
   * @param node - LLM-XML text node
   * @returns Text node
   */
  private convertTextNode(node: TextNode): TextNode {
    return {
      type: 'text',
      value: node.value || '',
    };
  }
}

// Export a singleton instance
export const llmToMarkdown = new LLMToMarkdownTransformer(); 