// YAML Parser for UI Specification Files

import * as yaml from 'js-yaml';
import { readFileSync } from 'fs';
import { ComponentMetadata } from './component-registry';

export interface UIComponentSpec {
  type: string;
  variant?: string;
  props?: Record<string, any>;
  content?: string;
  components?: UIComponentSpec[];
  elements?: UIComponentSpec[];
  [key: string]: any;
}

export interface UIScreenSpec {
  name: string;
  title?: string;
  description?: string;
  workareas?: UIWorkareaSpec[];
  sections?: UISectionSpec[];
  components?: UIComponentSpec[];
  elements?: UIComponentSpec[];
}

export interface UIWorkareaSpec {
  name: string;
  sections?: UISectionSpec[];
  components?: UIComponentSpec[];
  elements?: UIComponentSpec[];
}

export interface UISectionSpec {
  name: string;
  type?: string;
  elements?: UIComponentSpec[];
  components?: UIComponentSpec[];
}

export interface UIGlobalElementSpec {
  name: string;
  type: string;
  components?: UIComponentSpec[];
  elements?: UIComponentSpec[];
}

export interface UISpecification {
  version: number;
  type: string;
  global_elements?: UIGlobalElementSpec[];
  screens: UIScreenSpec[];
}

export class YAMLParser {
  /**
   * Parse a YAML file containing UI specifications
   * @param filePath Path to the YAML file
   * @returns Parsed UI specification
   */
  static parseUISpec(filePath: string): UISpecification {
    try {
      const fileContent = readFileSync(filePath, 'utf8');
      const parsed = yaml.load(fileContent) as UISpecification;
      
      // Validate required fields
      if (!parsed.version) {
        throw new Error('Missing required field: version');
      }
      
      if (!parsed.type) {
        throw new Error('Missing required field: type');
      }
      
      if (!parsed.screens) {
        throw new Error('Missing required field: screens');
      }
      
      return parsed;
    } catch (error) {
      throw new Error(`Failed to parse YAML file ${filePath}: ${(error as Error).message}`);
    }
  }
  
  /**
   * Parse a YAML file containing layout specifications
   * @param filePath Path to the YAML file
   * @returns Parsed layout specification
   */
  static parseLayoutSpec(filePath: string): any {
    try {
      const fileContent = readFileSync(filePath, 'utf8');
      const parsed = yaml.load(fileContent);
      return parsed;
    } catch (error) {
      throw new Error(`Failed to parse layout YAML file ${filePath}: ${(error as Error).message}`);
    }
  }
  
  /**
   * Extract all component specifications from a UI specification
   * @param uiSpec Parsed UI specification
   * @returns Array of component specifications with their variants and props
   */
  static extractComponentSpecs(uiSpec: UISpecification): UIComponentSpec[] {
    const components: UIComponentSpec[] = [];
    
    // Extract from global elements
    if (uiSpec.global_elements) {
      for (const globalElement of uiSpec.global_elements) {
        if (globalElement.components) {
          components.push(...this.extractComponentsFromList(globalElement.components));
        }
        if (globalElement.elements) {
          components.push(...this.extractComponentsFromList(globalElement.elements));
        }
      }
    }
    
    // Extract from screens
    for (const screen of uiSpec.screens) {
      components.push(...this.extractComponentsFromScreen(screen));
    }
    
    return components;
  }
  
  /**
   * Extract components from a screen specification
   * @param screen Screen specification
   * @returns Array of component specifications
   */
  private static extractComponentsFromScreen(screen: UIScreenSpec): UIComponentSpec[] {
    const components: UIComponentSpec[] = [];
    
    if (screen.components) {
      components.push(...this.extractComponentsFromList(screen.components));
    }
    
    if (screen.elements) {
      components.push(...this.extractComponentsFromList(screen.elements));
    }
    
    if (screen.sections) {
      for (const section of screen.sections) {
        components.push(...this.extractComponentsFromSection(section));
      }
    }
    
    if (screen.workareas) {
      for (const workarea of screen.workareas) {
        if (workarea.components) {
          components.push(...this.extractComponentsFromList(workarea.components));
        }
        
        if (workarea.elements) {
          components.push(...this.extractComponentsFromList(workarea.elements));
        }
        
        if (workarea.sections) {
          for (const section of workarea.sections) {
            components.push(...this.extractComponentsFromSection(section));
          }
        }
      }
    }
    
    return components;
  }
  
  /**
   * Extract components from a section specification
   * @param section Section specification
   * @returns Array of component specifications
   */
  private static extractComponentsFromSection(section: UISectionSpec): UIComponentSpec[] {
    const components: UIComponentSpec[] = [];
    
    if (section.components) {
      components.push(...this.extractComponentsFromList(section.components));
    }
    
    if (section.elements) {
      components.push(...this.extractComponentsFromList(section.elements));
    }
    
    return components;
  }
  
  /**
   * Extract components from a list of component specifications
   * @param componentList List of component specifications
   * @returns Array of component specifications
   */
  private static extractComponentsFromList(componentList: UIComponentSpec[]): UIComponentSpec[] {
    const components: UIComponentSpec[] = [];
    
    for (const component of componentList) {
      components.push(component);
      
      // Recursively extract nested components
      if (component.components) {
        components.push(...this.extractComponentsFromList(component.components));
      }
      
      if (component.elements) {
        components.push(...this.extractComponentsFromList(component.elements));
      }
    }
    
    return components;
  }
  
  /**
   * Apply component variants and props to component metadata
   * @param componentMetadata Base component metadata
   * @returns Updated component metadata with variants and props applied
   */
  static applyComponentSpec(
    componentMetadata: ComponentMetadata
  ): ComponentMetadata {
    // For now, we're just returning the base metadata
    // In the future, we might want to enhance this to apply variants/props
    // to the component configuration
    return componentMetadata;
  }

  // Generate component code from UI specification
  generateComponentCode(): string {
    // Basic component generation logic
    return `import React from 'react';

export const Component = (props) => {
  return (
    <div className="component">
      Component
    </div>
  );
};
`;
  }
}

// Utility functions for common parsing tasks
export const parseUISpec = (filePath: string) => YAMLParser.parseUISpec(filePath);
export const parseLayoutSpec = (filePath: string) => YAMLParser.parseLayoutSpec(filePath);
export const extractComponentSpecs = (uiSpec: UISpecification) => YAMLParser.extractComponentSpecs(uiSpec);
