import * as plugins from './plugins.js';
import * as interfaces from './interfaces.js';
import { PDFDocument, PDFDict, PDFName, PDFRawStream } from 'pdf-lib';

export class XInvoice {
  public pdfUint8Array: Uint8Array;

  constructor(pdfBuffer:  Uint8Array | Buffer) {
    this.pdfUint8Array = Uint8Array.from(pdfBuffer);
  }

  public async embedXml(xmlString: string): Promise<void> {
    try {
      
      const pdfDoc = await PDFDocument.load(this.pdfUint8Array);

      const xmlBuffer = new TextEncoder().encode(xmlString);
      pdfDoc.attach(xmlBuffer, plugins.path.basename('invoice.xml'), {
        mimeType: 'application/xml',
        description: 'XRechnung XML Invoice',
      });

      const modifiedPdfBytes = await pdfDoc.save();
      this.pdfUint8Array = modifiedPdfBytes;
      console.log(`PDF Buffer updated with new XML attachment!`);
    } catch (error) {
      console.error('Error embedding XML into PDF:', error);
      throw error;
    }
  }

  /**
   * reads the xml part and returns parsed structured data
   * @returns {Promise<interfaces.IXInvoice>} Parsed XML data
   */
  public async getParsedXmlData(): Promise<interfaces.IXInvoice> {
    try {
      const pdfBuffer = this.pdfUint8Array;
      const pdfDoc = await PDFDocument.load(pdfBuffer);

      const namesDict = pdfDoc.catalog.get(PDFName.of('Names')) as PDFDict;
      if (!namesDict) throw new Error('No Names dictionary found in PDF!');

      const embeddedFilesDict = namesDict.get(PDFName.of('EmbeddedFiles')) as PDFDict;
      if (!embeddedFilesDict) throw new Error('No EmbeddedFiles dictionary found!');

      const filesSpecDict = embeddedFilesDict.get(PDFName.of('Names')) as PDFDict;
      if (!filesSpecDict) throw new Error('No files specified in EmbeddedFiles dictionary!');

      let xmlFile: PDFRawStream | undefined = undefined;
      const entries = filesSpecDict.entries();
      for (const [key, fileSpecValue] of entries) {
        const fileSpec = fileSpecValue as PDFDict;
        const efDict = fileSpec.get(PDFName.of('EF')) as PDFDict;
        xmlFile = efDict.get(PDFName.of('F')) as PDFRawStream;
        if (xmlFile) break;
      }

      if (!xmlFile) throw new Error('XML file stream not found!');

      const xmlBytes = xmlFile.getContents();
      const xmlContent = new TextDecoder().decode(xmlBytes);
      console.log(`Read embedded XML: ${xmlContent}`);

      return this.parseXmlToInvoice(xmlContent);
    } catch (error) {
      console.error('Error extracting or parsing embedded XML from PDF:', error);
      throw error;
    }
  }

  private parseXmlToInvoice(xmlContent: string): interfaces.IXInvoice {
    // Implement XML parsing logic here
    // Placeholder return, replace with actual parsing result
    return {
      InvoiceNumber: '12345',
      DateIssued: '2023-04-01',
      Seller: {
        Name: 'Seller Co',
        Address: {
          Street: '1234 Market St',
          City: 'Sample City',
          PostalCode: '12345',
          Country: 'DE',
        },
        Contact: {
          Email: 'contact@sellerco.com',
          Phone: '123-456-7890',
        },
      },
      Buyer: {
        Name: 'Buyer Inc',
        Address: {
          Street: '5678 Trade Rd',
          City: 'Trade City',
          PostalCode: '67890',
          Country: 'DE',
        },
        Contact: {
          Email: 'info@buyerinc.com',
          Phone: '987-654-3210',
        },
      },
      Items: [
        {
          Description: 'Item 1',
          Quantity: 10,
          UnitPrice: 9.99,
          TotalPrice: 99.9,
        },
      ],
      TotalAmount: 99.9,
    };
  }
}