import { InvoiceFormat } from '../../interfaces/common.js';
import { DOMParser } from 'xmldom';
import * as xpath from 'xpath';
import { CII_PROFILE_IDS, ZUGFERD_V1_NAMESPACES } from '../cii/cii.types.js';

/**
 * Utility class for detecting invoice formats
 */
export class FormatDetector {
  /**
   * Detects the format of an XML document
   * @param xml XML content to analyze
   * @returns Detected invoice format
   */
  public 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') {
        // For simplicity, we'll treat all UBL documents as XRechnung for now
        // In a real implementation, we would check for specific customization IDs
        return InvoiceFormat.XRECHNUNG;
      }

      // Factur-X/ZUGFeRD detection (CrossIndustryInvoice or CrossIndustryDocument root element)
      if (root.nodeName === 'rsm:CrossIndustryInvoice' || root.nodeName === 'CrossIndustryInvoice') {
        // Set up namespaces for XPath queries (ZUGFeRD v2/Factur-X)
        const namespaces = {
          rsm: 'urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100',
          ram: 'urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'
        };

        // Create XPath selector with namespaces
        const select = xpath.useNamespaces(namespaces);

        // Look for profile identifier
        const profileNode = select(
          'string(//rsm:ExchangedDocumentContext/ram:GuidelineSpecifiedDocumentContextParameter/ram:ID)',
          doc
        );

        if (profileNode) {
          const profileText = profileNode.toString();

          // Check for ZUGFeRD profiles
          if (profileText.includes('zugferd') ||
              profileText === CII_PROFILE_IDS.ZUGFERD_BASIC ||
              profileText === CII_PROFILE_IDS.ZUGFERD_COMFORT ||
              profileText === CII_PROFILE_IDS.ZUGFERD_EXTENDED) {
            return InvoiceFormat.ZUGFERD;
          }

          // Check for Factur-X profiles
          if (profileText.includes('factur-x') ||
              profileText === CII_PROFILE_IDS.FACTURX_MINIMUM ||
              profileText === CII_PROFILE_IDS.FACTURX_BASIC ||
              profileText === CII_PROFILE_IDS.FACTURX_EN16931) {
            return InvoiceFormat.FACTURX;
          }
        }

        // If we can't determine the specific CII format, default to generic CII
        return InvoiceFormat.CII;
      }

      // ZUGFeRD v1 detection (CrossIndustryDocument root element)
      if (root.nodeName === 'rsm:CrossIndustryDocument' || root.nodeName === 'CrossIndustryDocument' ||
          root.nodeName === 'ram:CrossIndustryDocument') {

        // Check for ZUGFeRD v1 namespace in the document
        const xmlString = xml.toString();
        if (xmlString.includes('urn:ferd:CrossIndustryDocument:invoice:1p0') ||
            xmlString.includes('urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12')) {
          return InvoiceFormat.ZUGFERD;
        }

        // Set up namespaces for XPath queries (ZUGFeRD v1)
        try {
          const namespaces = {
            rsm: ZUGFERD_V1_NAMESPACES.RSM,
            ram: ZUGFERD_V1_NAMESPACES.RAM
          };

          // Create XPath selector with namespaces
          const select = xpath.useNamespaces(namespaces);

          // Look for profile identifier
          const profileNode = select(
            'string(//rsm:SpecifiedExchangedDocumentContext/ram:GuidelineSpecifiedDocumentContextParameter/ram:ID)',
            doc
          );

          if (profileNode) {
            const profileText = profileNode.toString();

            // Check for ZUGFeRD v1 profiles
            if (profileText.includes('ferd:CrossIndustryDocument:invoice:1p0') ||
                profileText === CII_PROFILE_IDS.ZUGFERD_V1_BASIC ||
                profileText === CII_PROFILE_IDS.ZUGFERD_V1_COMFORT ||
                profileText === CII_PROFILE_IDS.ZUGFERD_V1_EXTENDED) {
              return InvoiceFormat.ZUGFERD;
            }
          }
        } catch (error) {
          console.log('Error in ZUGFeRD v1 XPath detection:', error);
        }

        // If we can't determine the specific profile but it's a CrossIndustryDocument, it's likely ZUGFeRD v1
        return InvoiceFormat.ZUGFERD;
      }

      // FatturaPA detection would be implemented here
      if (root.nodeName === 'FatturaElettronica' ||
          (root.getAttribute('xmlns') && root.getAttribute('xmlns')!.includes('fatturapa.gov.it'))) {
        return InvoiceFormat.FATTURAPA;
      }

      return InvoiceFormat.UNKNOWN;
    } catch (error) {
      console.error('Error detecting format:', error);
      return InvoiceFormat.UNKNOWN;
    }
  }
}
