import { InvoiceFormat } from '../interfaces.js';
import type { IValidator } from '../interfaces.js';
import { BaseValidator } from './base.validator.js';
import { FacturXValidator } from './facturx.validator.js';
import { UBLValidator } from './ubl.validator.js';
import { DOMParser } from 'xmldom';

/**
 * Factory to create the appropriate validator based on the XML format
 */
export class ValidatorFactory {
  /**
   * Creates a validator for the specified XML content
   * @param xml XML content to validate
   * @returns Appropriate validator instance
   */
  public static createValidator(xml: string): BaseValidator {
    const format = ValidatorFactory.detectFormat(xml);
    
    switch (format) {
      case InvoiceFormat.UBL:
      case InvoiceFormat.XRECHNUNG:
        return new UBLValidator(xml);
        
      case InvoiceFormat.CII:
      case InvoiceFormat.ZUGFERD:
      case InvoiceFormat.FACTURX:
        return new FacturXValidator(xml);
        
      // FatturaPA and other formats would be implemented here
        
      default:
        throw new Error(`Unsupported invoice format: ${format}`);
    }
  }
  
  /**
   * Detects the invoice format from XML content
   * @param xml XML content to analyze
   * @returns Detected invoice format
   */
  private static detectFormat(xml: string): InvoiceFormat {
    try {
      const doc = new DOMParser().parseFromString(xml, 'application/xml');
      const root = doc.documentElement;
      
      if (!root) {
        return InvoiceFormat.UNKNOWN;
      }
      
      // UBL detection (Invoice or CreditNote root element)
      if (root.nodeName === 'Invoice' || root.nodeName === 'CreditNote') {
        // Check if it's XRechnung by looking at CustomizationID
        const customizationNodes = root.getElementsByTagName('cbc:CustomizationID');
        if (customizationNodes.length > 0) {
          const customizationId = customizationNodes[0].textContent || '';
          if (customizationId.includes('xrechnung') || customizationId.includes('XRechnung')) {
            return InvoiceFormat.XRECHNUNG;
          }
        }
        
        return InvoiceFormat.UBL;
      }
      
      // Factur-X/ZUGFeRD detection (CrossIndustryInvoice root element)
      if (root.nodeName === 'rsm:CrossIndustryInvoice' || root.nodeName === 'CrossIndustryInvoice') {
        // Check for profile to determine if it's Factur-X or ZUGFeRD
        const profileNodes = root.getElementsByTagName('ram:ID');
        for (let i = 0; i < profileNodes.length; i++) {
          const profileText = profileNodes[i].textContent || '';
          
          if (profileText.includes('factur-x') || profileText.includes('Factur-X')) {
            return InvoiceFormat.FACTURX;
          }
          
          if (profileText.includes('zugferd') || profileText.includes('ZUGFeRD')) {
            return InvoiceFormat.ZUGFERD;
          }
        }
        
        // If no specific profile found, default to CII
        return InvoiceFormat.CII;
      }
      
      // FatturaPA detection would be implemented here
      
      return InvoiceFormat.UNKNOWN;
    } catch (error) {
      return InvoiceFormat.UNKNOWN;
    }
  }
}