import PDFDocument from 'pdfkit';
import { Invoice } from '../../types/invoice.types';
import fs from 'fs';
import path from 'path';

export class ZUGFeRDGenerator {
  private invoice: Invoice;
  private options: {
    profile?: 'BASIC' | 'COMFORT' | 'EXTENDED';
    version?: '2.1.1' | '2.2.0';
  };

  constructor(invoice: Invoice, options: { profile?: 'BASIC' | 'COMFORT' | 'EXTENDED'; version?: '2.1.1' | '2.2.0' } = {}) {
    this.invoice = invoice;
    this.options = {
      profile: 'BASIC',
      version: '2.1.1',
      ...options
    };
  }

  /**
   * Generiert eine ZUGFeRD-konforme PDF/A-3 mit eingebettetem XML
   */
  public async generateZUGFeRDPDF(outputPath: string): Promise<void> {
    return new Promise((resolve, reject) => {
      try {
        // Erstelle PDF/A-3 Dokument
        const doc = new PDFDocument({
          size: 'A4',
          margin: 50,
          compress: false,
          bufferPages: true,
          info: {
            Title: 'ZUGFeRD Invoice',
            Author: 'Invoice Generator',
            Subject: 'Electronic Invoice',
            Creator: 'PDFKit',
            Producer: 'PDFKit',
            CreationDate: new Date(),
            ModDate: new Date()
          }
        });

        // Erstelle Write Stream
        const writeStream = fs.createWriteStream(outputPath);
        doc.pipe(writeStream);

        // Generiere PDF-Inhalt
        this.generatePDFContent(doc);

        // Generiere XML-Inhalt
        const xmlContent = this.generateXMLContent();

        // Füge XML als Attachment hinzu
        this.addXMLAttachment(doc, xmlContent);

        // Finalisiere PDF
        doc.end();

        writeStream.on('finish', () => {
          console.log(`ZUGFeRD PDF erfolgreich erstellt: ${outputPath}`);
          resolve();
        });

        writeStream.on('error', reject);
        doc.on('error', reject);

      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * Generiert den PDF-Inhalt (visuelle Darstellung)
   */
  private generatePDFContent(doc: PDFKit.PDFDocument): void {
    let currentY = 50;

    // Header
    currentY = this.drawHeader(doc, currentY);
    
    // Salutation
    currentY = this.drawSalutation(doc, currentY);
    
    // Items Table
    currentY = this.drawItemsTable(doc, currentY);
    
    // Totals
    currentY = this.drawTotals(doc, currentY);
    
    // Payment Info
    currentY = this.drawPaymentInfo(doc, currentY);
    
    // Footer
    this.drawFooter(doc, currentY);
  }

  private drawHeader(doc: PDFKit.PDFDocument, currentY: number): number {
    // Logo-Bereich (rechts)
    if (fs.existsSync('logo.png')) {
      try {
        doc.image('logo.png', 350, currentY, { width: 150 });
      } catch (error) {
        this.drawLogoPlaceholder(doc, currentY);
      }
    } else {
      this.drawLogoPlaceholder(doc, currentY);
    }
    currentY += 80;

    // Rechnungsdaten (rechts)
    const rightX = 350;
    let y = currentY - 80 + 80;

    doc.font('Helvetica-Bold').fontSize(8)
      .text('Rückfragen an:', rightX, y, { continued: false });
    y += 12;

    doc.font('Helvetica').fontSize(8)
      .text(this.invoice.sender.name, rightX, y, { continued: false });
    y += 12;
    doc.text(`Tel: ${this.invoice.sender.contactInfo.phone}`, rightX, y, { continued: false });
    y += 12;
    doc.text(`E-Mail: ${this.invoice.sender.contactInfo.email}`, rightX, y, { continued: false });

    y += 15;

    doc.fontSize(10)
      .text(`Rechnungs-Nr.: ${this.invoice.details.invoiceNumber}`, rightX, y, { continued: false });
    y += 15;
    doc.text(`Kunden-Nr.: ${this.invoice.details.customerNumber}`, rightX, y, { continued: false });
    y += 15;
    doc.text(`Rechnungsdatum: ${this.invoice.details.invoiceDate}`, rightX, y, { continued: false });
    y += 15;
    doc.text(`Lieferdatum: ${this.invoice.details.deliveryDate}`, rightX, y, { continued: false });
    y += 15;
    doc.text(`Leistungszeitraum: ${this.invoice.details.servicePeriod}`, rightX, y, { continued: false });

    // Empfänger-Adresse (links)
    const recipientY = Math.max(currentY, 160);

    const senderLine = [
      this.invoice.sender.name,
      this.invoice.sender.address.street,
      `${this.invoice.sender.address.postalCode} ${this.invoice.sender.address.city}`
    ].filter(Boolean).join(' · ');

    doc.fontSize(8)
      .text(senderLine, 50, recipientY - 20, { continued: false });

    doc.fontSize(12)
      .text(this.invoice.recipient.name, 50, recipientY, { continued: false });
    doc.text(this.invoice.recipient.address.street, 50, recipientY + 15, { continued: false });
    doc.text(`${this.invoice.recipient.address.postalCode} ${this.invoice.recipient.address.city}`, 50, recipientY + 30, { continued: false });

    return recipientY + 55;
  }

  private drawLogoPlaceholder(doc: PDFKit.PDFDocument, currentY: number): void {
    doc.font('Helvetica-Bold').fontSize(16)
      .text('LOGO', 350, currentY + 30, { continued: false });
    doc.rect(350, currentY, 150, 60).stroke();
  }

  private drawSalutation(doc: PDFKit.PDFDocument, currentY: number): number {
    doc.font('Helvetica-Bold').fontSize(10)
      .text('Rechnung', 50, currentY, { continued: false });
    currentY += 25;

    doc.font('Helvetica').fontSize(10)
      .text(this.invoice.salutation.greeting, 50, currentY, { continued: false });
    currentY += 15;
    doc.text(this.invoice.salutation.introduction, 50, currentY, { continued: false });

    return currentY + 25;
  }

  private drawItemsTable(doc: PDFKit.PDFDocument, currentY: number): number {
    const tableWidth = 480;
    const colWidths = [35, 170, 45, 45, 45, 70, 70];

    // Tabellenkopf
    doc.font('Helvetica-Bold').fontSize(8)
      .text('', 55, currentY + 8, { width: colWidths[0], continued: false })
      .text('Bezeichnung', 55 + colWidths[0], currentY + 8, { width: colWidths[1], continued: false })
      .text('Menge', 55 + colWidths[0] + colWidths[1], currentY + 8, { width: colWidths[2], align: 'center', continued: false })
      .text('Einh.', 55 + colWidths[0] + colWidths[1] + colWidths[2], currentY + 8, { width: colWidths[3], align: 'center', continued: false })
      .text('MwSt.', 55 + colWidths[0] + colWidths[1] + colWidths[2] + colWidths[3], currentY + 8, { width: colWidths[4], align: 'center', continued: false })
      .text('Einzelpreis', 55 + colWidths[0] + colWidths[1] + colWidths[2] + colWidths[3] + colWidths[4], currentY + 8, { width: colWidths[5], align: 'right', continued: false })
      .text('Summe', 55 + colWidths[0] + colWidths[1] + colWidths[2] + colWidths[3] + colWidths[4] + colWidths[5], currentY + 8, { width: colWidths[6], align: 'right', continued: false });

    currentY += 25;

    // Tabellenzeilen
    this.invoice.items.forEach((item, index) => {
      const topY = currentY + 5;

      doc.text((index + 1).toString(), 50, topY, { width: colWidths[0], align: 'center', continued: false });
      doc.text(item.description, 55 + colWidths[0], topY, { width: colWidths[1], continued: false });
      doc.text(item.quantity.toString(), 55 + colWidths[0] + colWidths[1], topY, { width: colWidths[2], align: 'center', continued: false });
      doc.text(item.unit, 55 + colWidths[0] + colWidths[1] + colWidths[2], topY, { width: colWidths[3], align: 'center', continued: false });
      doc.text(`${item.vatRate}`, 55 + colWidths[0] + colWidths[1] + colWidths[2] + colWidths[3], topY, { width: colWidths[4], align: 'center', continued: false });
      doc.text(`${item.unitPrice.toFixed(2).replace('.', ',')} ${item.currency}`, 55 + colWidths[0] + colWidths[1] + colWidths[2] + colWidths[3] + colWidths[4], topY, { width: colWidths[5], align: 'right', continued: false });
      doc.font('Helvetica-Bold').text(`${item.total.toFixed(2).replace('.', ',')} ${item.currency}`, 55 + colWidths[0] + colWidths[1] + colWidths[2] + colWidths[3] + colWidths[4] + colWidths[5], topY, { width: colWidths[6], align: 'right', continued: false });

      currentY += 20;
    });

    return currentY + 20;
  }

  private drawTotals(doc: PDFKit.PDFDocument, currentY: number): number {
    doc.moveTo(50, currentY).lineTo(550, currentY).lineWidth(0.5).stroke();
    currentY += 20;

    doc.font('Helvetica').fontSize(9)
      .text(`Nettobetrag: ${this.invoice.totals.netAmount.toFixed(2).replace('.', ',')} ${this.invoice.totals.currency}`, 50, currentY, { continued: false })
      .text(`MwSt. (${this.invoice.totals.vatRate.toFixed(2).replace('.', ',')}%): ${this.invoice.totals.vatAmount.toFixed(2).replace('.', ',')} ${this.invoice.totals.currency}`, 250, currentY, { continued: false })
      .font('Helvetica-Bold').fontSize(12)
      .text(`Gesamtbetrag: ${this.invoice.totals.grossAmount.toFixed(2).replace('.', ',')} ${this.invoice.totals.currency}`, 450, currentY, { continued: false });

    return currentY + 40;
  }

  private drawPaymentInfo(doc: PDFKit.PDFDocument, currentY: number): number {
    const paymentText = `Zahlbar ohne Abzug bis zum ${this.invoice.paymentInfo.dueDate}.`;

    doc.font('Helvetica').fontSize(10)
      .text(paymentText, 50, currentY, { continued: false });

    currentY += 30;

    doc.text('Mit freundlichen Grüßen', 50, currentY, { continued: false });
    currentY += 15;
    doc.text(this.invoice.sender.name, 50, currentY, { continued: false });

    return currentY + 40;
  }

  private drawFooter(doc: PDFKit.PDFDocument, currentY: number): void {
    const footerY = 720;
    const footerStartY = footerY + 20;
    const colWidth = 125;

    // Spalte 1 - Firmeninfo
             doc.font('Helvetica-Bold').fontSize(7)
           .text(this.invoice.sender.company || this.invoice.sender.name, 50, footerStartY, { continued: false })
      .font('Helvetica')
      .text(this.invoice.sender.name, 50, footerStartY + 12, { continued: false })
      .text(this.invoice.sender.address.street, 50, footerStartY + 24, { continued: false })
      .text(`${this.invoice.sender.address.postalCode} ${this.invoice.sender.address.city}`, 50, footerStartY + 36, { continued: false });

    // Spalte 2 - Kontaktdaten
    doc.fontSize(7)
      .text(`Tel.: ${this.invoice.sender.contactInfo.phone}`, 50 + colWidth, footerStartY, { continued: false })
      .text(`Email: ${this.invoice.sender.contactInfo.email}`, 50 + colWidth, footerStartY + 12, { continued: false })
      .text(`Web: ${this.invoice.sender.contactInfo.website}`, 50 + colWidth, footerStartY + 24, { continued: false });

    // Spalte 3 - Geschäftsinhaber und USt-IdNr.
    doc.fontSize(7)
      .text('Geschäftsinhaber:', 50 + 2 * colWidth, footerStartY, { continued: false })
      .text(this.invoice.sender.businessOwner || '', 50 + 2 * colWidth, footerStartY + 12, { continued: false })
      .text('USt-IdNr.:', 50 + 2 * colWidth, footerStartY + 24, { continued: false })
      .text(this.invoice.sender.vatId || '', 50 + 2 * colWidth, footerStartY + 36, { continued: false });

    // Spalte 4 - Bankdaten
    doc.fontSize(7)
      .text(`Bank: ${this.invoice.paymentInfo.bank}`, 50 + 3 * colWidth, footerStartY, { continued: false })
      .text(`Kontoinhaber: ${this.invoice.paymentInfo.accountHolder}`, 50 + 3 * colWidth, footerStartY + 12, { continued: false })
      .text(`IBAN: ${this.invoice.paymentInfo.iban}`, 50 + 3 * colWidth, footerStartY + 24, { continued: false })
      .text(`BIC/SWIFT-Code: ${this.invoice.paymentInfo.bic}`, 50 + 3 * colWidth, footerStartY + 36, { continued: false });
  }

  /**
   * Generiert das XML für ZUGFeRD
   */
  private generateXMLContent(): string {
    const xml = `<?xml version="1.0" encoding="UTF-8"?>
<rsm:CrossIndustryInvoice xmlns:rsm="urn:ferd:CrossIndustryDocument:invoice:2p0" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
  <rsm:ExchangedDocumentContext>
    <ram:TestIndicator>
      <udt:Indicator>false</udt:Indicator>
    </ram:TestIndicator>
    <ram:BusinessProcessSpecifiedDocumentContextParameter>
      <ram:ID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.3</ram:ID>
    </ram:BusinessProcessSpecifiedDocumentContextParameter>
    <ram:GuidelineSpecifiedDocumentContextParameter>
      <ram:ID>urn:cen.eu:en16931:2017</ram:ID>
    </ram:GuidelineSpecifiedDocumentContextParameter>
  </rsm:ExchangedDocumentContext>
  <rsm:ExchangedDocument>
    <ram:ID>${this.escapeXml(this.invoice.details.invoiceNumber)}</ram:ID>
    <ram:TypeCode>380</ram:TypeCode>
    <ram:IssueDateTime>
      <udt:DateTimeString format="102">${this.formatDate(this.invoice.details.invoiceDate)}</udt:DateTimeString>
    </ram:IssueDateTime>
  </rsm:ExchangedDocument>
  <rsm:SupplyChainTradeTransaction>
    <ram:IncludedSupplyChainTradeLineItem>
${this.generateLineItems()}
    </ram:IncludedSupplyChainTradeLineItem>
    <ram:ApplicableHeaderTradeAgreement>
      <ram:SellerTradeParty>
        <ram:Name>${this.escapeXml(this.invoice.sender.name)}</ram:Name>
        <ram:PostalTradeAddress>
          <ram:LineOne>${this.escapeXml(this.invoice.sender.address.street)}</ram:LineOne>
          <ram:CityName>${this.escapeXml(this.invoice.sender.address.city)}</ram:CityName>
          <ram:PostcodeCode>${this.escapeXml(this.invoice.sender.address.postalCode)}</ram:PostcodeCode>
          <ram:CountryID>DE</ram:CountryID>
        </ram:PostalTradeAddress>
        <ram:SpecifiedTaxRegistration>
          <ram:ID schemeID="FC">${this.escapeXml(this.invoice.sender.vatId || '')}</ram:ID>
        </ram:SpecifiedTaxRegistration>
        <ram:DefinedTradeContact>
          <ram:PersonName>${this.escapeXml(this.invoice.sender.businessOwner || '')}</ram:PersonName>
          <ram:TelephoneUniversalCommunication>
            <ram:CompleteNumber>${this.escapeXml(this.invoice.sender.contactInfo.phone)}</ram:CompleteNumber>
          </ram:TelephoneUniversalCommunication>
          <ram:EmailURIUniversalCommunication>
            <ram:URIID>${this.escapeXml(this.invoice.sender.contactInfo.email)}</ram:URIID>
          </ram:EmailURIUniversalCommunication>
        </ram:DefinedTradeContact>
      </ram:SellerTradeParty>
      <ram:BuyerTradeParty>
        <ram:Name>${this.escapeXml(this.invoice.recipient.name)}</ram:Name>
        <ram:PostalTradeAddress>
          <ram:LineOne>${this.escapeXml(this.invoice.recipient.address.street)}</ram:LineOne>
          <ram:CityName>${this.escapeXml(this.invoice.recipient.address.city)}</ram:CityName>
          <ram:PostcodeCode>${this.escapeXml(this.invoice.recipient.address.postalCode)}</ram:PostcodeCode>
          <ram:CountryID>DE</ram:CountryID>
        </ram:PostalTradeAddress>
      </ram:BuyerTradeParty>
    </ram:ApplicableHeaderTradeAgreement>
    <ram:ApplicableHeaderTradeSettlement>
      <ram:InvoiceCurrencyCode>${this.invoice.totals.currency}</ram:InvoiceCurrencyCode>
      <ram:SpecifiedTradeSettlementPaymentMeans>
        <ram:TypeCode>30</ram:TypeCode>
        <ram:Information>${this.escapeXml(this.invoice.paymentInfo.bank)}</ram:Information>
        <ram:PayeePartyCreditorFinancialAccount>
          <ram:IBANID>${this.escapeXml(this.invoice.paymentInfo.iban)}</ram:IBANID>
        </ram:PayeePartyCreditorFinancialAccount>
        <ram:PayeeSpecifiedCreditorFinancialInstitution>
          <ram:BICID>${this.escapeXml(this.invoice.paymentInfo.bic)}</ram:BICID>
        </ram:PayeeSpecifiedCreditorFinancialInstitution>
      </ram:SpecifiedTradeSettlementPaymentMeans>
      <ram:ApplicableTradeTax>
        <ram:CalculatedAmount>${this.invoice.totals.vatAmount.toFixed(2)}</ram:CalculatedAmount>
        <ram:TypeCode>VAT</ram:TypeCode>
        <ram:BasisAmount>${this.invoice.totals.netAmount.toFixed(2)}</ram:BasisAmount>
        <ram:ApplicablePercent>${this.invoice.totals.vatRate.toFixed(2)}</ram:ApplicablePercent>
      </ram:ApplicableTradeTax>
      <ram:SpecifiedTradePaymentTerms>
        <ram:Description>${this.escapeXml(this.invoice.paymentInfo.paymentTerms)}</ram:Description>
      </ram:SpecifiedTradePaymentTerms>
      <ram:SpecifiedTradeSettlementHeaderMonetarySummation>
        <ram:LineTotalAmount>${this.invoice.totals.netAmount.toFixed(2)}</ram:LineTotalAmount>
        <ram:TaxBasisTotalAmount>${this.invoice.totals.netAmount.toFixed(2)}</ram:TaxBasisTotalAmount>
        <ram:TaxTotalAmount>${this.invoice.totals.vatAmount.toFixed(2)}</ram:TaxTotalAmount>
        <ram:GrandTotalAmount>${this.invoice.totals.grossAmount.toFixed(2)}</ram:GrandTotalAmount>
      </ram:SpecifiedTradeSettlementHeaderMonetarySummation>
    </ram:ApplicableHeaderTradeSettlement>
  </rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>`;

    return xml;
  }

  private generateLineItems(): string {
    return this.invoice.items.map((item, index) => `
      <ram:IncludedSupplyChainTradeLineItem>
        <ram:AssociatedDocumentLineDocument>
          <ram:LineID>${index + 1}</ram:LineID>
        </ram:AssociatedDocumentLineDocument>
        <ram:SpecifiedTradeProduct>
          <ram:Name>${this.escapeXml(item.description)}</ram:Name>
        </ram:SpecifiedTradeProduct>
        <ram:SpecifiedLineTradeAgreement>
          <ram:NetPriceProductTradePrice>
            <ram:ChargeAmount>${item.unitPrice.toFixed(2)}</ram:ChargeAmount>
          </ram:NetPriceProductTradePrice>
        </ram:SpecifiedLineTradeAgreement>
        <ram:SpecifiedLineTradeDelivery>
          <ram:BilledQuantity>${item.quantity}</ram:BilledQuantity>
        </ram:SpecifiedLineTradeDelivery>
        <ram:SpecifiedLineTradeSettlement>
          <ram:ApplicableTradeTax>
            <ram:TypeCode>VAT</ram:TypeCode>
            <ram:ApplicablePercent>${item.vatRate.toFixed(2)}</ram:ApplicablePercent>
          </ram:ApplicableTradeTax>
          <ram:SpecifiedTradeSettlementLineMonetarySummation>
            <ram:LineTotalAmount>${item.total.toFixed(2)}</ram:LineTotalAmount>
          </ram:SpecifiedTradeSettlementLineMonetarySummation>
        </ram:SpecifiedLineTradeSettlement>
      </ram:IncludedSupplyChainTradeLineItem>`).join('');
  }

  private escapeXml(text: string): string {
    return text
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&apos;');
  }

  private formatDate(dateString: string): string {
    // Konvertiere DD.MM.YY zu YYYYMMDD
    const parts = dateString.split('.');
    if (parts.length === 3) {
      const day = parts[0].padStart(2, '0');
      const month = parts[1].padStart(2, '0');
      const year = '20' + parts[2]; // Annahme: 20xx
      return `${year}${month}${day}`;
    }
    return dateString;
  }

  /**
   * Fügt XML als Attachment zum PDF hinzu
   */
  private addXMLAttachment(doc: PDFKit.PDFDocument, xmlContent: string): void {
    // Hinweis: PDFKit unterstützt standardmäßig keine PDF/A-3 Attachments
    // In einer echten Implementierung würde hier ein PDF/A-3 Library verwendet werden
    console.log('XML-Inhalt für ZUGFeRD generiert (Attachment-Funktionalität erfordert PDF/A-3 Library)');
  }
} 